Shield Security for WordPress - Version 8.6.3

Version Description

  • Current Release = Released: 25th February, 2020 - Release Notes

  • (v.3) IMPROVED: AJAX handling and general plugin requests have been refined to be less prone to errors.

  • (v.3) IMPROVED: The Traffic Log Viewer will now be displayed even if it's disabled.

  • (v.3) REMOVED: 2 options from the Automatic Updates module have been removed, that influenced translations and version control.

  • (v.3) IMPROVED: Some minor improvements and optimisations.

  • (v.3) IMPROVED: Adjusted how Shield stores temporary WP options to prevent duplicates.

  • (v.3) FIXED: Login backup-code wasn't always reset after it was used.

  • (v.3) FIXED: IP address wasn't blocked even after committing an offense in 1 particular scenario.

Download this release

Release Info

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

Code changes from version 8.5.7 to 8.6.3

Files changed (171) hide show
  1. icwp-wpsf.php +1 -1
  2. init.php +11 -1
  3. plugin-spec.php +3 -3
  4. readme.txt +20 -43
  5. src/common/icwp-foundation.php +0 -18
  6. src/common/icwp-serviceproviders.php +0 -548
  7. src/common/icwp-wpcron.php +0 -171
  8. src/config/feature-autoupdates.php +0 -22
  9. src/config/feature-license.php +27 -19
  10. src/config/feature-login_protect.php +19 -3
  11. src/config/feature-plugin.php +0 -7
  12. src/config/feature-user_management.php +71 -0
  13. src/features/admin_access_restriction.php +6 -14
  14. src/features/base.php +23 -61
  15. src/features/base_wpsf.php +0 -54
  16. src/features/comments_filter.php +11 -15
  17. src/features/hack_protect.php +18 -207
  18. src/features/headers.php +0 -63
  19. src/features/insights.php +0 -6
  20. src/features/ips.php +11 -16
  21. src/features/license.php +174 -380
  22. src/features/login_protect.php +36 -13
  23. src/features/plugin.php +3 -134
  24. src/features/user_management.php +20 -170
  25. src/lib/src/Controller/Controller.php +36 -24
  26. src/lib/src/Crons/BaseCron.php +17 -0
  27. src/lib/src/Crons/DailyCron.php +30 -0
  28. src/lib/src/Crons/HourlyCron.php +30 -0
  29. src/lib/src/Databases/AuditTrail/Handler.php +0 -14
  30. src/lib/src/Databases/Base/BaseQuery.php +0 -14
  31. src/lib/src/Databases/IPs/EntryVO.php +0 -39
  32. src/lib/src/Databases/IPs/Select.php +0 -43
  33. src/lib/src/Deprecated/Foundation.php +0 -24
  34. src/lib/src/License/EddLicenseVO.php +0 -1
  35. src/lib/src/Modules/Autoupdates/Strings.php +2 -2
  36. src/lib/src/Modules/Base/AjaxHandlerBase.php +17 -9
  37. src/lib/src/Modules/Base/AjaxHandlerShield.php +0 -2
  38. src/lib/src/Modules/Base/BaseProcessor.php +1 -0
  39. src/lib/src/Modules/Base/Options.php +3 -1
  40. src/lib/src/Modules/Base/Strings.php +3 -0
  41. src/lib/src/Modules/CommentsFilter/Options.php +7 -0
  42. src/lib/src/Modules/CommentsFilter/Scan/Bot.php +5 -4
  43. src/lib/src/Modules/CommentsFilter/Token/Create.php +5 -4
  44. src/lib/src/Modules/HackGuard/Lib/Snapshots/StoreAction/BuildAll.php +0 -53
  45. src/lib/src/Modules/HackGuard/Options.php +0 -16
  46. src/lib/src/Modules/IPs/AjaxHandler.php +19 -15
  47. src/lib/src/Modules/IPs/Components/ProcessOffense.php +11 -6
  48. src/lib/src/Modules/IPs/Components/QueryIpBlock.php +2 -7
  49. src/lib/src/Modules/IPs/Lib/BlacklistHandler.php +101 -0
  50. src/lib/src/Modules/IPs/Lib/BlackmarkRequest.php +84 -0
  51. src/lib/src/Modules/IPs/Lib/BlockRequest.php +144 -0
  52. src/lib/src/Modules/IPs/Lib/Ops/AddIp.php +41 -5
  53. src/lib/src/Modules/IPs/Lib/Ops/LookupIpOnList.php +4 -20
  54. src/lib/src/Modules/License/AdminNotices.php +72 -0
  55. src/lib/src/Modules/License/AjaxHandler.php +26 -32
  56. src/lib/src/Modules/License/Lib/LicenseEmails.php +66 -0
  57. src/lib/src/Modules/License/Lib/LicenseHandler.php +201 -0
  58. src/lib/src/Modules/License/Lib/LookupRequest.php +56 -0
  59. src/lib/src/Modules/License/Lib/Verify.php +94 -0
  60. src/lib/src/Modules/License/Lib/WpHashes/ApiTokenManager.php +145 -0
  61. src/lib/src/Modules/LoginGuard/AjaxHandler.php +15 -12
  62. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/LoginIntentPage.php +155 -0
  63. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/MfaController.php +328 -0
  64. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/MfaControllerConsumer.php +33 -0
  65. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Backup.php +169 -0
  66. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/BaseProvider.php +258 -0
  67. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Email.php +237 -0
  68. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/GoogleAuth.php +260 -0
  69. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Yubikey.php +254 -0
  70. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/UserProfile.php +90 -0
  71. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/ValidateLoginIntentRequest.php +67 -0
  72. src/lib/src/Modules/LoginGuard/Options.php +114 -3
  73. src/lib/src/Modules/LoginGuard/Strings.php +6 -0
  74. src/lib/src/Modules/Plugin/AdminNotices.php +2 -1
  75. src/lib/src/Modules/Plugin/Lib/WpHashesTokenManager.php +19 -2
  76. src/lib/src/Modules/Plugin/Options.php +0 -17
  77. src/lib/src/Modules/Plugin/Strings.php +3 -0
  78. src/lib/src/Modules/SecurityAdmin/Lib/WhiteLabel/ApplyLabels.php +143 -0
  79. src/lib/src/Modules/UserManagement/Lib/Registration/EmailValidate.php +82 -0
  80. src/lib/src/Modules/UserManagement/Options.php +16 -0
  81. src/lib/src/Modules/UserManagement/Strings.php +16 -0
  82. src/lib/src/Modules/UserManagement/Suspend/Idle.php +4 -6
  83. src/lib/src/Modules/UserManagement/Suspend/PasswordExpiry.php +4 -3
  84. src/lib/src/Scans/Mal/Utilities/FalsePositiveQuery.php +10 -4
  85. src/lib/src/Scans/Mal/Utilities/FalsePositiveReporter.php +14 -4
  86. src/lib/src/Scans/Mal/Utilities/Patterns.php +5 -2
  87. src/lib/src/Scans/Ptg/ScannerBase.php +0 -53
  88. src/lib/src/Scans/Ptg/ScannerPlugins.php +0 -23
  89. src/lib/src/Scans/Wpv/Scan.php +7 -2
  90. src/lib/src/Tables/Build/Ip.php +2 -0
  91. src/lib/src/Tables/Render/IpBlack.php +9 -2
  92. src/lib/src/Users/ShieldUserMeta.php +17 -0
  93. src/lib/src/Utilities/AdminNotices/Controller.php +1 -1
  94. src/lib/vendor/composer/autoload_classmap.php +30 -7
  95. src/lib/vendor/composer/autoload_static.php +30 -7
  96. src/lib/vendor/fernleafsystems/wordpress-services/src/Core/General.php +18 -7
  97. src/lib/vendor/fernleafsystems/wordpress-services/src/Core/System.php +8 -0
  98. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Data.php +1 -0
  99. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/ApiBase.php +25 -4
  100. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Hashes/ApiInfo.php +1 -1
  101. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Hashes/AssetHashesBase.php +3 -5
  102. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Hashes/Base.php +1 -1
  103. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Hashes/PluginThemeBase.php +1 -1
  104. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Malware/Confidence/Base.php +1 -1
  105. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Malware/Confidence/Retrieve.php +1 -1
  106. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Services/Base.php +1 -1
  107. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Services/IPs.php +1 -1
  108. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Token/Base.php +1 -1
  109. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Token/Solicit.php +16 -13
  110. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Verify/Base.php +1 -1
  111. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Verify/Email.php +1 -1
  112. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Vulnerabilities/Base.php +2 -2
  113. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Vulnerabilities/BasePluginTheme.php +2 -2
  114. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/IpUtils.php +0 -160
  115. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Licenses/EddActions.php +5 -3
  116. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Licenses/EddLicenseVO.php +6 -4
  117. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Base.php +110 -0
  118. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Lookup.php +59 -0
  119. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Ping.php +26 -0
  120. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Licenses/Lookup.php +5 -1
  121. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Options/TestCanUseTransients.php +57 -0
  122. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Options/Transient.php +82 -0
  123. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/ServiceProviders.php +3 -4
  124. src/lib/vendor/symfony/polyfill-mbstring/Mbstring.php +8 -1
  125. src/processors/admin_access_restriction.php +3 -17
  126. src/processors/adminaccess_whitelabel.php +7 -4
  127. src/processors/autoupdates.php +24 -53
  128. src/processors/comments_filter.php +2 -16
  129. src/processors/commentsfilter_botspam.php +6 -3
  130. src/processors/email.php +16 -63
  131. src/processors/events.php +0 -8
  132. src/processors/hackprotect_integrity.php +2 -1
  133. src/processors/hackprotect_scan_assets_base.php +0 -29
  134. src/processors/hackprotect_scan_base.php +0 -57
  135. src/processors/hackprotect_scan_ptg.php +0 -117
  136. src/processors/hackprotect_scan_ufc.php +3 -3
  137. src/processors/hackprotect_scan_wcf.php +4 -2
  138. src/processors/hackprotect_scanner.php +0 -9
  139. src/processors/headers.php +1 -1
  140. src/processors/ips.php +5 -413
  141. src/processors/license.php +20 -15
  142. src/processors/lockdown.php +1 -1
  143. src/processors/login_protect.php +18 -17
  144. src/processors/loginprotect_intent.php +9 -319
  145. src/processors/loginprotect_intent_tracker.php +4 -0
  146. src/processors/loginprotect_intentprovider_backup.php +3 -84
  147. src/processors/loginprotect_intentprovider_base.php +3 -0
  148. src/processors/loginprotect_intentprovider_email.php +4 -75
  149. src/processors/loginprotect_intentprovider_ga.php +3 -48
  150. src/processors/loginprotect_intentprovider_yubikey.php +4 -44
  151. src/processors/plugin.php +7 -11
  152. src/processors/plugin_importexport.php +8 -8
  153. src/processors/sessions.php +0 -9
  154. src/processors/user_management.php +4 -24
  155. src/processors/usermanagement_sessions.php +0 -18
  156. src/wizards/login_protect.php +35 -36
  157. src/wizards/plugin.php +2 -1
  158. templates/php/snippets/user_profile_backupcode.php +0 -47
  159. templates/php/snippets/user_profile_emailauthentication.php +0 -29
  160. templates/php/snippets/user_profile_googleauthenticator.php +0 -89
  161. templates/php/snippets/user_profile_yubikey.php +0 -81
  162. templates/twig/notices/wphashes-token-fail.twig +7 -0
  163. templates/twig/pages/login_intent/index.twig +1 -127
  164. templates/twig/snippets/login_intent/form.twig +136 -0
  165. templates/twig/snippets/user/profile/mfa/mfa_backup.twig +18 -0
  166. templates/twig/snippets/user/profile/mfa/mfa_container.twig +11 -0
  167. templates/twig/snippets/user/profile/mfa/mfa_email.twig +13 -0
  168. templates/twig/snippets/user/profile/mfa/mfa_ga.twig +55 -0
  169. templates/twig/snippets/user/profile/mfa/mfa_yubikey.twig +36 -0
  170. templates/twig/wpadmin_pages/insights/license/license.twig +17 -4
  171. templates/twig/wpadmin_pages/insights/traffic/index.twig +6 -4
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: 8.5.7
7
  * Text Domain: wp-simple-firewall
8
  * Domain Path: /languages
9
  * Author: Shield Security
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: 8.6.3
7
  * Text Domain: wp-simple-firewall
8
  * Domain Path: /languages
9
  * Author: Shield Security
init.php CHANGED
@@ -59,4 +59,14 @@ catch ( \Exception $oE ) {
59
  error_log( 'Perhaps due to a failed upgrade, the Shield plugin failed to load certain component(s) - you should remove the plugin and reinstall.' );
60
  error_log( $oE->getMessage() );
61
  }
62
- }
 
 
 
 
 
 
 
 
 
 
59
  error_log( 'Perhaps due to a failed upgrade, the Shield plugin failed to load certain component(s) - you should remove the plugin and reinstall.' );
60
  error_log( $oE->getMessage() );
61
  }
62
+ }
63
+
64
+ if ( !function_exists( 'shield_security_get_plugin' ) ) {
65
+ /**
66
+ * @return ICWP_WPSF_Shield_Security|null
67
+ */
68
+ function shield_security_get_plugin() {
69
+ global $oICWP_Wpsf;
70
+ return ( $oICWP_Wpsf instanceof \ICWP_WPSF_Shield_Security ) ? $oICWP_Wpsf : null;
71
+ }
72
+ }
plugin-spec.php CHANGED
@@ -1,8 +1,8 @@
1
  {
2
  "properties": {
3
- "version": "8.5.7",
4
- "release_timestamp": 1581339113,
5
- "build": "202002.1001",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
  "human_name": "Shield",
1
  {
2
  "properties": {
3
+ "version": "8.6.3",
4
+ "release_timestamp": 1582635039,
5
+ "build": "202002.2505",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
  "human_name": "Shield",
readme.txt CHANGED
@@ -8,7 +8,7 @@ Requires at least: 3.5.2
8
  Requires PHP: 5.4.0
9
  Recommended PHP: 7.0
10
  Tested up to: 5.3
11
- Stable tag: 8.5.7
12
 
13
  Smarter security protection from hackers through automation. Powerful scanners, 2-Factor Auth, limit logins, auto IP blocks & more.
14
 
@@ -370,47 +370,24 @@ You will always be able to use Shield Security and its free features in-full.
370
 
371
  [Go Pro for just $1/month](https://shsec.io/aa).
372
 
373
- = 8.5.7 - Current Release =
374
- *Released: 10th February, 2020* - [Release Notes](https://shsec.io/gb)
375
-
376
- * **(v.7)** ADDED: New admin notice to indicate that the plugin is currently disabled.
377
- * **(v.7)** IMPROVED: Malware scanning for premium assets always uses hashes where possible to verify contents.
378
- * **(v.7)** IMPROVED: Optimised loading of libraries that run for certain features, if they aren't enabled.
379
- * **(v.7)** IMPROVED: Prevent a rare fatal error on activation.
380
-
381
- = 8.5 - Series =
382
- *Released: 8th January, 2020* - [Release Notes](https://shsec.io/gb)
383
-
384
- * **(v.6)** FIXED: Locking session to IP address was not handling all IP addresses correctly.
385
- * **(v.5)** FIXED: Further protection against errors if IP address is of a private network.
386
- * **(v.5)** FIXED: Can't activate plugins in a particular scenario.
387
- * **(v.5)** FIXED: Traffic Logger wasn't capturing traffic in some cases.
388
- * **(v.3)** FIXED: Prevent MySQL error when Shield is running on private network or local machine.
389
- * **(v.3)** FIXED: Prevent duplicate emails being sent when removing Security Admin key.
390
- * **(v.2)** ADDED: Introductory tour of plugin, on activation.
391
- * **(v.2)** IMPROVED: Enhanced IP detection of service providers for exclusion from traffic log.
392
- * **(v.2)** IMPROVED: Plugin/Theme Hack Guard Snapshot building is optimised to reduce disruption is some cases.
393
- * **(v.2)** IMPROVED: Visitor IP detection processing.
394
- * **(v.2)** IMPROVED: Improved cache-prevention of Login Two-Factor Authentication portal.
395
- * **(v.2)** FIXED: Firewall email alert was not sent when using certain dedicated email plugins.
396
- * **(v.2)** FIXED: Firewall 404 setting was redirecting instead of responding with 404.
397
- * **(v.2)** ADDED: Added support for NodePing filtering in the traffic logger.
398
- * **(v.1)** FIXED: Fix for page loading issue/slowdown in some cases.
399
- * **(v.0)** NEW: Initial support for checksum scanning of premium plugins and themes.
400
- * **(v.0)** NEW: Ability to switch-off Security Admin with an email confirmation if key is lost/forgotten.
401
- * **(v.0)** NEW: Ability to auto-repair theme files.
402
- * **(v.0)** ADDED: Ability to whitelist requests so that they are never blacklisted.
403
- * **(v.0)** ADDED: Ability to filter the IP White/Black list tables for a specific IP address.
404
- * **(v.0)** ADDED: Support for repeated audit trail entries - so the logs don't get filled with repeated messages.
405
- * **(v.0)** ADDED: [**PRO**] Option to provide complete, custom Content Security Policy headers.
406
- * **(v.0)** IMPROVED: Protection against a certain type of broken plugin installation if WordPress doesn't properly copy files.
407
- * **(v.0)** IMPROVED: Redesigned Table UI for scan results.
408
- * **(v.0)** IMPROVED: Redesigned Plugin/Theme File Guard.
409
- * **(v.0)** IMPROVED: Completely re-written much of the scanners code.
410
- * **(v.0)** IMPROVED: Better detection of the hosting server's IP addresses - i.e. support for IPv6 alongside IPv4.
411
- * **(v.0)** FIXED: Two-Factor Authentication (2FA) login screen redirection bug.
412
- * **(v.0)** FIXED: It was possible to temporarily by-pass the 2FA screen to gain access to WP Admin after logging-in.
413
- * **(v.0)** CLEANED: Code cleaning.
414
- * **(v.0)** UPDATED: Twitter Bootstrap library.
415
 
416
  #### [Full Shield Security Changelog](https://shsec.io/shieldwporgfullchangelog)
8
  Requires PHP: 5.4.0
9
  Recommended PHP: 7.0
10
  Tested up to: 5.3
11
+ Stable tag: 8.6.3
12
 
13
  Smarter security protection from hackers through automation. Powerful scanners, 2-Factor Auth, limit logins, auto IP blocks & more.
14
 
370
 
371
  [Go Pro for just $1/month](https://shsec.io/aa).
372
 
373
+ = 8.6.3 - Current Release =
374
+ *Released: 25th February, 2020* - [Release Notes](https://shsec.io/gl)
375
+
376
+ * **(v.3)** IMPROVED: AJAX handling and general plugin requests have been refined to be less prone to errors.
377
+ * **(v.3)** IMPROVED: The Traffic Log Viewer will now be displayed even if it's disabled.
378
+ * **(v.3)** REMOVED: 2 options from the Automatic Updates module have been removed, that influenced translations and version control.
379
+ * **(v.3)** IMPROVED: Some minor improvements and optimisations.
380
+ * **(v.3)** IMPROVED: Adjusted how Shield stores temporary WP options to prevent duplicates.
381
+ * **(v.3)** FIXED: Login backup-code wasn't always reset after it was used.
382
+ * **(v.3)** FIXED: IP address wasn't blocked even after committing an offense in 1 particular scenario.
383
+
384
+ = 8.6 - Series =
385
+ *Released: 19th February, 2020* - [Release Notes](https://shsec.io/gl)
386
+
387
+ * **(v.1)** NEW: [**PRO**] Deep scanning for valid email addresses when user registers with site.
388
+ * **(v.1)** ADDED: [**PRO**] New option allows users to turn on email-based two-factor authentication from their profile.
389
+ * **(v.1)** ADDED: Support for manually blocking IP Ranges (not just single IPs).
390
+ * **(v.1)** IMPROVED: Two-Factor Authentication system has been rewritten and improved.
391
+ * **(v.1)** IMPROVED: Table ordering and descriptions for the IP Black List.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
392
 
393
  #### [Full Shield Security Changelog](https://shsec.io/shieldwporgfullchangelog)
src/common/icwp-foundation.php DELETED
@@ -1,18 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ICWP_WPSF_Foundation
5
- * @deprecated 8.4
6
- */
7
- class ICWP_WPSF_Foundation {
8
-
9
- const DEFAULT_SERVICE_PREFIX = 'icwp_wpsf_';
10
-
11
- /**
12
- * @param string $sSuffix
13
- * @return string
14
- */
15
- protected function prefix( $sSuffix ) {
16
- return self::DEFAULT_SERVICE_PREFIX.$sSuffix;
17
- }
18
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/common/icwp-serviceproviders.php DELETED
@@ -1,548 +0,0 @@
1
- <?php
2
-
3
- use FernleafSystems\Wordpress\Services\Services;
4
-
5
- /**
6
- * Class ICWP_WPSF_ServiceProviders
7
- */
8
- class ICWP_WPSF_ServiceProviders extends ICWP_WPSF_Foundation {
9
-
10
- const URL_STATUS_CAKE_IPS = 'https://app.statuscake.com/Workfloor/Locations.php?format=json';
11
- const URL_ICONTROLWP_IPS = 'https://serviceips.icontrolwp.com/';
12
-
13
- /**
14
- * @var ICWP_WPSF_ServiceProviders
15
- */
16
- protected static $oInstance = null;
17
-
18
- /**
19
- * @return ICWP_WPSF_ServiceProviders
20
- */
21
- public static function GetInstance() {
22
- if ( is_null( self::$oInstance ) ) {
23
- self::$oInstance = new self();
24
- }
25
- return self::$oInstance;
26
- }
27
-
28
- /**
29
- * @return string[][]
30
- */
31
- public function getIps_CloudFlare() {
32
- $oWp = Services::WpGeneral();
33
-
34
- $sStoreKey = $this->prefix( 'serviceips_cloudflare' );
35
- $aIps = $oWp->getTransient( $sStoreKey );
36
- if ( empty( $aIps ) ) {
37
- $aIps = [
38
- 4 => $this->downloadServiceIps_Cloudflare( 4 ),
39
- 6 => $this->downloadServiceIps_Cloudflare( 6 )
40
- ];
41
- $oWp->setTransient( $sStoreKey, $aIps, $this->getLookupExpiration() );
42
- }
43
- return $aIps;
44
- }
45
-
46
- /**
47
- * @return string[]
48
- */
49
- public function getIps_CloudFlareV4() {
50
- $aIps = $this->getIps_CloudFlare();
51
- return $aIps[ 4 ];
52
- }
53
-
54
- /**
55
- * @return string[]
56
- */
57
- public function getIps_CloudFlareV6() {
58
- $aIps = $this->getIps_CloudFlare();
59
- return $aIps[ 6 ];
60
- }
61
-
62
- /**
63
- * @return string[]
64
- */
65
- public function getIps_DuckDuckGo() {
66
- return [ '107.20.237.51', '23.21.226.191', '107.21.1.8', '54.208.102.37' ];
67
- }
68
-
69
- /**
70
- * @param bool $bFlat
71
- * @return array[]|string[]
72
- */
73
- public function getIps_iControlWP( $bFlat = false ) {
74
- $oWp = Services::WpGeneral();
75
-
76
- $sStoreKey = $this->prefix( 'serviceips_icontrolwp' );
77
- $aIps = $oWp->getTransient( $sStoreKey );
78
- if ( empty( $aIps ) ) {
79
- $aIps = $this->downloadServiceIps_iControlWP();
80
- $oWp->setTransient( $sStoreKey, $aIps, $this->getLookupExpiration() );
81
- }
82
-
83
- return $bFlat ? array_merge( $aIps[ 4 ], $aIps[ 6 ] ) : $aIps;
84
- }
85
-
86
- /**
87
- * @return array[]
88
- */
89
- public function getIps_ManageWp() {
90
- $oWp = Services::WpGeneral();
91
-
92
- $sStoreKey = $this->prefix( 'serviceips_managewp' );
93
- $aIps = $oWp->getTransient( $sStoreKey );
94
- if ( empty( $aIps ) ) {
95
- $aIps = $this->downloadServiceIps_ManageWp();
96
- $oWp->setTransient( $sStoreKey, $aIps, $this->getLookupExpiration() );
97
- }
98
- return $aIps;
99
- }
100
-
101
- /**
102
- * @return string[][]
103
- */
104
- public function getIps_Pingdom() {
105
- $oWp = Services::WpGeneral();
106
-
107
- $sStoreKey = $this->prefix( 'serviceips_pingdom' );
108
- $aIps = $oWp->getTransient( $sStoreKey );
109
- if ( empty( $aIps ) ) {
110
- $aIps = [
111
- 4 => $this->downloadServiceIps_Pingdom( 4 ),
112
- 6 => $this->downloadServiceIps_Pingdom( 6 )
113
- ];
114
- $oWp->setTransient( $sStoreKey, $aIps, $this->getLookupExpiration() );
115
- }
116
- return $aIps;
117
- }
118
-
119
- /**
120
- * @return string[]
121
- */
122
- public function getIps_Statuscake() {
123
- $oWp = Services::WpGeneral();
124
-
125
- $sStoreKey = $this->prefix( 'serviceips_statuscake' );
126
- $aIps = $oWp->getTransient( $sStoreKey );
127
- if ( empty( $aIps ) || !is_array( $aIps ) ) {
128
- $aIps = $this->downloadServiceIps_StatusCake();
129
- $oWp->setTransient( $sStoreKey, $aIps, $this->getLookupExpiration() );
130
- }
131
- return $aIps;
132
- }
133
-
134
- /**
135
- * @return array[]
136
- */
137
- public function getIps_UptimeRobot() {
138
- $oWp = Services::WpGeneral();
139
-
140
- $sStoreKey = $this->prefix( 'serviceips_uptimerobot' );
141
- $aIps = $oWp->getTransient( $sStoreKey );
142
- if ( empty( $aIps ) ) {
143
- $aIps = [
144
- 4 => $this->downloadServiceIps_UptimeRobot( 4 ),
145
- 6 => $this->downloadServiceIps_UptimeRobot( 6 )
146
- ];
147
- $oWp->setTransient( $sStoreKey, $aIps, $this->getLookupExpiration() );
148
- }
149
- return $aIps;
150
- }
151
-
152
- /**
153
- * @param string $sIp
154
- * @param string $sUserAgent
155
- * @return bool
156
- */
157
- public function isIp_AppleBot( $sIp, $sUserAgent ) {
158
- $oWp = Services::WpGeneral();
159
-
160
- $sStoreKey = $this->prefix( 'serviceips_applebot' );
161
- $aIps = $oWp->getTransient( $sStoreKey );
162
- if ( !is_array( $aIps ) ) {
163
- $aIps = [];
164
- }
165
-
166
- if ( !in_array( $sIp, $aIps ) && $this->verifyIp_AppleBot( $sIp, $sUserAgent ) ) {
167
- $aIps[] = $sIp;
168
- $oWp->setTransient( $sStoreKey, $aIps, WEEK_IN_SECONDS*4 );
169
- }
170
-
171
- return in_array( $sIp, $aIps );
172
- }
173
-
174
- /**
175
- * @param string $sIp
176
- * @param string $sUserAgent
177
- * @return bool
178
- */
179
- public function isIp_BaiduBot( $sIp, $sUserAgent ) {
180
- $oWp = Services::WpGeneral();
181
-
182
- $sStoreKey = $this->prefix( 'serviceips_baidubot' );
183
- $aIps = $oWp->getTransient( $sStoreKey );
184
- if ( !is_array( $aIps ) ) {
185
- $aIps = [];
186
- }
187
-
188
- if ( !in_array( $sIp, $aIps ) && $this->verifyIp_BaiduBot( $sIp, $sUserAgent ) ) {
189
- $aIps[] = $sIp;
190
- $oWp->setTransient( $sStoreKey, $aIps, WEEK_IN_SECONDS*4 );
191
- }
192
-
193
- return in_array( $sIp, $aIps );
194
- }
195
-
196
- /**
197
- * @param string $sIp
198
- * @param string $sUserAgent
199
- * @return bool
200
- */
201
- public function isIp_BingBot( $sIp, $sUserAgent ) {
202
- $oWp = Services::WpGeneral();
203
-
204
- $sStoreKey = $this->prefix( 'serviceips_bingbot' );
205
- $aIps = $oWp->getTransient( $sStoreKey );
206
- if ( !is_array( $aIps ) ) {
207
- $aIps = [];
208
- }
209
-
210
- if ( !in_array( $sIp, $aIps ) && $this->verifyIp_BingBot( $sIp, $sUserAgent ) ) {
211
- $aIps[] = $sIp;
212
- $oWp->setTransient( $sStoreKey, $aIps, WEEK_IN_SECONDS*4 );
213
- }
214
-
215
- return in_array( $sIp, $aIps );
216
- }
217
-
218
- /**
219
- * @param string $sIp
220
- * @return bool
221
- */
222
- public function isIp_Cloudflare( $sIp ) {
223
- $bIs = false;
224
- try {
225
- $oIp = Services::IP();
226
- if ( $oIp->getIpVersion( $sIp ) == 4 ) {
227
- $bIs = $oIp->checkIp( $sIp, $this->getIps_CloudFlareV4() );
228
- }
229
- else {
230
- $bIs = $oIp->checkIp( $sIp, $this->getIps_CloudFlareV6() );
231
- }
232
- }
233
- catch ( Exception $oE ) {
234
- }
235
- return $bIs;
236
- }
237
-
238
- /**
239
- * https://duckduckgo.com/duckduckbot
240
- * @param string $sIp
241
- * @param string $sUserAgent
242
- * @return bool
243
- */
244
- public function isIp_DuckDuckGoBot( $sIp, $sUserAgent ) {
245
- $bIsBot = false;
246
- // We check the useragent if available
247
- if ( is_null( $sUserAgent ) || stripos( $sUserAgent, 'DuckDuckBot' ) !== false ) {
248
- $bIsBot = in_array( $sIp, $this->getIps_DuckDuckGo() );
249
- }
250
- return $bIsBot;
251
- }
252
-
253
- /**
254
- * @param string $sIp
255
- * @param string $sAgent
256
- * @return bool
257
- */
258
- public function isIp_iControlWP( $sIp, $sAgent = null ) { //TODO: Agent
259
- $bIsBot = false;
260
- if ( is_null( $sAgent ) || stripos( $sAgent, 'iControlWPApp' ) !== false ) {
261
- $bIsBot = in_array( $sIp, $this->getIps_iControlWP( true ) );
262
- }
263
- return $bIsBot;
264
- }
265
-
266
- /**
267
- * https://support.google.com/webmasters/answer/80553?hl=en
268
- * @param string $sIp
269
- * @param string $sUserAgent
270
- * @return bool
271
- */
272
- public function isIp_GoogleBot( $sIp, $sUserAgent ) {
273
- $oWp = Services::WpGeneral();
274
-
275
- $sStoreKey = $this->prefix( 'serviceips_googlebot' );
276
- $aIps = $oWp->getTransient( $sStoreKey );
277
- if ( !is_array( $aIps ) ) {
278
- $aIps = [];
279
- }
280
-
281
- if ( !in_array( $sIp, $aIps ) && $this->verifyIp_GoogleBot( $sIp, $sUserAgent ) ) {
282
- $aIps[] = $sIp;
283
- $oWp->setTransient( $sStoreKey, $aIps, WEEK_IN_SECONDS*4 );
284
- }
285
-
286
- return in_array( $sIp, $aIps );
287
- }
288
-
289
- /**
290
- * @param string $sIp
291
- * @param string $sAgent
292
- * @return bool
293
- */
294
- public function isIp_Statuscake( $sIp, $sAgent ) {
295
- $bIsIp = false;
296
- if ( stripos( $sAgent, 'StatusCake' ) !== false ) {
297
- $aIps = $this->getIps_Statuscake();
298
- $bIsIp = in_array( $sIp, $aIps );
299
- }
300
- return $bIsIp;
301
- }
302
-
303
- /**
304
- * @param string $sIp
305
- * @param string $sAgent
306
- * @return bool
307
- */
308
- public function isIp_Pingdom( $sIp, $sAgent ) {
309
- $bIsIp = false;
310
- if ( stripos( $sAgent, 'pingdom.com' ) !== false ) {
311
- $aIps = $this->getIps_Pingdom();
312
- $bIsIp = in_array( $sIp, $aIps[ Services::IP()->getIpVersion( $sIp ) ] );
313
- }
314
- return $bIsIp;
315
- }
316
-
317
- /**
318
- * @param string $sIp
319
- * @param string $sAgent
320
- * @return bool
321
- */
322
- public function isIp_UptimeRobot( $sIp, $sAgent ) {
323
- $bIsIp = false;
324
- if ( stripos( $sAgent, 'UptimeRobot' ) !== false ) {
325
- $aIps = $this->getIps_UptimeRobot();
326
- $bIsIp = in_array( $sIp, $aIps[ Services::IP()->getIpVersion( $sIp ) ] );
327
- }
328
- return $bIsIp;
329
- }
330
-
331
- /**
332
- * https://yandex.com/support/webmaster/robot-workings/check-yandex-robots.html
333
- * @param string $sIp
334
- * @param string $sUserAgent
335
- * @return bool
336
- */
337
- public function isIp_YandexBot( $sIp, $sUserAgent ) {
338
- $oWp = Services::WpGeneral();
339
-
340
- $sStoreKey = $this->prefix( 'serviceips_yandexbot' );
341
- $aIps = $oWp->getTransient( $sStoreKey );
342
- if ( !is_array( $aIps ) ) {
343
- $aIps = [];
344
- }
345
-
346
- if ( !in_array( $sIp, $aIps ) && $this->verifyIp_YandexBot( $sIp, $sUserAgent ) ) {
347
- $aIps[] = $sIp;
348
- $oWp->setTransient( $sStoreKey, $aIps, WEEK_IN_SECONDS*4 );
349
- }
350
-
351
- return in_array( $sIp, $aIps );
352
- }
353
-
354
- /**
355
- * https://yandex.com/support/webmaster/robot-workings/check-yandex-robots.html
356
- * @param string $sIp
357
- * @param string $sUserAgent
358
- * @return bool
359
- */
360
- public function isIp_YahooBot( $sIp, $sUserAgent ) {
361
- $oWp = Services::WpGeneral();
362
-
363
- $sStoreKey = $this->prefix( 'serviceips_yahoobot' );
364
- $aIps = $oWp->getTransient( $sStoreKey );
365
- if ( !is_array( $aIps ) ) {
366
- $aIps = [];
367
- }
368
-
369
- if ( !in_array( $sIp, $aIps ) && $this->verifyIp_YahooBot( $sIp, $sUserAgent ) ) {
370
- $aIps[] = $sIp;
371
- $oWp->setTransient( $sStoreKey, $aIps, WEEK_IN_SECONDS*4 );
372
- }
373
-
374
- return in_array( $sIp, $aIps );
375
- }
376
-
377
- /**
378
- * https://support.apple.com/en-gb/HT204683
379
- * https://discussions.apple.com/thread/7090135
380
- * Apple IPs start with '17.'
381
- * @param string $sIp
382
- * @param string $sUserAgent
383
- * @return bool
384
- */
385
- private function verifyIp_AppleBot( $sIp, $sUserAgent = '' ) {
386
- return ( Services::IP()->getIpVersion( $sIp ) != 4 || strpos( $sIp, '17.' ) === 0 )
387
- && $this->isIpOfBot( [ 'Applebot/' ], '#.*\.applebot.apple.com\.?$#i', $sIp, $sUserAgent );
388
- }
389
-
390
- /**
391
- * @param string $sIp
392
- * @param string $sUserAgent
393
- * @return bool
394
- */
395
- private function verifyIp_BaiduBot( $sIp, $sUserAgent = '' ) {
396
- return $this->isIpOfBot( [ 'baidu' ], '#.*\.crawl\.baidu\.(com|jp)\.?$#i', $sIp, $sUserAgent );
397
- }
398
-
399
- /**
400
- * @param string $sIp
401
- * @param string $sUserAgent
402
- * @return bool
403
- */
404
- private function verifyIp_BingBot( $sIp, $sUserAgent = '' ) {
405
- return $this->isIpOfBot( [ 'bingbot' ], '#.*\.search\.msn\.com\.?$#i', $sIp, $sUserAgent );
406
- }
407
-
408
- /**
409
- * @param string $sIp
410
- * @param string $sUserAgent
411
- * @return bool
412
- */
413
- private function verifyIp_GoogleBot( $sIp, $sUserAgent = '' ) {
414
- return $this->isIpOfBot(
415
- [ 'Googlebot', 'APIs-Google', 'AdsBot-Google', 'Mediapartners-Google' ],
416
- '#.*\.google(bot)?\.com\.?$#i', $sIp, $sUserAgent
417
- );
418
- }
419
-
420
- /**
421
- * @param string $sIp
422
- * @param string $sUserAgent
423
- * @return bool
424
- */
425
- private function verifyIp_YandexBot( $sIp, $sUserAgent = '' ) {
426
- return $this->isIpOfBot( [ 'yandex.com/bots' ], '#.*\.yandex?\.(com|ru|net)\.?$#i', $sIp, $sUserAgent );
427
- }
428
-
429
- /**
430
- * @param string $sIp
431
- * @param string $sUserAgent
432
- * @return bool
433
- */
434
- private function verifyIp_YahooBot( $sIp, $sUserAgent = '' ) {
435
- return $this->isIpOfBot( [ 'yahoo!' ], '#.*\.crawl\.yahoo\.net\.?$#i', $sIp, $sUserAgent );
436
- }
437
-
438
- /**
439
- * Will test useragent, then attempt to resolve to hostname and back again
440
- * https://www.elephate.com/detect-verify-crawlers/
441
- * @param array $aBotUserAgents
442
- * @param string $sBotHostPattern
443
- * @param string $sReqIp
444
- * @param string $sReqUserAgent
445
- * @return bool
446
- */
447
- private function isIpOfBot( $aBotUserAgents, $sBotHostPattern, $sReqIp, $sReqUserAgent = '' ) {
448
- $bIsBot = false;
449
-
450
- $bCheckIpHost = is_null( $sReqUserAgent );
451
- if ( !$bCheckIpHost ) {
452
- $aBotUserAgents = array_map(
453
- function ( $sAgent ) {
454
- return preg_quote( $sAgent, '#' );
455
- },
456
- $aBotUserAgents
457
- );
458
- $bCheckIpHost = (bool)preg_match( sprintf( '#%s#i', implode( '|', $aBotUserAgents ) ), $sReqUserAgent );
459
- }
460
-
461
- if ( $bCheckIpHost ) {
462
- $sHost = @gethostbyaddr( $sReqIp ); // returns the ip on failure
463
- $bIsBot = !empty( $sHost ) && ( $sHost != $sReqIp )
464
- && preg_match( $sBotHostPattern, $sHost )
465
- && gethostbyname( $sHost ) === $sReqIp;
466
- }
467
- return $bIsBot;
468
- }
469
-
470
- /**
471
- * @param int $sIpVersion
472
- * @return string[]
473
- */
474
- private function downloadServiceIps_Cloudflare( $sIpVersion = 4 ) {
475
- return $this->downloadServiceIps_Standard( 'https://www.cloudflare.com/ips-v%s', $sIpVersion );
476
- }
477
-
478
- /**
479
- * @return string[]
480
- */
481
- private function downloadServiceIps_ManageWp() {
482
- return $this->downloadServiceIps_Standard( 'https://managewp.com/wp-content/uploads/2016/11/managewp-ips.txt' );
483
- }
484
-
485
- /**
486
- * @return array[]
487
- */
488
- private function downloadServiceIps_iControlWP() {
489
- $aIps = @json_decode( Services::HttpRequest()->getContent( self::URL_ICONTROLWP_IPS ), true );
490
- return is_array( $aIps ) ? $aIps : [ 4 => [], 6 => [] ];
491
- }
492
-
493
- /**
494
- * @param int $sIpVersion
495
- * @return string[]
496
- */
497
- private function downloadServiceIps_Pingdom( $sIpVersion = 4 ) {
498
- return $this->downloadServiceIps_Standard( 'https://my.pingdom.com/probes/ipv%s', $sIpVersion );
499
- }
500
-
501
- /**
502
- * @return string[]
503
- */
504
- private function downloadServiceIps_StatusCake() {
505
- $aIps = [];
506
- $aData = @json_decode( Services::HttpRequest()->getContent( self::URL_STATUS_CAKE_IPS ), true );
507
- if ( is_array( $aData ) ) {
508
- foreach ( $aData as $aItem ) {
509
- if ( !empty( $aItem[ 'ip' ] ) ) {
510
- $aIps[] = $aItem[ 'ip' ];
511
- }
512
- }
513
- }
514
- return $aIps;
515
- }
516
-
517
- /**
518
- * @param int $sIpVersion
519
- * @return string[]
520
- */
521
- private function downloadServiceIps_UptimeRobot( $sIpVersion = 4 ) {
522
- return $this->downloadServiceIps_Standard( 'https://uptimerobot.com/inc/files/ips/IPv%s.txt', $sIpVersion );
523
- }
524
-
525
- /**
526
- * @param string $sSourceUrl must have an sprintf %s placeholder
527
- * @param int $sIpVersion
528
- * @return string[]
529
- */
530
- private function downloadServiceIps_Standard( $sSourceUrl, $sIpVersion = null ) {
531
- if ( !is_null( $sIpVersion ) ) {
532
- if ( !in_array( (int)$sIpVersion, [ 4, 6 ] ) ) {
533
- $sIpVersion = 4;
534
- }
535
- $sSourceUrl = Services::HttpRequest()->getContent( sprintf( $sSourceUrl, $sIpVersion ) );
536
- }
537
- $sRaw = Services::HttpRequest()->getContent( $sSourceUrl );
538
- $aIps = empty( $sRaw ) ? [] : explode( "\n", $sRaw );
539
- return array_filter( array_map( 'trim', $aIps ) );
540
- }
541
-
542
- /**
543
- * @return int
544
- */
545
- private function getLookupExpiration() {
546
- return WEEK_IN_SECONDS*2;
547
- }
548
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/common/icwp-wpcron.php DELETED
@@ -1,171 +0,0 @@
1
- <?php
2
-
3
- class ICWP_WPSF_WpCron {
4
-
5
- /**
6
- * @var ICWP_WPSF_WpCron
7
- */
8
- protected static $oInstance = null;
9
-
10
- /**
11
- * @var int
12
- */
13
- protected $nNextRun;
14
-
15
- /**
16
- * @var string
17
- */
18
- protected $sRecurrence;
19
-
20
- /**
21
- * @var array
22
- */
23
- protected $aSchedules;
24
-
25
- /**
26
- * @return ICWP_WPSF_WpCron
27
- */
28
- public static function GetInstance() {
29
- if ( is_null( self::$oInstance ) ) {
30
- self::$oInstance = new self();
31
- }
32
- return self::$oInstance;
33
- }
34
-
35
- private function __construct() {
36
- add_filter( 'cron_schedules', [ $this, 'addSchedules' ] );
37
- }
38
-
39
- /**
40
- * @param array $aSchedules
41
- * @return array
42
- */
43
- public function addSchedules( $aSchedules ) {
44
- return array_merge( $aSchedules, $this->getSchedules() );
45
- }
46
-
47
- /**
48
- * @param string $sSlug
49
- * @param array $aNewSchedule
50
- * @return $this
51
- */
52
- public function addNewSchedule( $sSlug, $aNewSchedule ) {
53
- if ( !empty( $aNewSchedule ) && is_array( $aNewSchedule ) ) {
54
- $aSchedules = $this->getSchedules();
55
- $aSchedules[ $sSlug ] = $aNewSchedule;
56
- $this->aSchedules = $aSchedules;
57
- }
58
- return $this;
59
- }
60
-
61
- /**
62
- * @return array
63
- * @deprecated uses undocumented private WP function
64
- */
65
- public function getCrons() {
66
- return function_exists( '_get_cron_array' ) && is_array( _get_cron_array() ) ? _get_cron_array() : [];
67
- }
68
-
69
- /**
70
- * @return array
71
- */
72
- protected function getSchedules() {
73
- if ( !is_array( $this->aSchedules ) ) {
74
- $this->aSchedules = [];
75
- }
76
- return $this->aSchedules;
77
- }
78
-
79
- /**
80
- * @param string $sCronName
81
- * @return bool
82
- */
83
- public function getIfCronExists( $sCronName ) {
84
- return (bool)wp_next_scheduled( $sCronName );
85
- }
86
-
87
- /**
88
- * @return int
89
- */
90
- public function getNextRun() {
91
- if ( is_null( $this->nNextRun ) ) {
92
- return strtotime( 'tomorrow 4am' ) - get_option( 'gmt_offset' )*HOUR_IN_SECONDS;
93
- }
94
- return $this->nNextRun;
95
- }
96
-
97
- /**
98
- * @return string
99
- */
100
- public function getRecurrence() {
101
- if ( empty( $this->sRecurrence ) ) {
102
- return 'daily';
103
- }
104
- return $this->sRecurrence;
105
- }
106
-
107
- /**
108
- * @param int $nNextRun
109
- * @return $this
110
- */
111
- public function setNextRun( $nNextRun ) {
112
- $this->nNextRun = $nNextRun;
113
- return $this;
114
- }
115
-
116
- /**
117
- * @param string $sRecurrence
118
- * @return $this
119
- */
120
- public function setRecurrence( $sRecurrence ) {
121
- $this->sRecurrence = $sRecurrence;
122
- return $this;
123
- }
124
-
125
- /**
126
- * @return $this
127
- */
128
- public function reset() {
129
- return $this
130
- ->setNextRun( null )
131
- ->setRecurrence( null );
132
- }
133
-
134
- /**
135
- * @param string $sUniqueCronName
136
- * @param callable $cCallback
137
- * @return $this
138
- * @throws Exception
139
- */
140
- public function createCronJob( $sUniqueCronName, $cCallback ) {
141
- if ( !is_callable( $cCallback ) ) {
142
- throw new Exception( sprintf( 'Tried to schedule a new cron but the Callback function is not callable: %s', print_r( $cCallback, true ) ) );
143
- }
144
- add_action( $sUniqueCronName, $cCallback );
145
- return $this->setCronSchedule( $sUniqueCronName );
146
- }
147
-
148
- /**
149
- * @param string $sUniqueCronName
150
- * @return $this
151
- */
152
- public function deleteCronJob( $sUniqueCronName ) {
153
- if ( function_exists( 'wp_unschedule_hook' ) ) {
154
- wp_unschedule_hook( $sUniqueCronName );
155
- }
156
- wp_clear_scheduled_hook( $sUniqueCronName );
157
- return $this;
158
- }
159
-
160
- /**
161
- * @param string $sUniqueCronActionName
162
- * @return $this
163
- */
164
- protected function setCronSchedule( $sUniqueCronActionName ) {
165
- if ( !wp_next_scheduled( $sUniqueCronActionName ) && !defined( 'WP_INSTALLING' ) ) {
166
- wp_schedule_event( $this->getNextRun(), $this->getRecurrence(), $sUniqueCronActionName );
167
- $this->reset();
168
- }
169
- return $this;
170
- }
171
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/config/feature-autoupdates.php CHANGED
@@ -128,28 +128,6 @@
128
  "summary": "Automatically Update Themes",
129
  "description": "Note: Automatic updates for themes are disabled on WordPress by default."
130
  },
131
- {
132
- "key": "enable_autoupdate_translations",
133
- "section": "section_automatic_updates_for_wordpress_components",
134
- "default": "Y",
135
- "type": "checkbox",
136
- "link_info": "",
137
- "link_blog": "",
138
- "name": "Translations",
139
- "summary": "Automatically Update Translations",
140
- "description": "Note: Automatic updates for translations are enabled on WordPress by default."
141
- },
142
- {
143
- "key": "enable_autoupdate_ignore_vcs",
144
- "section": "section_automatic_updates_for_wordpress_components",
145
- "default": "N",
146
- "type": "checkbox",
147
- "link_info": "",
148
- "link_blog": "",
149
- "name": "Ignore Version Control",
150
- "summary": "Ignore Version Control Systems Such As GIT and SVN",
151
- "description": "If you use SVN or GIT and WordPress detects it, automatic updates are disabled by default. Check this box to ignore version control systems and allow automatic updates."
152
- },
153
  {
154
  "key": "update_delay",
155
  "section": "section_options",
128
  "summary": "Automatically Update Themes",
129
  "description": "Note: Automatic updates for themes are disabled on WordPress by default."
130
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  {
132
  "key": "update_delay",
133
  "section": "section_options",
src/config/feature-license.php CHANGED
@@ -1,6 +1,6 @@
1
  {
2
- "slug": "license",
3
- "properties": {
4
  "slug": "license",
5
  "name": "Pro Security",
6
  "menu_title": "Go Pro!",
@@ -16,13 +16,23 @@
16
  "run_if_verified_bot": true,
17
  "run_if_wpcli": true
18
  },
19
- "sections": [
 
 
 
 
 
 
 
 
 
 
20
  {
21
  "slug": "section_non_ui",
22
  "hidden": true
23
  }
24
  ],
25
- "options": [
26
  {
27
  "key": "license_key",
28
  "section": "section_non_ui",
@@ -52,13 +62,6 @@
52
  "type": "integer",
53
  "default": 0
54
  },
55
- {
56
- "key": "license_deactivated_reason",
57
- "section": "section_non_ui",
58
- "transferable": false,
59
- "type": "text",
60
- "default": ""
61
- },
62
  {
63
  "key": "last_warning_email_sent_at",
64
  "section": "section_non_ui",
@@ -89,7 +92,7 @@
89
  "default": 0
90
  },
91
  {
92
- "key": "keyless_request_hash",
93
  "section": "section_non_ui",
94
  "sensitive": true,
95
  "transferable": false,
@@ -97,7 +100,7 @@
97
  "default": ""
98
  },
99
  {
100
- "key": "keyless_request_at",
101
  "section": "section_non_ui",
102
  "sensitive": true,
103
  "transferable": false,
@@ -111,30 +114,35 @@
111
  "transferable": false,
112
  "type": "array",
113
  "default": []
 
 
 
 
 
 
 
114
  }
115
  ],
116
- "definitions": {
117
  "license_store_url": "https://onedollarplugin.com/edd-sl/",
 
118
  "keyless_cp": "https://shsec.io/c5",
119
  "license_item_name": "Shield Security Pro",
120
  "license_item_id": "6047",
121
  "license_item_name_sc": "Shield Security Pro (via Shield Central)",
122
- "license_item_id_sc": "968",
123
  "lic_verify_expire_days": 7,
124
  "lic_verify_expire_grace_days": 3,
125
- "license_key_length": 32,
126
- "license_key_type": "alphanumeric",
127
  "keyless": true,
128
  "keyless_handshake_expire": 90,
129
  "events": {
130
- "lic_check_success": {
131
  "stat": false
132
  },
133
  "lic_fail_email": {
134
  "stat": false
135
  },
136
  "lic_fail_deactivate": {
137
- "cat": 2,
138
  "stat": false
139
  }
140
  }
1
  {
2
+ "slug": "license",
3
+ "properties": {
4
  "slug": "license",
5
  "name": "Pro Security",
6
  "menu_title": "Go Pro!",
16
  "run_if_verified_bot": true,
17
  "run_if_wpcli": true
18
  },
19
+ "admin_notices": {
20
+ "wphashes-token-fail": {
21
+ "id": "wphashes-token-fail",
22
+ "schedule": "conditions",
23
+ "valid_admin": true,
24
+ "plugin_page_only": true,
25
+ "can_dismiss": false,
26
+ "type": "error"
27
+ }
28
+ },
29
+ "sections": [
30
  {
31
  "slug": "section_non_ui",
32
  "hidden": true
33
  }
34
  ],
35
+ "options": [
36
  {
37
  "key": "license_key",
38
  "section": "section_non_ui",
62
  "type": "integer",
63
  "default": 0
64
  },
 
 
 
 
 
 
 
65
  {
66
  "key": "last_warning_email_sent_at",
67
  "section": "section_non_ui",
92
  "default": 0
93
  },
94
  {
95
+ "key": "keyless_handshake_hash",
96
  "section": "section_non_ui",
97
  "sensitive": true,
98
  "transferable": false,
100
  "default": ""
101
  },
102
  {
103
+ "key": "keyless_handshake_until",
104
  "section": "section_non_ui",
105
  "sensitive": true,
106
  "transferable": false,
114
  "transferable": false,
115
  "type": "array",
116
  "default": []
117
+ },
118
+ {
119
+ "key": "wphashes_api_token",
120
+ "transferable": false,
121
+ "section": "section_non_ui",
122
+ "type": "array",
123
+ "default": []
124
  }
125
  ],
126
+ "definitions": {
127
  "license_store_url": "https://onedollarplugin.com/edd-sl/",
128
+ "license_store_url_api": "https://onedollarplugin.com/wp-json/odp-eddkeyless/v1",
129
  "keyless_cp": "https://shsec.io/c5",
130
  "license_item_name": "Shield Security Pro",
131
  "license_item_id": "6047",
132
  "license_item_name_sc": "Shield Security Pro (via Shield Central)",
 
133
  "lic_verify_expire_days": 7,
134
  "lic_verify_expire_grace_days": 3,
 
 
135
  "keyless": true,
136
  "keyless_handshake_expire": 90,
137
  "events": {
138
+ "lic_check_success": {
139
  "stat": false
140
  },
141
  "lic_fail_email": {
142
  "stat": false
143
  },
144
  "lic_fail_deactivate": {
145
+ "cat": 2,
146
  "stat": false
147
  }
148
  }
src/config/feature-login_protect.php CHANGED
@@ -18,9 +18,12 @@
18
  "admin_notices": {
19
  "email-verification-sent": {
20
  "id": "email-verification-sent",
21
- "once": false,
 
 
22
  "type": "warning",
23
- "plugin_admin": "yes"
 
24
  }
25
  },
26
  "sections": [
@@ -256,6 +259,18 @@
256
  "summary": "All User Roles Subject To Email Authentication",
257
  "description": "Enforces email-based authentication on all users with the selected roles. Note: This setting only applies to email authentication."
258
  },
 
 
 
 
 
 
 
 
 
 
 
 
259
  {
260
  "key": "bot_protection_locations",
261
  "section": "section_brute_force_login_protection",
@@ -435,7 +450,8 @@
435
  "section": "section_non_ui",
436
  "transferable": false,
437
  "type": "integer",
438
- "default": -1
 
439
  },
440
  {
441
  "key": "gasp_key",
18
  "admin_notices": {
19
  "email-verification-sent": {
20
  "id": "email-verification-sent",
21
+ "schedule": "conditions",
22
+ "plugin_page_only": true,
23
+ "can_dismiss": false,
24
  "type": "warning",
25
+ "plugin_admin": "yes",
26
+ "valid_admin": true
27
  }
28
  },
29
  "sections": [
259
  "summary": "All User Roles Subject To Email Authentication",
260
  "description": "Enforces email-based authentication on all users with the selected roles. Note: This setting only applies to email authentication."
261
  },
262
+ {
263
+ "key": "email_any_user_set",
264
+ "section": "section_2fa_email",
265
+ "premium": true,
266
+ "default": "N",
267
+ "type": "checkbox",
268
+ "link_info": "https://shsec.io/gj",
269
+ "link_blog": "",
270
+ "name": "Allow Any User",
271
+ "summary": "Allow Any User To Turn-On Two-Factor Authentication By Email",
272
+ "description": "Allow Any User To Turn-On Two-Factor Authentication By Email."
273
+ },
274
  {
275
  "key": "bot_protection_locations",
276
  "section": "section_brute_force_login_protection",
450
  "section": "section_non_ui",
451
  "transferable": false,
452
  "type": "integer",
453
+ "default": 0,
454
+ "min": 0
455
  },
456
  {
457
  "key": "gasp_key",
src/config/feature-plugin.php CHANGED
@@ -421,13 +421,6 @@
421
  "section": "section_non_ui",
422
  "type": "text",
423
  "default": ""
424
- },
425
- {
426
- "key": "wphashes_api_token",
427
- "transferable": false,
428
- "section": "section_non_ui",
429
- "type": "array",
430
- "default": []
431
  }
432
  ],
433
  "definitions": {
421
  "section": "section_non_ui",
422
  "type": "text",
423
  "default": ""
 
 
 
 
 
 
 
424
  }
425
  ],
426
  "definitions": {
src/config/feature-user_management.php CHANGED
@@ -25,6 +25,15 @@
25
  "Recommendation - Use of this feature is highly recommend."
26
  ]
27
  },
 
 
 
 
 
 
 
 
 
28
  {
29
  "slug": "section_passwords",
30
  "reqs": {
@@ -153,6 +162,65 @@
153
  "summary": "Limit Simultaneous Sessions For The Same Username",
154
  "description": "The number provided here is the maximum number of simultaneous, distinct, sessions allowed for any given username. Use '0' for no limits."
155
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
  {
157
  "key": "enable_password_policies",
158
  "section": "section_passwords",
@@ -342,6 +410,9 @@
342
  "recent": true
343
  },
344
  "user_hard_unsuspended": {
 
 
 
345
  }
346
  }
347
  }
25
  "Recommendation - Use of this feature is highly recommend."
26
  ]
27
  },
28
+ {
29
+ "slug": "section_user_reg",
30
+ "title": "User Registration",
31
+ "title_short": "User Registration",
32
+ "summary": [
33
+ "Purpose - Control user registration and prevent SPAM.",
34
+ "Recommendation - Use of this feature is highly recommend."
35
+ ]
36
+ },
37
  {
38
  "slug": "section_passwords",
39
  "reqs": {
162
  "summary": "Limit Simultaneous Sessions For The Same Username",
163
  "description": "The number provided here is the maximum number of simultaneous, distinct, sessions allowed for any given username. Use '0' for no limits."
164
  },
165
+ {
166
+ "key": "reg_email_validate",
167
+ "section": "section_user_reg",
168
+ "premium": true,
169
+ "type": "select",
170
+ "default": "log",
171
+ "value_options": [
172
+ {
173
+ "value_key": "disabled",
174
+ "text": "Disabled"
175
+ },
176
+ {
177
+ "value_key": "log",
178
+ "text": "Log Only"
179
+ },
180
+ {
181
+ "value_key": "offense",
182
+ "text": "Increment Offense Counter"
183
+ },
184
+ {
185
+ "value_key": "block",
186
+ "text": "Immediate Block and Kill"
187
+ }
188
+ ],
189
+ "link_info": "https://shsec.io/gk",
190
+ "link_blog": "",
191
+ "name": "Validate Email Addresses",
192
+ "summary": "Validate Email Addresses When User Attempts To Register",
193
+ "description": "Validate Email Addresses When User Attempts To Register."
194
+ },
195
+ {
196
+ "key": "email_checks",
197
+ "section": "section_user_reg",
198
+ "type": "multiple_select",
199
+ "default": [ "syntax", "domain" ],
200
+ "value_options": [
201
+ {
202
+ "value_key": "syntax",
203
+ "text": "Email Address Syntax"
204
+ },
205
+ {
206
+ "value_key": "domain",
207
+ "text": "Domain Name Resolves"
208
+ },
209
+ {
210
+ "value_key": "mx",
211
+ "text": "Domain MX"
212
+ },
213
+ {
214
+ "value_key": "nondisposable",
215
+ "text": "Disposable Email Service"
216
+ }
217
+ ],
218
+ "link_info": "",
219
+ "link_blog": "",
220
+ "name": "Email Checks",
221
+ "summary": "The Email Address Properties That Will Be Tested",
222
+ "description": "Select which ."
223
+ },
224
  {
225
  "key": "enable_password_policies",
226
  "section": "section_passwords",
410
  "recent": true
411
  },
412
  "user_hard_unsuspended": {
413
+ },
414
+ "reg_email_invalid": {
415
+ "offense": true
416
  }
417
  }
418
  }
src/features/admin_access_restriction.php CHANGED
@@ -86,7 +86,7 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
86
  private function verifySecAdminUsers( $aSecUsers ) {
87
  $oDP = Services::Data();
88
  $oWpUsers = Services::WpUsers();
89
- /** @var Shield\Modules\SecurityAdmin\Options $oOpts */
90
  $oOpts = $this->getOptions();
91
 
92
  $aFiltered = [];
@@ -144,10 +144,10 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
144
  }
145
 
146
  /**
 
147
  */
148
- public function handleModRequest() {
149
- $oReq = Services::Request();
150
- switch ( $oReq->query( 'exec' ) ) {
151
  case 'remove_secadmin_confirm':
152
  ( new SecurityAdmin\Lib\Actions\RemoveSecAdmin() )
153
  ->setMod( $this )
@@ -169,7 +169,7 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
169
  * @return bool
170
  */
171
  public function isEnabledSecurityAdmin() {
172
- /** @var Shield\Modules\SecurityAdmin\Options $oOpts */
173
  $oOpts = $this->getOptions();
174
  return $this->isModOptEnabled() &&
175
  ( $this->hasSecAdminUsers() ||
@@ -204,7 +204,7 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
204
  $bValid = false;
205
  $sReqKey = Services::Request()->post( 'sec_admin_key' );
206
  if ( !empty( $sReqKey ) ) {
207
- /** @var Shield\Modules\SecurityAdmin\Options $oOpts */
208
  $oOpts = $this->getOptions();
209
  $bValid = hash_equals( $oOpts->getAccessKeyHash(), md5( $sReqKey ) );
210
  if ( !$bValid ) {
@@ -326,17 +326,9 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
326
  return $this->saveModOptions();
327
  }
328
 
329
- /**
330
- * @return $this
331
- */
332
- protected function clearAdminAccessKey() {
333
- return $this->setOpt( 'admin_access_key', '' );
334
- }
335
-
336
  public function insertCustomJsVars_Admin() {
337
  parent::insertCustomJsVars_Admin();
338
 
339
- $aInsertData = [];
340
  if ( $this->getSecAdminTimeLeft() > 0 ) {
341
  $aInsertData = [
342
  'ajax' => [
86
  private function verifySecAdminUsers( $aSecUsers ) {
87
  $oDP = Services::Data();
88
  $oWpUsers = Services::WpUsers();
89
+ /** @var SecurityAdmin\Options $oOpts */
90
  $oOpts = $this->getOptions();
91
 
92
  $aFiltered = [];
144
  }
145
 
146
  /**
147
+ * @inheritDoc
148
  */
149
+ protected function handleModAction( $sAction ) {
150
+ switch ( $sAction ) {
 
151
  case 'remove_secadmin_confirm':
152
  ( new SecurityAdmin\Lib\Actions\RemoveSecAdmin() )
153
  ->setMod( $this )
169
  * @return bool
170
  */
171
  public function isEnabledSecurityAdmin() {
172
+ /** @var SecurityAdmin\Options $oOpts */
173
  $oOpts = $this->getOptions();
174
  return $this->isModOptEnabled() &&
175
  ( $this->hasSecAdminUsers() ||
204
  $bValid = false;
205
  $sReqKey = Services::Request()->post( 'sec_admin_key' );
206
  if ( !empty( $sReqKey ) ) {
207
+ /** @var SecurityAdmin\Options $oOpts */
208
  $oOpts = $this->getOptions();
209
  $bValid = hash_equals( $oOpts->getAccessKeyHash(), md5( $sReqKey ) );
210
  if ( !$bValid ) {
326
  return $this->saveModOptions();
327
  }
328
 
 
 
 
 
 
 
 
329
  public function insertCustomJsVars_Admin() {
330
  parent::insertCustomJsVars_Admin();
331
 
 
332
  if ( $this->getSecAdminTimeLeft() > 0 ) {
333
  $aInsertData = [
334
  'ajax' => [
src/features/base.php CHANGED
@@ -83,26 +83,11 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends Shield\Deprecated\Foundatio
83
  * @param array $aModProps
84
  */
85
  protected function setupHooks( $aModProps ) {
86
- $oReq = Services::Request();
87
-
88
  $nRunPriority = isset( $aModProps[ 'load_priority' ] ) ? $aModProps[ 'load_priority' ] : 100;
89
  add_action( $this->prefix( 'run_processors' ), [ $this, 'onRunProcessors' ], $nRunPriority );
90
  add_action( 'init', [ $this, 'onWpInit' ], 1 );
91
  add_action( $this->prefix( 'import_options' ), [ $this, 'processImportOptions' ] );
92
 
93
- if ( $this->isModuleRequest() ) {
94
-
95
- if ( Services::WpGeneral()->isAjax() ) {
96
- $this->loadAjaxHandler();
97
- }
98
-
99
- if ( $oReq->request( 'action' ) == $this->prefix()
100
- && check_admin_referer( $oReq->request( 'exec' ), 'exec_nonce' )
101
- ) {
102
- add_action( $this->prefix( 'mod_request' ), [ $this, 'handleModRequest' ] );
103
- }
104
- }
105
-
106
  $nMenuPri = isset( $aModProps[ 'menu_priority' ] ) ? $aModProps[ 'menu_priority' ] : 100;
107
  add_filter( $this->prefix( 'submenu_items' ), [ $this, 'supplySubMenuItem' ], $nMenuPri );
108
  add_filter( $this->prefix( 'collect_mod_summary' ), [ $this, 'addModuleSummaryData' ], $nMenuPri );
@@ -348,7 +333,19 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends Shield\Deprecated\Foundatio
348
  * A action added to WordPress 'init' hook
349
  */
350
  public function onWpInit() {
351
- do_action( $this->prefix( 'mod_request' ) );
 
 
 
 
 
 
 
 
 
 
 
 
352
 
353
  $this->runWizards();
354
 
@@ -791,7 +788,7 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends Shield\Deprecated\Foundatio
791
  * @param string $sGlue
792
  * @return string|array
793
  */
794
- public function getLastErrors( $bAsString = true, $sGlue = " " ) {
795
  $aErrors = $this->getOpt( 'last_errors' );
796
  if ( !is_array( $aErrors ) ) {
797
  $aErrors = [];
@@ -895,7 +892,7 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends Shield\Deprecated\Foundatio
895
  /**
896
  * @param string $sAction
897
  * @param bool $bAsJsonEncodedObject
898
- * @return array
899
  */
900
  public function getAjaxActionData( $sAction = '', $bAsJsonEncodedObject = false ) {
901
  $aData = $this->getNonceActionData( $sAction );
@@ -1183,8 +1180,15 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends Shield\Deprecated\Foundatio
1183
  }
1184
 
1185
  /**
 
 
 
 
 
 
 
1186
  */
1187
- public function handleModRequest() {
1188
  }
1189
 
1190
  /**
@@ -1964,46 +1968,4 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends Shield\Deprecated\Foundatio
1964
  public function savePluginOptions() {
1965
  $this->saveModOptions();
1966
  }
1967
-
1968
- /**
1969
- * @return array[]
1970
- * @deprecated 8.5
1971
- */
1972
- public function getStatEvents_Recent() {
1973
- return [];
1974
- }
1975
-
1976
- /**
1977
- * @param string $sKey
1978
- * @return array|null
1979
- * @deprecated 8.5
1980
- */
1981
- public function getEventDef( $sKey ) {
1982
- return null;
1983
- }
1984
-
1985
- /**
1986
- * @param string $sKey
1987
- * @return bool
1988
- * @deprecated 8.5
1989
- */
1990
- public function isSupportedEvent( $sKey ) {
1991
- return false;
1992
- }
1993
-
1994
- /**
1995
- * @return array[]
1996
- * @deprecated 8.5
1997
- */
1998
- protected function getSupportedEvents() {
1999
- return [];
2000
- }
2001
-
2002
- /**
2003
- * @return array[]
2004
- * @deprecated 8.5
2005
- */
2006
- public function getEvents() {
2007
- return $this->getDef( 'events' );
2008
- }
2009
  }
83
  * @param array $aModProps
84
  */
85
  protected function setupHooks( $aModProps ) {
 
 
86
  $nRunPriority = isset( $aModProps[ 'load_priority' ] ) ? $aModProps[ 'load_priority' ] : 100;
87
  add_action( $this->prefix( 'run_processors' ), [ $this, 'onRunProcessors' ], $nRunPriority );
88
  add_action( 'init', [ $this, 'onWpInit' ], 1 );
89
  add_action( $this->prefix( 'import_options' ), [ $this, 'processImportOptions' ] );
90
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  $nMenuPri = isset( $aModProps[ 'menu_priority' ] ) ? $aModProps[ 'menu_priority' ] : 100;
92
  add_filter( $this->prefix( 'submenu_items' ), [ $this, 'supplySubMenuItem' ], $nMenuPri );
93
  add_filter( $this->prefix( 'collect_mod_summary' ), [ $this, 'addModuleSummaryData' ], $nMenuPri );
333
  * A action added to WordPress 'init' hook
334
  */
335
  public function onWpInit() {
336
+ $oReq = Services::Request();
337
+ if ( $this->isModuleRequest() ) {
338
+
339
+ if ( Services::WpGeneral()->isAjax() ) {
340
+ $this->loadAjaxHandler();
341
+ }
342
+
343
+ if ( $oReq->request( 'action' ) == $this->prefix()
344
+ && check_admin_referer( $oReq->request( 'exec' ), 'exec_nonce' )
345
+ && $this->getCon()->getMeetsBasePermissions() ) {
346
+ $this->handleModAction( $oReq->request( 'exec' ) );
347
+ }
348
+ }
349
 
350
  $this->runWizards();
351
 
788
  * @param string $sGlue
789
  * @return string|array
790
  */
791
+ public function getLastErrors( $bAsString = false, $sGlue = " " ) {
792
  $aErrors = $this->getOpt( 'last_errors' );
793
  if ( !is_array( $aErrors ) ) {
794
  $aErrors = [];
892
  /**
893
  * @param string $sAction
894
  * @param bool $bAsJsonEncodedObject
895
+ * @return array|string
896
  */
897
  public function getAjaxActionData( $sAction = '', $bAsJsonEncodedObject = false ) {
898
  $aData = $this->getNonceActionData( $sAction );
1180
  }
1181
 
1182
  /**
1183
+ * @param string $sAction
1184
+ */
1185
+ protected function handleModAction( $sAction ) {
1186
+ }
1187
+
1188
+ /**
1189
+ * @deprecated 8.6.2
1190
  */
1191
+ protected function handleModRequest() {
1192
  }
1193
 
1194
  /**
1968
  public function savePluginOptions() {
1969
  $this->saveModOptions();
1970
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1971
  }
src/features/base_wpsf.php CHANGED
@@ -379,58 +379,4 @@ class ICWP_WPSF_FeatureHandler_BaseWpsf extends ICWP_WPSF_FeatureHandler_Base {
379
  public function getIpOffenceCount() {
380
  return isset( self::$nIpOffenceCount ) ? self::$nIpOffenceCount : 0;
381
  }
382
-
383
- /**
384
- * @param string $sEvent
385
- * @param array $aMeta
386
- * @return $this
387
- * @deprecated 8.5
388
- */
389
- public function eventAudit( $sEvent = '', $aMeta = [] ) {
390
- return $this;
391
- }
392
-
393
- /**
394
- * @param string $sEvent
395
- * @param array $aMeta
396
- * @deprecated 8.5
397
- */
398
- public function eventOffense( $sEvent, $aMeta = [] ) {
399
- }
400
-
401
- /**
402
- * @param string $sEvent
403
- * @param array $aMeta
404
- * @deprecated 8.5
405
- */
406
- public function eventStat( $sEvent, $aMeta = [] ) {
407
- }
408
-
409
- /**
410
- * @param string $sEvent
411
- * @param array $aMeta
412
- * @return $this
413
- * @deprecated 8.5
414
- */
415
- protected function addStatEvent( $sEvent, $aMeta = [] ) {
416
- return $this;
417
- }
418
-
419
- /**
420
- * @param bool $bFlush
421
- * @return Shield\Databases\AuditTrail\EntryVO[]
422
- * @deprecated 8.5
423
- */
424
- public function getRegisteredAuditLogs( $bFlush = false ) {
425
- return [];
426
- }
427
-
428
- /**
429
- * @param bool $bFlush
430
- * @return string[]
431
- * @deprecated 8.5
432
- */
433
- public function getRegisteredEvents( $bFlush = false ) {
434
- return [];
435
- }
436
  }
379
  public function getIpOffenceCount() {
380
  return isset( self::$nIpOffenceCount ) ? self::$nIpOffenceCount : 0;
381
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
382
  }
src/features/comments_filter.php CHANGED
@@ -5,20 +5,6 @@ use FernleafSystems\Wordpress\Services\Services;
5
 
6
  class ICWP_WPSF_FeatureHandler_CommentsFilter extends ICWP_WPSF_FeatureHandler_BaseWpsf {
7
 
8
- /**
9
- * @return int
10
- */
11
- public function getTokenCooldown() {
12
- return (int)$this->getOpt( 'comments_cooldown_interval' );
13
- }
14
-
15
- /**
16
- * @return int
17
- */
18
- public function getTokenExpireInterval() {
19
- return (int)$this->getOpt( 'comments_token_expire_interval' );
20
- }
21
-
22
  /**
23
  * @return string
24
  */
@@ -76,7 +62,9 @@ class ICWP_WPSF_FeatureHandler_CommentsFilter extends ICWP_WPSF_FeatureHandler_B
76
  }
77
 
78
  protected function doExtraSubmitProcessing() {
79
- if ( $this->getTokenExpireInterval() != 0 && $this->getTokenCooldown() > $this->getTokenExpireInterval() ) {
 
 
80
  $this->getOptions()->resetOptToDefault( 'comments_cooldown_interval' );
81
  $this->getOptions()->resetOptToDefault( 'comments_token_expire_interval' );
82
  }
@@ -219,4 +207,12 @@ class ICWP_WPSF_FeatureHandler_CommentsFilter extends ICWP_WPSF_FeatureHandler_B
219
  public function getSpamBlacklistFile() {
220
  return $this->getCon()->getPluginCachePath( 'spamblacklist.txt' );
221
  }
 
 
 
 
 
 
 
 
222
  }
5
 
6
  class ICWP_WPSF_FeatureHandler_CommentsFilter extends ICWP_WPSF_FeatureHandler_BaseWpsf {
7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  /**
9
  * @return string
10
  */
62
  }
63
 
64
  protected function doExtraSubmitProcessing() {
65
+ /** @var Shield\Modules\CommentsFilter\Options $oOpts */
66
+ $oOpts = $this->getOptions();
67
+ if ( $oOpts->getTokenExpireInterval() != 0 && $oOpts->getTokenCooldown() > $oOpts->getTokenExpireInterval() ) {
68
  $this->getOptions()->resetOptToDefault( 'comments_cooldown_interval' );
69
  $this->getOptions()->resetOptToDefault( 'comments_token_expire_interval' );
70
  }
207
  public function getSpamBlacklistFile() {
208
  return $this->getCon()->getPluginCachePath( 'spamblacklist.txt' );
209
  }
210
+
211
+ /**
212
+ * @return int
213
+ * @deprecated 8.6.0
214
+ */
215
+ public function getTokenCooldown() {
216
+ return (int)$this->getOpt( 'comments_cooldown_interval' );
217
+ }
218
  }
src/features/hack_protect.php CHANGED
@@ -63,19 +63,17 @@ class ICWP_WPSF_FeatureHandler_HackProtect extends ICWP_WPSF_FeatureHandler_Base
63
  }
64
 
65
  /**
66
- */
67
- public function handleModRequest() {
68
- $oReq = Services::Request();
69
- if ( $this->getCon()->isPluginAdmin() ) {
70
- switch ( $oReq->query( 'exec' ) ) {
71
- case 'scan_file_download':
72
- ( new Shield\Modules\HackGuard\Lib\Utility\FileDownloadHandler() )
73
- ->setDbHandler( $this->getDbHandler_ScanResults() )
74
- ->downloadByItemId( (int)$oReq->query( 'rid', 0 ) );
75
- break;
76
- default:
77
- break;
78
- }
79
  }
80
  }
81
 
@@ -795,11 +793,11 @@ class ICWP_WPSF_FeatureHandler_HackProtect extends ICWP_WPSF_FeatureHandler_Base
795
  'weight' => 2,
796
  'href' => $this->getUrl_DirectLinkToSection( 'section_scan_wcf' ),
797
  ];
798
- if ( $bCore && !$this->isWcfScanAutoRepair() ) {
799
  $aThis[ 'key_opts' ][ 'wcf_repair' ] = [
800
  'name' => __( 'WP Core File Repair', 'wp-simple-firewall' ),
801
- 'enabled' => $this->isWcfScanAutoRepair(),
802
- 'summary' => $this->isWcfScanAutoRepair() ?
803
  __( 'Core files are automatically repaired', 'wp-simple-firewall' )
804
  : __( "Core files aren't automatically repaired!", 'wp-simple-firewall' ),
805
  'weight' => 1,
@@ -807,7 +805,7 @@ class ICWP_WPSF_FeatureHandler_HackProtect extends ICWP_WPSF_FeatureHandler_Base
807
  ];
808
  }
809
 
810
- $bUcf = $this->isUfcEnabled();
811
  $aThis[ 'key_opts' ][ 'ufc' ] = [
812
  'name' => __( 'Unrecognised Files', 'wp-simple-firewall' ),
813
  'enabled' => $bUcf,
@@ -817,11 +815,11 @@ class ICWP_WPSF_FeatureHandler_HackProtect extends ICWP_WPSF_FeatureHandler_Base
817
  'weight' => 2,
818
  'href' => $this->getUrl_DirectLinkToSection( 'section_scan_ufc' ),
819
  ];
820
- if ( $bUcf && !$this->isUfcDeleteFiles() ) {
821
  $aThis[ 'key_opts' ][ 'ufc_repair' ] = [
822
  'name' => __( 'Unrecognised Files Removal', 'wp-simple-firewall' ),
823
- 'enabled' => $this->isUfcDeleteFiles(),
824
- 'summary' => $this->isUfcDeleteFiles() ?
825
  __( 'Unrecognised files are automatically removed', 'wp-simple-firewall' )
826
  : __( "Unrecognised files aren't automatically removed!", 'wp-simple-firewall' ),
827
  'weight' => 1,
@@ -935,191 +933,4 @@ class ICWP_WPSF_FeatureHandler_HackProtect extends ICWP_WPSF_FeatureHandler_Base
935
  protected function getNamespaceBase() {
936
  return 'HackGuard';
937
  }
938
-
939
- /**
940
- * @return bool
941
- * @deprecated 8.5
942
- */
943
- public function isPtgReadyToScan() {
944
- return false;
945
- }
946
-
947
- /**
948
- * @param int $nTime
949
- * @return $this
950
- * @deprecated 8.5
951
- */
952
- public function setPtgLastBuildAt( $nTime = null ) {
953
- return $this;
954
- }
955
-
956
- /**
957
- * @return int
958
- * @deprecated 8.5
959
- */
960
- public function getPtgLastBuildAt() {
961
- return $this->getOpt( 'ptg_last_build_at' );
962
- }
963
-
964
- /**
965
- * @return bool
966
- * @deprecated 8.5
967
- */
968
- public function isPtgRebuildSelfRequired() {
969
- return $this->isOpt( 'rebuild_self', true );
970
- }
971
-
972
- /**
973
- * @param bool $bIsRequired
974
- * @return $this
975
- * @deprecated 8.5
976
- */
977
- public function setPtgRebuildSelfRequired( $bIsRequired ) {
978
- return $this->setOpt( 'rebuild_self', (bool)$bIsRequired );
979
- }
980
-
981
- /**
982
- * @return bool
983
- * @deprecated 8.5
984
- */
985
- public function isPtgBuildRequired() {
986
- return false;
987
- }
988
-
989
- /**
990
- * @param bool $bIsRequired
991
- * @return $this
992
- * @deprecated 8.5
993
- */
994
- public function setPtgUpdateStoreFormat( $bIsRequired ) {
995
- return $this->setOpt( 'ptg_update_store_format', (bool)$bIsRequired );
996
- }
997
-
998
- /**
999
- * @return bool
1000
- * @deprecated 8.5
1001
- */
1002
- public function getPtgDepth() {
1003
- return 0;
1004
- }
1005
-
1006
- /**
1007
- * @return bool
1008
- * @deprecated 8.5
1009
- */
1010
- public function isPtgUpdateStoreFormat() {
1011
- return $this->isOpt( 'ptg_update_store_format', true );
1012
- }
1013
-
1014
- /**
1015
- * @return string[]
1016
- * @deprecated 8.5
1017
- */
1018
- public function getPtgFileExtensions() {
1019
- return $this->getOpt( 'ptg_extensions' );
1020
- }
1021
-
1022
- /**
1023
- * @return bool
1024
- * @deprecated 8.5
1025
- */
1026
- public function isPtgReinstallLinks() {
1027
- return $this->isOpt( 'ptg_reinstall_links', 'Y' );
1028
- }
1029
-
1030
- /**
1031
- * @return string
1032
- * @deprecated 8.5
1033
- */
1034
- public function isUfcDeleteFiles() {
1035
- /** @var HackGuard\Options $oOpts */
1036
- $oOpts = $this->getOptions();
1037
- return $oOpts->isUfcDeleteFiles();
1038
- }
1039
-
1040
- /**
1041
- * @return bool
1042
- * @deprecated 8.5
1043
- */
1044
- public function isUfcEnabled() {
1045
- /** @var HackGuard\Options $oOpts */
1046
- $oOpts = $this->getOptions();
1047
- return $oOpts->isUfcEnabled();
1048
- }
1049
-
1050
- /**
1051
- * @return string
1052
- * @deprecated 8.5
1053
- */
1054
- public function isUfcSendReport() {
1055
- /** @var HackGuard\Options $oOpts */
1056
- $oOpts = $this->getOptions();
1057
- return $oOpts->isUfcSendReport();
1058
- }
1059
-
1060
- /**
1061
- * @return bool
1062
- * @deprecated 8.5
1063
- */
1064
- public function isApcEnabled() {
1065
- /** @var HackGuard\Options $oOpts */
1066
- $oOpts = $this->getOptions();
1067
- return $oOpts->isApcEnabled();
1068
- }
1069
-
1070
- /**
1071
- * @return bool
1072
- * @deprecated 8.5
1073
- */
1074
- public function isWcfScanEnabled() {
1075
- /** @var HackGuard\Options $oOpts */
1076
- $oOpts = $this->getOptions();
1077
- return $oOpts->isWcfScanEnabled();
1078
- }
1079
-
1080
- /**
1081
- * @return bool
1082
- * @deprecated 8.5
1083
- */
1084
- public function isWpvulnEnabled() {
1085
- /** @var HackGuard\Options $oOpts */
1086
- $oOpts = $this->getOptions();
1087
- return $oOpts->isWpvulnEnabled();
1088
- }
1089
-
1090
- /**
1091
- * @return bool
1092
- * @deprecated 8.5
1093
- */
1094
- public function isWpvulnSendEmail() {
1095
- return $this->isWpvulnEnabled() && $this->isOpt( 'enable_wpvuln_scan', 'enabled_email' );
1096
- }
1097
-
1098
- /**
1099
- * @return bool
1100
- * @deprecated 8.5
1101
- */
1102
- public function isWpvulnAutoupdatesEnabled() {
1103
- /** @var HackGuard\Options $oOpts */
1104
- $oOpts = $this->getOptions();
1105
- return $oOpts->isWpvulnAutoupdatesEnabled();
1106
- }
1107
-
1108
- /**
1109
- * @return string
1110
- * @deprecated 8.5
1111
- */
1112
- public function getUnrecognisedFileScannerOption() {
1113
- return $this->getOpt( 'enable_unrecognised_file_cleaner_scan', 'disabled' );
1114
- }
1115
-
1116
- /**
1117
- * @return bool
1118
- * @deprecated 8.5
1119
- */
1120
- public function isWcfScanAutoRepair() {
1121
- /** @var HackGuard\Options $oOpts */
1122
- $oOpts = $this->getOptions();
1123
- return $oOpts->isWcfScanAutoRepair();
1124
- }
1125
  }
63
  }
64
 
65
  /**
66
+ * @inheritDoc
67
+ */
68
+ protected function handleModAction( $sAction ) {
69
+ switch ( $sAction ) {
70
+ case 'scan_file_download':
71
+ ( new HackGuard\Lib\Utility\FileDownloadHandler() )
72
+ ->setDbHandler( $this->getDbHandler_ScanResults() )
73
+ ->downloadByItemId( (int)Services::Request()->query( 'rid', 0 ) );
74
+ break;
75
+ default:
76
+ break;
 
 
77
  }
78
  }
79
 
793
  'weight' => 2,
794
  'href' => $this->getUrl_DirectLinkToSection( 'section_scan_wcf' ),
795
  ];
796
+ if ( $bCore && !$oOpts->isWcfScanAutoRepair() ) {
797
  $aThis[ 'key_opts' ][ 'wcf_repair' ] = [
798
  'name' => __( 'WP Core File Repair', 'wp-simple-firewall' ),
799
+ 'enabled' => $oOpts->isWcfScanAutoRepair(),
800
+ 'summary' => $oOpts->isWcfScanAutoRepair() ?
801
  __( 'Core files are automatically repaired', 'wp-simple-firewall' )
802
  : __( "Core files aren't automatically repaired!", 'wp-simple-firewall' ),
803
  'weight' => 1,
805
  ];
806
  }
807
 
808
+ $bUcf = $oOpts->isUfcEnabled();
809
  $aThis[ 'key_opts' ][ 'ufc' ] = [
810
  'name' => __( 'Unrecognised Files', 'wp-simple-firewall' ),
811
  'enabled' => $bUcf,
815
  'weight' => 2,
816
  'href' => $this->getUrl_DirectLinkToSection( 'section_scan_ufc' ),
817
  ];
818
+ if ( $bUcf && !$oOpts->isUfcDeleteFiles() ) {
819
  $aThis[ 'key_opts' ][ 'ufc_repair' ] = [
820
  'name' => __( 'Unrecognised Files Removal', 'wp-simple-firewall' ),
821
+ 'enabled' => $oOpts->isUfcDeleteFiles(),
822
+ 'summary' => $oOpts->isUfcDeleteFiles() ?
823
  __( 'Unrecognised files are automatically removed', 'wp-simple-firewall' )
824
  : __( "Unrecognised files aren't automatically removed!", 'wp-simple-firewall' ),
825
  'weight' => 1,
933
  protected function getNamespaceBase() {
934
  return 'HackGuard';
935
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
936
  }
src/features/headers.php CHANGED
@@ -140,67 +140,4 @@ class ICWP_WPSF_FeatureHandler_Headers extends ICWP_WPSF_FeatureHandler_BaseWpsf
140
  protected function getNamespaceBase() {
141
  return 'Headers';
142
  }
143
-
144
- /**
145
- * @return bool
146
- * @deprecated 8.5
147
- */
148
- public function isContentSecurityPolicyEnabled() {
149
- return $this->isOpt( 'enable_x_content_security_policy', 'Y' );
150
- }
151
-
152
- /**
153
- * @return bool
154
- * @deprecated 8.5
155
- */
156
- public function isReferrerPolicyEnabled() {
157
- return !$this->isOpt( 'x_referrer_policy', 'disabled' );
158
- }
159
-
160
- /**
161
- * @return bool
162
- * @deprecated 8.5
163
- */
164
- public function isEnabledXFrame() {
165
- return in_array( $this->getOpt( 'x_frame' ), [ 'on_sameorigin', 'on_deny' ] );
166
- }
167
-
168
- /**
169
- * @return bool
170
- * @deprecated 8.5
171
- */
172
- public function isEnabledXssProtection() {
173
- return $this->isOpt( 'x_xss_protect', 'Y' );
174
- }
175
-
176
- /**
177
- * @return bool
178
- * @deprecated 8.5
179
- */
180
- public function isEnabledContentTypeHeader() {
181
- return $this->isOpt( 'x_content_type', 'Y' );
182
- }
183
-
184
- /**
185
- * Using this function without first checking isReferrerPolicyEnabled() will result in empty
186
- * referrer policy header in the case of "disabled"
187
- * @return string
188
- * @deprecated 8.5
189
- */
190
- public function getReferrerPolicyValue() {
191
- $sValue = $this->getOpt( 'x_referrer_policy' );
192
- return in_array( $sValue, [ 'empty', 'disabled' ] ) ? '' : $sValue;
193
- }
194
-
195
- /**
196
- * @return array
197
- * @deprecated 8.5
198
- */
199
- public function getCspHosts() {
200
- $aHosts = $this->getOpt( 'xcsp_hosts', [] );
201
- if ( empty( $aHosts ) || !is_array( $aHosts ) ) {
202
- $aHosts = [];
203
- }
204
- return $aHosts;
205
- }
206
  }
140
  protected function getNamespaceBase() {
141
  return 'Headers';
142
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  }
src/features/insights.php CHANGED
@@ -266,12 +266,6 @@ class ICWP_WPSF_FeatureHandler_Insights extends ICWP_WPSF_FeatureHandler_BaseWps
266
  'insight_notices_count' => $nNoticesCount,
267
  'insight_stats' => $this->getStats(),
268
  ],
269
- 'inputs' => [
270
- 'license_key' => [
271
- 'name' => $oCon->prefixOption( 'license_key' ),
272
- 'maxlength' => $this->getDef( 'license_key_length' ),
273
- ]
274
- ],
275
  'ajax' => [
276
  'render_chart_post' => $oEvtsMod->getAjaxActionData( 'render_chart_post', true ),
277
  ],
266
  'insight_notices_count' => $nNoticesCount,
267
  'insight_stats' => $this->getStats(),
268
  ],
 
 
 
 
 
 
269
  'ajax' => [
270
  'render_chart_post' => $oEvtsMod->getAjaxActionData( 'render_chart_post', true ),
271
  ],
src/features/ips.php CHANGED
@@ -35,7 +35,7 @@ class ICWP_WPSF_FeatureHandler_Ips extends ICWP_WPSF_FeatureHandler_BaseWpsf {
35
  }
36
 
37
  protected function doExtraSubmitProcessing() {
38
- /** @var Shield\Modules\IPs\Options $oOpts */
39
  $oOpts = $this->getOptions();
40
  if ( !defined( strtoupper( $oOpts->getOpt( 'auto_expire' ).'_IN_SECONDS' ) ) ) {
41
  $oOpts->resetOptToDefault( 'auto_expire' );
@@ -118,7 +118,7 @@ class ICWP_WPSF_FeatureHandler_Ips extends ICWP_WPSF_FeatureHandler_BaseWpsf {
118
  protected function getSectionWarnings( $sSection ) {
119
  $aWarnings = [];
120
 
121
- /** @var Shield\Modules\IPs\Options $oOpts */
122
  $oOpts = $this->getOptions();
123
 
124
  switch ( $sSection ) {
@@ -206,15 +206,19 @@ class ICWP_WPSF_FeatureHandler_Ips extends ICWP_WPSF_FeatureHandler_BaseWpsf {
206
  $aIps = apply_filters( 'icwp_simple_firewall_whitelist_ips', $aIps );
207
 
208
  if ( !empty( $aIps ) && is_array( $aIps ) ) {
209
- $aWhiteIps = ( new Shield\Modules\IPs\Lib\Ops\RetrieveIpsForLists() )
210
  ->setDbHandler( $this->getDbHandler_IPs() )
211
  ->white();
212
  foreach ( $aIps as $sIP => $sLabel ) {
213
  if ( !in_array( $sIP, $aWhiteIps ) ) {
214
- ( new Shield\Modules\IPs\Lib\Ops\AddIp() )
215
- ->setMod( $this )
216
- ->setIP( $sIP )
217
- ->toManualWhitelist( $sLabel );
 
 
 
 
218
  }
219
  }
220
  }
@@ -226,13 +230,4 @@ class ICWP_WPSF_FeatureHandler_Ips extends ICWP_WPSF_FeatureHandler_BaseWpsf {
226
  protected function getNamespaceBase() {
227
  return 'IPs';
228
  }
229
-
230
- /**
231
- * IP addresses that should never be put on the black list.
232
- * @return string[]
233
- * @deprecated 8.5.1
234
- */
235
- public function getReservedIps() {
236
- return Services::IP()->getServerPublicIPs();
237
- }
238
  }
35
  }
36
 
37
  protected function doExtraSubmitProcessing() {
38
+ /** @var IPs\Options $oOpts */
39
  $oOpts = $this->getOptions();
40
  if ( !defined( strtoupper( $oOpts->getOpt( 'auto_expire' ).'_IN_SECONDS' ) ) ) {
41
  $oOpts->resetOptToDefault( 'auto_expire' );
118
  protected function getSectionWarnings( $sSection ) {
119
  $aWarnings = [];
120
 
121
+ /** @var IPs\Options $oOpts */
122
  $oOpts = $this->getOptions();
123
 
124
  switch ( $sSection ) {
206
  $aIps = apply_filters( 'icwp_simple_firewall_whitelist_ips', $aIps );
207
 
208
  if ( !empty( $aIps ) && is_array( $aIps ) ) {
209
+ $aWhiteIps = ( new IPs\Lib\Ops\RetrieveIpsForLists() )
210
  ->setDbHandler( $this->getDbHandler_IPs() )
211
  ->white();
212
  foreach ( $aIps as $sIP => $sLabel ) {
213
  if ( !in_array( $sIP, $aWhiteIps ) ) {
214
+ try {
215
+ ( new IPs\Lib\Ops\AddIp() )
216
+ ->setMod( $this )
217
+ ->setIP( $sIP )
218
+ ->toManualWhitelist( $sLabel );
219
+ }
220
+ catch ( Exception $oE ) {
221
+ }
222
  }
223
  }
224
  }
230
  protected function getNamespaceBase() {
231
  return 'IPs';
232
  }
 
 
 
 
 
 
 
 
 
233
  }
src/features/license.php CHANGED
@@ -1,11 +1,121 @@
1
  <?php
2
 
3
  use FernleafSystems\Wordpress\Plugin\Shield;
 
4
  use FernleafSystems\Wordpress\Services\Services;
5
  use FernleafSystems\Wordpress\Services\Utilities;
6
 
7
  class ICWP_WPSF_FeatureHandler_License extends ICWP_WPSF_FeatureHandler_BaseWpsf {
8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  protected function redirectToInsightsSubPage() {
10
  Services::Response()->redirect(
11
  $this->getCon()->getModule_Insights()->getUrl_AdminPage(),
@@ -13,9 +123,23 @@ class ICWP_WPSF_FeatureHandler_License extends ICWP_WPSF_FeatureHandler_BaseWpsf
13
  );
14
  }
15
 
 
 
 
 
16
  protected function setupCustomHooks() {
17
- parent::setupCustomHooks();
18
- add_filter( $this->getCon()->getPremiumLicenseFilterName(), [ $this, 'hasValidWorkingLicense' ], PHP_INT_MAX );
 
 
 
 
 
 
 
 
 
 
19
  }
20
 
21
  /**
@@ -26,19 +150,25 @@ class ICWP_WPSF_FeatureHandler_License extends ICWP_WPSF_FeatureHandler_BaseWpsf
26
  }
27
 
28
  public function onPluginShutdown() {
29
- $this->verifyLicense( false );
 
 
 
 
30
  parent::onPluginShutdown();
31
  }
32
 
33
  /**
34
  * @return Shield\License\EddLicenseVO
 
35
  */
36
  protected function loadLicense() {
37
- return ( new Shield\License\EddLicenseVO() )->applyFromArray( $this->getLicenseData() );
38
  }
39
 
40
  /**
41
  * @return array
 
42
  */
43
  protected function getLicenseData() {
44
  $aData = $this->getOpt( 'license_data', [] );
@@ -47,6 +177,7 @@ class ICWP_WPSF_FeatureHandler_License extends ICWP_WPSF_FeatureHandler_BaseWpsf
47
 
48
  /**
49
  * @return $this
 
50
  */
51
  public function clearLicenseData() {
52
  return $this->setOpt( 'license_data', [] );
@@ -55,6 +186,7 @@ class ICWP_WPSF_FeatureHandler_License extends ICWP_WPSF_FeatureHandler_BaseWpsf
55
  /**
56
  * @param Utilities\Licenses\EddLicenseVO $oLic
57
  * @return $this
 
58
  */
59
  protected function setLicenseData( $oLic ) {
60
  return $this->setOpt( 'license_data', $oLic->getRawDataAsArray() );
@@ -62,18 +194,9 @@ class ICWP_WPSF_FeatureHandler_License extends ICWP_WPSF_FeatureHandler_BaseWpsf
62
 
63
  /**
64
  * @param string $sDeactivatedReason
 
65
  */
66
  public function deactivate( $sDeactivatedReason = '' ) {
67
- $oOpts = $this->getOptions();
68
- if ( $this->isLicenseActive() ) {
69
- $oOpts->setOptAt( 'license_deactivated_at' );
70
- }
71
-
72
- if ( !empty( $sDeactivatedReason ) ) {
73
- $oOpts->setOpt( 'license_deactivated_reason', $sDeactivatedReason );
74
- }
75
- // force all options to resave i.e. reset premium to defaults.
76
- add_filter( $this->prefix( 'force_options_resave' ), '__return_true' );
77
  }
78
 
79
  /**
@@ -81,91 +204,44 @@ class ICWP_WPSF_FeatureHandler_License extends ICWP_WPSF_FeatureHandler_BaseWpsf
81
  * for a currently valid license.
82
  * @param bool $bForceCheck
83
  * @return $this
 
84
  */
85
  public function verifyLicense( $bForceCheck = true ) {
86
- $oCon = $this->getCon();
87
- // Is a check actually required and permitted
88
- $bCheckReq = $this->isLicenseCheckRequired() && $this->canLicenseCheck();
89
-
90
- // 1 check in 20 seconds
91
- if ( ( $bForceCheck || $bCheckReq ) && $this->getIsLicenseNotCheckedFor( 20 ) ) {
92
-
93
- $oCurrent = $this->loadLicense();
94
-
95
- $this->touchLicenseCheckFileFlag()
96
- ->setLicenseLastCheckedAt();
97
- $this->saveModOptions();
98
-
99
- $oLookupLicense = $this->lookupOfficialLicense();
100
- if ( $oLookupLicense->isValid() ) {
101
- $oCurrent = $oLookupLicense;
102
- $oCurrent->updateLastVerifiedAt( true );
103
- $this->activateLicense()
104
- ->clearLastErrors();
105
- $oCon->fireEvent( 'lic_check_success' );
106
- }
107
- else {
108
- if ( $oCurrent->isValid() ) { // we have something valid previously stored
109
-
110
- if ( !$bForceCheck && $this->isWithinVerifiedGraceExpired() ) {
111
- $this->sendLicenseWarningEmail();
112
- $oCon->fireEvent( 'lic_fail_email' );
113
- }
114
- elseif ( $bForceCheck || $oCurrent->isExpired() || $this->isLastVerifiedGraceExpired() ) {
115
- $oCurrent = $oLookupLicense;
116
- $this->deactivate( __( 'Automatic license verification failed.', 'wp-simple-firewall' ) );
117
- $this->sendLicenseDeactivatedEmail();
118
- $oCon->fireEvent( 'lic_fail_deactivate' );
119
- }
120
- }
121
- else {
122
- // No previously valid license, and the license lookup also failed but the http request was successful.
123
- if ( $oLookupLicense->isReady() ) {
124
- $this->deactivate();
125
- $oCurrent = $oLookupLicense;
126
- }
127
- }
128
- }
129
-
130
- $oCurrent->last_request_at = Services::Request()->ts();
131
- $this->setLicenseData( $oCurrent );
132
- $this->saveModOptions();
133
  }
134
-
135
  return $this;
136
  }
137
 
138
  /**
139
  * @return bool
 
140
  */
141
  private function isLicenseCheckRequired() {
142
- return ( $this->isLicenseMaybeExpiring() && $this->getIsLicenseNotCheckedFor( HOUR_IN_SECONDS*4 ) )
143
- || ( $this->isLicenseActive()
144
- && !$this->loadLicense()->isReady() && $this->getIsLicenseNotCheckedFor( HOUR_IN_SECONDS ) )
145
- || ( $this->hasValidWorkingLicense() && $this->isLastVerifiedExpired()
146
- && $this->getIsLicenseNotCheckedFor( HOUR_IN_SECONDS*4 ) );
147
  }
148
 
149
  /**
150
  * @return bool
 
151
  */
152
  private function canLicenseCheck() {
153
- return !in_array( $this->getCon()->getShieldAction(), [ 'keyless_handshake', 'license_check' ] )
154
- && $this->canLicenseCheck_FileFlag();
155
  }
156
 
157
  /**
158
  * @return bool
 
159
  */
160
  private function canLicenseCheck_FileFlag() {
161
- $oFs = Services::WpFs();
162
- $sFileFlag = $this->getCon()->getPath_Flags( 'license_check' );
163
- $nMtime = $oFs->exists( $sFileFlag ) ? $oFs->getModifiedTime( $sFileFlag ) : 0;
164
- return ( Services::Request()->ts() - $nMtime ) > MINUTE_IN_SECONDS;
165
  }
166
 
167
  /**
168
  * @return $this
 
169
  */
170
  private function touchLicenseCheckFileFlag() {
171
  Services::WpFs()->touch( $this->getCon()->getPath_Flags( 'license_check' ) );
@@ -174,110 +250,35 @@ class ICWP_WPSF_FeatureHandler_License extends ICWP_WPSF_FeatureHandler_BaseWpsf
174
 
175
  /**
176
  * @return bool
 
177
  */
178
  protected function isLicenseMaybeExpiring() {
179
- return $this->isLicenseActive() &&
180
- (
181
- abs( Services::Request()->ts() - $this->loadLicense()->getExpiresAt() )
182
- < ( DAY_IN_SECONDS/2 )
183
- );
184
  }
185
 
186
  /**
187
  * @return $this
 
188
  */
189
  protected function activateLicense() {
190
- if ( !$this->isLicenseActive() ) {
191
- $this->getOptions()->setOptAt( 'license_activated_at' );
192
- }
193
  return $this;
194
  }
195
 
196
  /**
 
197
  */
198
  protected function sendLicenseWarningEmail() {
199
- $oOpts = $this->getOptions();
200
-
201
- $bCanSend = Services::Request()
202
- ->carbon()
203
- ->subDay( 1 )->timestamp > $oOpts->getOpt( 'last_warning_email_sent_at' );
204
-
205
- if ( $bCanSend ) {
206
- $oOpts->setOptAt( 'last_warning_email_sent_at' );
207
- $this->saveModOptions();
208
-
209
- $aMessage = [
210
- __( 'Attempts to verify Shield Pro license has just failed.', 'wp-simple-firewall' ),
211
- sprintf( __( 'Please check your license on-site: %s', 'wp-simple-firewall' ), $this->getUrl_AdminPage() ),
212
- sprintf( __( 'If this problem persists, please contact support: %s', 'wp-simple-firewall' ), 'https://support.onedollarplugin.com/' )
213
- ];
214
- $this->getEmailProcessor()
215
- ->sendEmailWithWrap(
216
- $this->getPluginDefaultRecipientAddress(),
217
- 'Pro License Check Has Failed',
218
- $aMessage
219
- );
220
- }
221
  }
222
 
223
  /**
 
224
  */
225
  private function sendLicenseDeactivatedEmail() {
226
- $oOpts = $this->getOptions();
227
-
228
- $bCanSend = Services::Request()
229
- ->carbon()
230
- ->subDay( 1 )->timestamp > $oOpts->getOpt( 'last_deactivated_email_sent_at' );
231
-
232
- if ( $bCanSend ) {
233
- $oOpts->setOptAt( 'last_deactivated_email_sent_at' );
234
- $this->saveModOptions();
235
-
236
- $aMessage = [
237
- __( 'All attempts to verify Shield Pro license have failed.', 'wp-simple-firewall' ),
238
- sprintf( __( 'Please check your license on-site: %s', 'wp-simple-firewall' ), $this->getUrl_AdminPage() ),
239
- sprintf( __( 'If this problem persists, please contact support: %s', 'wp-simple-firewall' ), 'https://support.onedollarplugin.com/' )
240
- ];
241
- $this->getEmailProcessor()
242
- ->sendEmailWithWrap(
243
- $this->getPluginDefaultRecipientAddress(),
244
- '[Action May Be Required] Pro License Has Been Deactivated',
245
- $aMessage
246
- );
247
- }
248
- }
249
-
250
- /**
251
- * @return Utilities\Licenses\EddLicenseVO
252
- */
253
- private function lookupOfficialLicense() {
254
-
255
- $sPass = wp_generate_password( 16 );
256
-
257
- $this->setKeylessRequestAt()
258
- ->setKeylessRequestHash( sha1( $sPass.Services::WpGeneral()->getHomeUrl( '', true ) ) );
259
- $this->saveModOptions();
260
-
261
- $oLicense = ( new Utilities\Licenses\Lookup() )
262
- ->setRequestParams(
263
- [
264
- 'installation_id' => $this->getCon()->getSiteInstallationId(),
265
- 'version_shield' => $this->getCon()->getVersion(),
266
- 'nonce' => $sPass,
267
- ]
268
- )
269
- ->activateLicenseKeyless( $this->getLicenseStoreUrl(), $this->getLicenseItemId() );
270
-
271
- // clear the handshake data
272
- $this->setKeylessRequestAt( 0 )
273
- ->setKeylessRequestHash( '' );
274
- $this->saveModOptions();
275
-
276
- return $oLicense;
277
  }
278
 
279
  /**
280
  * @return int
 
281
  */
282
  protected function getLicenseActivatedAt() {
283
  return $this->getOpt( 'license_activated_at' );
@@ -285,6 +286,7 @@ class ICWP_WPSF_FeatureHandler_License extends ICWP_WPSF_FeatureHandler_BaseWpsf
285
 
286
  /**
287
  * @return int
 
288
  */
289
  protected function getLicenseDeactivatedAt() {
290
  return $this->getOpt( 'license_deactivated_at' );
@@ -292,43 +294,17 @@ class ICWP_WPSF_FeatureHandler_License extends ICWP_WPSF_FeatureHandler_BaseWpsf
292
 
293
  /**
294
  * @return string
295
- */
296
- public function getLicenseKey() {
297
- return $this->getOpt( 'license_key' );
298
- }
299
-
300
- /**
301
- * @return string
302
- */
303
- public function hasLicenseKey() {
304
- return $this->isLicenseKeyValidFormat();
305
- }
306
-
307
- /**
308
- * @return string
309
- */
310
- public function getLicenseItemId() {
311
- return $this->getDef( 'license_item_id' );
312
- }
313
-
314
- /**
315
- * @return string
316
  */
317
  public function getLicenseItemName() {
318
- return $this->loadLicense()->is_central ?
319
  $this->getDef( 'license_item_name_sc' ) :
320
  $this->getDef( 'license_item_name' );
321
  }
322
 
323
- /**
324
- * @return string
325
- */
326
- public function getLicenseStoreUrl() {
327
- return $this->getDef( 'license_store_url' );
328
- }
329
-
330
  /**
331
  * @return int
 
332
  */
333
  protected function getLicenseLastCheckedAt() {
334
  return $this->getOpt( 'license_last_checked_at' );
@@ -337,31 +313,26 @@ class ICWP_WPSF_FeatureHandler_License extends ICWP_WPSF_FeatureHandler_BaseWpsf
337
  /**
338
  * @param int $nTimePeriod
339
  * @return bool
 
340
  */
341
  private function getIsLicenseNotCheckedFor( $nTimePeriod ) {
342
- return ( $this->getLicenseNotCheckedForInterval() > $nTimePeriod );
343
  }
344
 
345
  /**
346
  * @return int
 
347
  */
348
  public function getLicenseNotCheckedForInterval() {
349
- return ( Services::Request()->ts() - $this->getLicenseLastCheckedAt() );
350
  }
351
 
352
  /**
353
  * @return bool
 
354
  */
355
  public function isLicenseActive() {
356
- return ( $this->getLicenseActivatedAt() > 0 )
357
- && ( $this->getLicenseDeactivatedAt() < $this->getLicenseActivatedAt() );
358
- }
359
-
360
- /**
361
- * @return bool
362
- */
363
- public function isLicenseKeyValidFormat() {
364
- return !is_null( $this->verifyLicenseKeyFormat( $this->getLicenseKey() ) );
365
  }
366
 
367
  /**
@@ -373,222 +344,45 @@ class ICWP_WPSF_FeatureHandler_License extends ICWP_WPSF_FeatureHandler_BaseWpsf
373
  * 4) the license hasn't expired
374
  * 5) the time since the last check hasn't expired
375
  * @return bool
 
376
  */
377
  public function hasValidWorkingLicense() {
378
- $oLic = $this->loadLicense();
379
- return ( $this->isKeyless() || $this->isLicenseKeyValidFormat() )
380
- && $oLic->isValid() && $this->isLicenseActive();
381
- }
382
-
383
- /**
384
- * @return bool
385
- */
386
- protected function isKeyless() {
387
- return (bool)$this->getDef( 'keyless' );
388
  }
389
 
390
  /**
391
- * Expires in 3 days.
392
  * @return bool
 
393
  */
394
  protected function isLastVerifiedExpired() {
395
- return ( Services::Request()->ts() - $this->loadLicense()->last_verified_at )
396
- > $this->getDef( 'lic_verify_expire_days' )*DAY_IN_SECONDS;
397
  }
398
 
399
  /**
400
  * @return bool
 
401
  */
402
  protected function isLastVerifiedGraceExpired() {
403
- $nGracePeriod = ( $this->getDef( 'lic_verify_expire_days' ) + $this->getDef( 'lic_verify_expire_grace_days' ) )
404
- *DAY_IN_SECONDS;
405
- return ( Services::Request()->ts() - $this->loadLicense()->last_verified_at ) > $nGracePeriod;
406
  }
407
 
408
  /**
409
  * @return bool
 
410
  */
411
  protected function isWithinVerifiedGraceExpired() {
412
- return $this->isLastVerifiedExpired() && !$this->isLastVerifiedGraceExpired();
413
  }
414
 
415
  /**
416
  * @param int $nAt
417
  * @return $this
 
418
  */
419
  protected function setLicenseLastCheckedAt( $nAt = null ) {
420
- $this->getOptions()->setOptAt( 'license_last_checked_at', $nAt );
421
  return $this;
422
  }
423
 
424
- /**
425
- * @param string $sKey
426
- * @return string|null
427
- */
428
- public function verifyLicenseKeyFormat( $sKey ) {
429
- $sCleanKey = null;
430
-
431
- $sKey = $this->cleanLicenseKey( $sKey );
432
- $bValid = !empty( $sKey ) && is_string( $sKey )
433
- && ( strlen( $sKey ) == $this->getDef( 'license_key_length' ) );
434
-
435
- if ( $bValid ) {
436
- switch ( $this->getDef( 'license_key_type' ) ) {
437
- case 'alphanumeric':
438
- default:
439
- if ( preg_match( '#[^a-z0-9]#i', $sKey ) === 0 ) {
440
- $sCleanKey = $sKey;
441
- }
442
- break;
443
- }
444
- }
445
-
446
- return $sCleanKey;
447
- }
448
-
449
- protected function cleanLicenseKey( $sKey ) {
450
-
451
- switch ( $this->getDef( 'license_key_type' ) ) {
452
- case 'alphanumeric':
453
- default:
454
- $sKey = preg_replace( '#[^a-z0-9]#i', '', $sKey );
455
- break;
456
- }
457
-
458
- return $sKey;
459
- }
460
-
461
- /**
462
- */
463
- protected function doPrePluginOptionsSave() {
464
- // clean the key.
465
- $sLicKey = $this->getLicenseKey();
466
- if ( strlen( $sLicKey ) > 0 ) {
467
- switch ( $this->getDef( 'license_key_type' ) ) {
468
- case 'alphanumeric':
469
- default:
470
- $this->setOpt( 'license_key', preg_replace( '#[^a-z0-9]#i', '', $sLicKey ) );
471
- break;
472
- }
473
- }
474
- }
475
-
476
- /**
477
- * @return int
478
- */
479
- public function getKeylessRequestAt() {
480
- return (int)$this->getOpt( 'keyless_request_at', 0 );
481
- }
482
-
483
- /**
484
- * @return string
485
- */
486
- public function getKeylessRequestHash() {
487
- return (string)$this->getOpt( 'keyless_request_hash', '' );
488
- }
489
-
490
- /**
491
- * @return bool
492
- */
493
- public function isKeylessHandshakeExpired() {
494
- return ( Services::Request()->ts() - $this->getKeylessRequestAt() )
495
- > $this->getDef( 'keyless_handshake_expire' );
496
- }
497
-
498
- /**
499
- * @param string $sHash
500
- * @return $this
501
- */
502
- public function setKeylessRequestHash( $sHash ) {
503
- return $this->setOpt( 'keyless_request_hash', $sHash );
504
- }
505
-
506
- /**
507
- * @param int|null $nTime
508
- * @return $this
509
- */
510
- public function setKeylessRequestAt( $nTime = null ) {
511
- $nTime = is_numeric( $nTime ) ? $nTime : Services::Request()->ts();
512
- return $this->setOpt( 'keyless_request_at', $nTime );
513
- }
514
-
515
- /**
516
- * @return bool
517
- */
518
- protected function isEnabledForUiSummary() {
519
- return $this->hasValidWorkingLicense();
520
- }
521
-
522
- public function buildInsightsVars() {
523
- $oWp = Services::WpGeneral();
524
- $oCon = $this->getCon();
525
- $oCarbon = Services::Request()->carbon();
526
-
527
- $oCurrent = $this->loadLicense();
528
-
529
- $nExpiresAt = $oCurrent->getExpiresAt();
530
- if ( $nExpiresAt > 0 && $nExpiresAt != PHP_INT_MAX ) {
531
- $sExpiresAt = $oCarbon->setTimestamp( $nExpiresAt )->diffForHumans()
532
- .sprintf( '<br/><small>%s</small>', $oWp->getTimeStampForDisplay( $nExpiresAt ) );
533
- }
534
- else {
535
- $sExpiresAt = 'n/a';
536
- }
537
-
538
- $nLastReqAt = $oCurrent->last_request_at;
539
- if ( empty( $nLastReqAt ) ) {
540
- $sChecked = __( 'Never', 'wp-simple-firewall' );
541
- }
542
- else {
543
- $sChecked = $oCarbon->setTimestamp( $nLastReqAt )->diffForHumans()
544
- .sprintf( '<br/><small>%s</small>', $oWp->getTimeStampForDisplay( $nLastReqAt ) );
545
- }
546
- $aLicenseTableVars = [
547
- 'product_name' => $this->getLicenseItemName(),
548
- 'license_active' => $this->hasValidWorkingLicense() ? __( 'Yes', 'wp-simple-firewall' ) : __( 'Not Active', 'wp-simple-firewall' ),
549
- 'license_expires' => $sExpiresAt,
550
- 'license_email' => $oCurrent->customer_email,
551
- 'last_checked' => $sChecked,
552
- 'last_errors' => $this->hasLastErrors() ? $this->getLastErrors() : ''
553
- ];
554
- if ( !$this->isKeyless() ) {
555
- $aLicenseTableVars[ 'license_key' ] = $this->hasLicenseKey() ? $this->getLicenseKey() : 'n/a';
556
- }
557
- return [
558
- 'vars' => [
559
- 'license_table' => $aLicenseTableVars,
560
- 'activation_url' => $oWp->getHomeUrl()
561
- ],
562
- 'inputs' => [
563
- 'license_key' => [
564
- 'name' => $oCon->prefixOption( 'license_key' ),
565
- 'maxlength' => $this->getDef( 'license_key_length' ),
566
- ]
567
- ],
568
- 'ajax' => [
569
- 'license_handling' => $this->getAjaxActionData( 'license_handling' ),
570
- 'connection_debug' => $this->getAjaxActionData( 'connection_debug' )
571
- ],
572
- 'aHrefs' => [
573
- 'shield_pro_url' => 'https://shsec.io/shieldpro',
574
- 'shield_pro_more_info_url' => 'https://shsec.io/shld1',
575
- 'iframe_url' => $this->getDef( 'landing_page_url' ),
576
- 'keyless_cp' => $this->getDef( 'keyless_cp' ),
577
- ],
578
- 'flags' => [
579
- 'show_key' => !$this->isKeyless(),
580
- 'has_license_key' => $this->isLicenseKeyValidFormat(),
581
- 'show_ads' => false,
582
- 'button_enabled_check' => true,
583
- 'button_enabled_remove' => $this->isLicenseKeyValidFormat(),
584
- 'show_standard_options' => false,
585
- 'show_alt_content' => true,
586
- 'is_pro' => $this->isPremium()
587
- ],
588
- 'strings' => $this->getStrings()->getDisplayStrings(),
589
- ];
590
- }
591
-
592
  /**
593
  * @return string
594
  */
1
  <?php
2
 
3
  use FernleafSystems\Wordpress\Plugin\Shield;
4
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\License;
5
  use FernleafSystems\Wordpress\Services\Services;
6
  use FernleafSystems\Wordpress\Services\Utilities;
7
 
8
  class ICWP_WPSF_FeatureHandler_License extends ICWP_WPSF_FeatureHandler_BaseWpsf {
9
 
10
+ /**
11
+ * @var License\Lib\LicenseHandler
12
+ */
13
+ private $oLicHandler;
14
+
15
+ /**
16
+ * @var License\Lib\WpHashes\ApiTokenManager
17
+ */
18
+ private $oWpHashesTokenManager;
19
+
20
+ /**
21
+ * @return License\Lib\LicenseHandler
22
+ */
23
+ public function getLicenseHandler() {
24
+ if ( !isset( $this->oLicHandler ) ) {
25
+ $this->oLicHandler = ( new Shield\Modules\License\Lib\LicenseHandler() )->setMod( $this );
26
+ }
27
+ return $this->oLicHandler;
28
+ }
29
+
30
+ /**
31
+ * @return License\Lib\WpHashes\ApiTokenManager
32
+ */
33
+ public function getWpHashesTokenManager() {
34
+ if ( !isset( $this->oWpHashesTokenManager ) ) {
35
+ $this->oWpHashesTokenManager = ( new Shield\Modules\License\Lib\WpHashes\ApiTokenManager() )->setMod( $this );
36
+ }
37
+ return $this->oWpHashesTokenManager;
38
+ }
39
+
40
+ /**
41
+ * @return bool
42
+ */
43
+ protected function isEnabledForUiSummary() {
44
+ return $this->getLicenseHandler()->hasValidWorkingLicense();
45
+ }
46
+
47
+ public function buildInsightsVars() {
48
+ $oWp = Services::WpGeneral();
49
+ $oCon = $this->getCon();
50
+ $oCarbon = Services::Request()->carbon();
51
+
52
+ $oCurrent = $this->getLicenseHandler()->getLicense();
53
+
54
+ $nExpiresAt = $oCurrent->getExpiresAt();
55
+ if ( $nExpiresAt > 0 && $nExpiresAt != PHP_INT_MAX ) {
56
+ $sExpiresAt = $oCarbon->setTimestamp( $nExpiresAt )->diffForHumans()
57
+ .sprintf( '<br/><small>%s</small>', $oWp->getTimeStampForDisplay( $nExpiresAt ) );
58
+ }
59
+ else {
60
+ $sExpiresAt = 'n/a';
61
+ }
62
+
63
+ $nLastReqAt = $oCurrent->last_request_at;
64
+ if ( empty( $nLastReqAt ) ) {
65
+ $sChecked = __( 'Never', 'wp-simple-firewall' );
66
+ }
67
+ else {
68
+ $sChecked = $oCarbon->setTimestamp( $nLastReqAt )->diffForHumans()
69
+ .sprintf( '<br/><small>%s</small>', $oWp->getTimeStampForDisplay( $nLastReqAt ) );
70
+ }
71
+ $aLicenseTableVars = [
72
+ 'product_name' => $oCurrent->is_central ?
73
+ $this->getDef( 'license_item_name_sc' ) :
74
+ $this->getDef( 'license_item_name' ),
75
+ 'license_active' => $this->getLicenseHandler()->hasValidWorkingLicense() ?
76
+ __( '&#10004;', 'wp-simple-firewall' ) : __( '&#10006;', 'wp-simple-firewall' ),
77
+ 'license_expires' => $sExpiresAt,
78
+ 'license_email' => $oCurrent->customer_email,
79
+ 'last_checked' => $sChecked,
80
+ 'last_errors' => $this->hasLastErrors() ? $this->getLastErrors( true ) : '',
81
+ 'wphashes_token' => $this->getWpHashesTokenManager()->hasToken() ?
82
+ __( '&#10004;', 'wp-simple-firewall' ) : __( '&#10006;', 'wp-simple-firewall' ),
83
+ 'installation_id' => $oCon->getSiteInstallationId(),
84
+ ];
85
+ return [
86
+ 'vars' => [
87
+ 'license_table' => $aLicenseTableVars,
88
+ 'activation_url' => $oWp->getHomeUrl(),
89
+ 'error' => $this->getLastErrors( true )
90
+ ],
91
+ 'inputs' => [
92
+ 'license_key' => [
93
+ 'name' => $oCon->prefixOption( 'license_key' ),
94
+ 'maxlength' => $this->getDef( 'license_key_length' ),
95
+ ]
96
+ ],
97
+ 'ajax' => [
98
+ 'license_handling' => $this->getAjaxActionData( 'license_handling' ),
99
+ 'connection_debug' => $this->getAjaxActionData( 'connection_debug' )
100
+ ],
101
+ 'aHrefs' => [
102
+ 'shield_pro_url' => 'https://shsec.io/shieldpro',
103
+ 'shield_pro_more_info_url' => 'https://shsec.io/shld1',
104
+ 'iframe_url' => $this->getDef( 'landing_page_url' ),
105
+ 'keyless_cp' => $this->getDef( 'keyless_cp' ),
106
+ ],
107
+ 'flags' => [
108
+ 'show_ads' => false,
109
+ 'button_enabled_check' => true,
110
+ 'show_standard_options' => false,
111
+ 'show_alt_content' => true,
112
+ 'is_pro' => $this->isPremium(),
113
+ 'has_error' => $this->hasLastErrors()
114
+ ],
115
+ 'strings' => $this->getStrings()->getDisplayStrings(),
116
+ ];
117
+ }
118
+
119
  protected function redirectToInsightsSubPage() {
120
  Services::Response()->redirect(
121
  $this->getCon()->getModule_Insights()->getUrl_AdminPage(),
123
  );
124
  }
125
 
126
+ public function runHourlyCron() {
127
+ $this->getWpHashesTokenManager()->getToken();
128
+ }
129
+
130
  protected function setupCustomHooks() {
131
+ add_action( 'wp_loaded', [ $this, 'onWpLoaded' ] );
132
+ }
133
+
134
+ /**
135
+ * @deprecated 8.6.2
136
+ */
137
+ protected function updateHandler() {
138
+ $this->getWpHashesTokenManager()->getToken();
139
+ }
140
+
141
+ public function onWpLoaded() {
142
+ $this->getWpHashesTokenManager()->run();
143
  }
144
 
145
  /**
150
  }
151
 
152
  public function onPluginShutdown() {
153
+ try {
154
+ $this->getLicenseHandler()->verify( false );
155
+ }
156
+ catch ( Exception $oE ) {
157
+ }
158
  parent::onPluginShutdown();
159
  }
160
 
161
  /**
162
  * @return Shield\License\EddLicenseVO
163
+ * @deprecated 8.6.2
164
  */
165
  protected function loadLicense() {
166
+ return $this->getLicenseHandler()->getLicense();
167
  }
168
 
169
  /**
170
  * @return array
171
+ * @deprecated 8.6.2
172
  */
173
  protected function getLicenseData() {
174
  $aData = $this->getOpt( 'license_data', [] );
177
 
178
  /**
179
  * @return $this
180
+ * @deprecated 8.6.2
181
  */
182
  public function clearLicenseData() {
183
  return $this->setOpt( 'license_data', [] );
186
  /**
187
  * @param Utilities\Licenses\EddLicenseVO $oLic
188
  * @return $this
189
+ * @deprecated 8.6.2
190
  */
191
  protected function setLicenseData( $oLic ) {
192
  return $this->setOpt( 'license_data', $oLic->getRawDataAsArray() );
194
 
195
  /**
196
  * @param string $sDeactivatedReason
197
+ * @deprecated 8.6.2
198
  */
199
  public function deactivate( $sDeactivatedReason = '' ) {
 
 
 
 
 
 
 
 
 
 
200
  }
201
 
202
  /**
204
  * for a currently valid license.
205
  * @param bool $bForceCheck
206
  * @return $this
207
+ * @deprecated 8.6.2
208
  */
209
  public function verifyLicense( $bForceCheck = true ) {
210
+ try {
211
+ $this->getLicenseHandler()->verify( $bForceCheck );
212
+ }
213
+ catch ( Exception $oE ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
  }
 
215
  return $this;
216
  }
217
 
218
  /**
219
  * @return bool
220
+ * @deprecated 8.6.2
221
  */
222
  private function isLicenseCheckRequired() {
223
+ return false;
 
 
 
 
224
  }
225
 
226
  /**
227
  * @return bool
228
+ * @deprecated 8.6.2
229
  */
230
  private function canLicenseCheck() {
231
+ return false;
 
232
  }
233
 
234
  /**
235
  * @return bool
236
+ * @deprecated 8.6.2
237
  */
238
  private function canLicenseCheck_FileFlag() {
239
+ return false;
 
 
 
240
  }
241
 
242
  /**
243
  * @return $this
244
+ * @deprecated 8.6.2
245
  */
246
  private function touchLicenseCheckFileFlag() {
247
  Services::WpFs()->touch( $this->getCon()->getPath_Flags( 'license_check' ) );
250
 
251
  /**
252
  * @return bool
253
+ * @deprecated 8.6.2
254
  */
255
  protected function isLicenseMaybeExpiring() {
256
+ return false;
 
 
 
 
257
  }
258
 
259
  /**
260
  * @return $this
261
+ * @deprecated 8.6.2
262
  */
263
  protected function activateLicense() {
 
 
 
264
  return $this;
265
  }
266
 
267
  /**
268
+ * @deprecated 8.6.2
269
  */
270
  protected function sendLicenseWarningEmail() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
271
  }
272
 
273
  /**
274
+ * @deprecated 8.6.2
275
  */
276
  private function sendLicenseDeactivatedEmail() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
  }
278
 
279
  /**
280
  * @return int
281
+ * @deprecated 8.6.2
282
  */
283
  protected function getLicenseActivatedAt() {
284
  return $this->getOpt( 'license_activated_at' );
286
 
287
  /**
288
  * @return int
289
+ * @deprecated 8.6.2
290
  */
291
  protected function getLicenseDeactivatedAt() {
292
  return $this->getOpt( 'license_deactivated_at' );
294
 
295
  /**
296
  * @return string
297
+ * @deprecated 8.6.2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
298
  */
299
  public function getLicenseItemName() {
300
+ return $this->getLicenseHandler()->getLicense()->is_central ?
301
  $this->getDef( 'license_item_name_sc' ) :
302
  $this->getDef( 'license_item_name' );
303
  }
304
 
 
 
 
 
 
 
 
305
  /**
306
  * @return int
307
+ * @deprecated 8.6.2
308
  */
309
  protected function getLicenseLastCheckedAt() {
310
  return $this->getOpt( 'license_last_checked_at' );
313
  /**
314
  * @param int $nTimePeriod
315
  * @return bool
316
+ * @deprecated 8.6.2
317
  */
318
  private function getIsLicenseNotCheckedFor( $nTimePeriod ) {
319
+ return false;
320
  }
321
 
322
  /**
323
  * @return int
324
+ * @deprecated 8.6.2
325
  */
326
  public function getLicenseNotCheckedForInterval() {
327
+ return 0;
328
  }
329
 
330
  /**
331
  * @return bool
332
+ * @deprecated 8.6.2
333
  */
334
  public function isLicenseActive() {
335
+ return $this->getLicenseHandler()->isActive();
 
 
 
 
 
 
 
 
336
  }
337
 
338
  /**
344
  * 4) the license hasn't expired
345
  * 5) the time since the last check hasn't expired
346
  * @return bool
347
+ * @deprecated 8.6.2
348
  */
349
  public function hasValidWorkingLicense() {
350
+ return $this->getLicenseHandler()->hasValidWorkingLicense();
 
 
 
 
 
 
 
 
 
351
  }
352
 
353
  /**
 
354
  * @return bool
355
+ * @deprecated 8.6.2
356
  */
357
  protected function isLastVerifiedExpired() {
358
+ return false;
 
359
  }
360
 
361
  /**
362
  * @return bool
363
+ * @deprecated 8.6.2
364
  */
365
  protected function isLastVerifiedGraceExpired() {
366
+ return false;
 
 
367
  }
368
 
369
  /**
370
  * @return bool
371
+ * @deprecated 8.6.2
372
  */
373
  protected function isWithinVerifiedGraceExpired() {
374
+ return false;
375
  }
376
 
377
  /**
378
  * @param int $nAt
379
  * @return $this
380
+ * @deprecated 8.6.2
381
  */
382
  protected function setLicenseLastCheckedAt( $nAt = null ) {
 
383
  return $this;
384
  }
385
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
386
  /**
387
  * @return string
388
  */
src/features/login_protect.php CHANGED
@@ -1,12 +1,19 @@
1
  <?php
2
 
3
  use FernleafSystems\Wordpress\Plugin\Shield;
 
4
  use FernleafSystems\Wordpress\Services\Services;
5
 
6
  class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_BaseWpsf {
7
 
 
 
 
 
 
8
  /**
9
  * @return bool
 
10
  */
11
  public function getIfUseLoginIntentPage() {
12
  return $this->isOpt( 'use_login_intent_page', true );
@@ -41,9 +48,10 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
41
  }
42
 
43
  /**
 
44
  */
45
- public function handleModRequest() {
46
- switch ( Services::Request()->query( 'exec' ) ) {
47
  case 'email_send_verify':
48
  $this->processEmailSendVerify();
49
  break;
@@ -161,7 +169,7 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
161
  * @param bool $bAsOptDefaults
162
  * @return array
163
  */
164
- protected function getOptEmailTwoFactorRolesDefaults( $bAsOptDefaults = true ) {
165
  $aTwoAuthRoles = [
166
  'type' => 'multiple_select',
167
  0 => __( 'Subscribers', 'wp-simple-firewall' ),
@@ -227,7 +235,7 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
227
  }
228
 
229
  /**
230
- * @param WP_User $oUser
231
  * @return bool
232
  */
233
  public function canUserMfaSkip( $oUser ) {
@@ -294,7 +302,9 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
294
  }
295
 
296
  /**
297
- * @return int
 
 
298
  */
299
  public function getMfaSkip() {
300
  return (int)$this->getOpt( 'mfa_skip', 0 );
@@ -314,6 +324,7 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
314
 
315
  /**
316
  * @return bool
 
317
  */
318
  public function isEmailAuthenticationOptionOn() {
319
  return $this->isOpt( 'enable_email_authentication', 'Y' );
@@ -322,6 +333,7 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
322
  /**
323
  * Also considers whether email sending ability has been verified
324
  * @return bool
 
325
  */
326
  public function isEmailAuthenticationActive() {
327
  return $this->getIfCanSendEmailVerified() && $this->isEmailAuthenticationOptionOn();
@@ -329,6 +341,7 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
329
 
330
  /**
331
  * @return bool
 
332
  */
333
  public function isEnabledBackupCodes() {
334
  return $this->isPremium() && $this->isOpt( 'allow_backupcodes', 'Y' );
@@ -336,6 +349,7 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
336
 
337
  /**
338
  * @return bool
 
339
  */
340
  public function isEnabledGoogleAuthenticator() {
341
  return $this->isOpt( 'enable_google_authenticator', 'Y' );
@@ -350,6 +364,7 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
350
 
351
  /**
352
  * @return int
 
353
  */
354
  public function getCanSendEmailVerifiedAt() {
355
  return $this->getOpt( 'email_can_send_verified_at' );
@@ -357,6 +372,7 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
357
 
358
  /**
359
  * @return bool
 
360
  */
361
  public function getIfCanSendEmailVerified() {
362
  return $this->getCanSendEmailVerifiedAt() > 0;
@@ -382,8 +398,20 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
382
  return is_array( $aLocs ) ? $aLocs : (array)$this->getOptions()->getOptDefault( 'bot_protection_locations' );
383
  }
384
 
 
 
 
 
 
 
 
 
 
 
 
385
  /**
386
  * @return bool
 
387
  */
388
  public function isChainedAuth() {
389
  return $this->isOpt( 'enable_chained_authentication', 'Y' );
@@ -402,14 +430,7 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
402
  * @return $this
403
  */
404
  public function setIfCanSendEmail( $bCan ) {
405
- $nCurrentDateAt = $this->getCanSendEmailVerifiedAt();
406
- if ( $bCan ) {
407
- $nDateAt = ( $nCurrentDateAt <= 0 ) ? Services::Request()->ts() : $nCurrentDateAt;
408
- }
409
- else {
410
- $nDateAt = 0;
411
- }
412
- return $this->setOpt( 'email_can_send_verified_at', $nDateAt );
413
  }
414
 
415
  /**
@@ -518,6 +539,7 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
518
 
519
  /**
520
  * @return bool
 
521
  */
522
  public function isYubikeyActive() {
523
  return $this->isOpt( 'enable_yubikey', 'Y' ) && $this->isYubikeyConfigReady();
@@ -525,6 +547,7 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
525
 
526
  /**
527
  * @return bool
 
528
  */
529
  private function isYubikeyConfigReady() {
530
  $sAppId = $this->getOpt( 'yubikey_app_id' );
1
  <?php
2
 
3
  use FernleafSystems\Wordpress\Plugin\Shield;
4
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
5
  use FernleafSystems\Wordpress\Services\Services;
6
 
7
  class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_BaseWpsf {
8
 
9
+ /**
10
+ * @var LoginGuard\Lib\TwoFactor\MfaController
11
+ */
12
+ private $oLoginIntentController;
13
+
14
  /**
15
  * @return bool
16
+ * @deprecated 8.6.0
17
  */
18
  public function getIfUseLoginIntentPage() {
19
  return $this->isOpt( 'use_login_intent_page', true );
48
  }
49
 
50
  /**
51
+ * @inheritDoc
52
  */
53
+ protected function handleModAction( $sAction ) {
54
+ switch ( $sAction ) {
55
  case 'email_send_verify':
56
  $this->processEmailSendVerify();
57
  break;
169
  * @param bool $bAsOptDefaults
170
  * @return array
171
  */
172
+ public function getOptEmailTwoFactorRolesDefaults( $bAsOptDefaults = true ) {
173
  $aTwoAuthRoles = [
174
  'type' => 'multiple_select',
175
  0 => __( 'Subscribers', 'wp-simple-firewall' ),
235
  }
236
 
237
  /**
238
+ * @param \WP_User $oUser
239
  * @return bool
240
  */
241
  public function canUserMfaSkip( $oUser ) {
302
  }
303
 
304
  /**
305
+ * NOTE: DO NOT REPLACE WITH OPTIONS USE AS THIS RETURNS DAYS
306
+ * @return int - days
307
+ * @deprecated 8.6.0
308
  */
309
  public function getMfaSkip() {
310
  return (int)$this->getOpt( 'mfa_skip', 0 );
324
 
325
  /**
326
  * @return bool
327
+ * @deprecated 8.6.0
328
  */
329
  public function isEmailAuthenticationOptionOn() {
330
  return $this->isOpt( 'enable_email_authentication', 'Y' );
333
  /**
334
  * Also considers whether email sending ability has been verified
335
  * @return bool
336
+ * @deprecated 8.6.0
337
  */
338
  public function isEmailAuthenticationActive() {
339
  return $this->getIfCanSendEmailVerified() && $this->isEmailAuthenticationOptionOn();
341
 
342
  /**
343
  * @return bool
344
+ * @deprecated 8.6.0
345
  */
346
  public function isEnabledBackupCodes() {
347
  return $this->isPremium() && $this->isOpt( 'allow_backupcodes', 'Y' );
349
 
350
  /**
351
  * @return bool
352
+ * @deprecated 8.6.0
353
  */
354
  public function isEnabledGoogleAuthenticator() {
355
  return $this->isOpt( 'enable_google_authenticator', 'Y' );
364
 
365
  /**
366
  * @return int
367
+ * @deprecated 8.6.0
368
  */
369
  public function getCanSendEmailVerifiedAt() {
370
  return $this->getOpt( 'email_can_send_verified_at' );
372
 
373
  /**
374
  * @return bool
375
+ * @deprecated 8.6.0
376
  */
377
  public function getIfCanSendEmailVerified() {
378
  return $this->getCanSendEmailVerifiedAt() > 0;
398
  return is_array( $aLocs ) ? $aLocs : (array)$this->getOptions()->getOptDefault( 'bot_protection_locations' );
399
  }
400
 
401
+ /**
402
+ * @return LoginGuard\Lib\TwoFactor\MfaController
403
+ */
404
+ public function getLoginIntentController() {
405
+ if ( !isset( $this->oLoginIntentController ) ) {
406
+ $this->oLoginIntentController = ( new LoginGuard\Lib\TwoFactor\MfaController() )
407
+ ->setMod( $this );
408
+ }
409
+ return $this->oLoginIntentController;
410
+ }
411
+
412
  /**
413
  * @return bool
414
+ * @deprecated 8.6.0
415
  */
416
  public function isChainedAuth() {
417
  return $this->isOpt( 'enable_chained_authentication', 'Y' );
430
  * @return $this
431
  */
432
  public function setIfCanSendEmail( $bCan ) {
433
+ return $this->setOpt( 'email_can_send_verified_at', $bCan ? Services::Request()->ts() : 0 );
 
 
 
 
 
 
 
434
  }
435
 
436
  /**
539
 
540
  /**
541
  * @return bool
542
+ * @deprecated 8.6.0
543
  */
544
  public function isYubikeyActive() {
545
  return $this->isOpt( 'enable_yubikey', 'Y' ) && $this->isYubikeyConfigReady();
547
 
548
  /**
549
  * @return bool
550
+ * @deprecated 8.6.0
551
  */
552
  private function isYubikeyConfigReady() {
553
  $sAppId = $this->getOpt( 'yubikey_app_id' );
src/features/plugin.php CHANGED
@@ -75,12 +75,6 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
75
  && ( Services::Request()->cookie( $this->getCookieIdBadgeState() ) != 'closed' );
76
  }
77
 
78
- public function runHourlyCron() {
79
- ( new Plugin\Lib\WpHashesTokenManager() )
80
- ->setMod( $this )
81
- ->getToken();
82
- }
83
-
84
  /**
85
  * @param bool $bDisplay
86
  * @return $this
@@ -118,9 +112,10 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
118
  }
119
 
120
  /**
 
121
  */
122
- public function handleModRequest() {
123
- switch ( Services::Request()->request( 'exec' ) ) {
124
 
125
  case 'export_file_download':
126
  header( 'Set-Cookie: fileDownload=true; path=/' );
@@ -178,15 +173,6 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
178
  return $aConfig;
179
  }
180
 
181
- /**
182
- * @param bool $bGloballyDisabled
183
- * @return bool
184
- * @deprecated 8.5.7
185
- */
186
- public function filter_IsPluginGloballyDisabled( $bGloballyDisabled ) {
187
- return $bGloballyDisabled || !$this->isOpt( 'global_enable_plugin_features', 'Y' );
188
- }
189
-
190
  /**
191
  * @return bool
192
  */
@@ -704,127 +690,10 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
704
  return 'Plugin';
705
  }
706
 
707
- /**
708
- * @return string
709
- * @deprecated 8.5.2
710
- */
711
- public function getVisitorAddressSource() {
712
- return $this->getOptions()->getOpt( 'visitor_address_source' );
713
- }
714
-
715
- /**
716
- * @return string
717
- * @deprecated 8.5.2
718
- */
719
- public function isVisitorAddressSourceAutoDetect() {
720
- return $this->getVisitorAddressSource() == 'AUTO_DETECT_IP';
721
- }
722
-
723
  /**
724
  * @return string
725
  */
726
  public function getSurveyEmail() {
727
  return base64_decode( $this->getDef( 'survey_email' ) );
728
  }
729
-
730
- /**
731
- * @return bool
732
- * @deprecated 8.5.2
733
- */
734
- public function hasImportExportMasterImportUrl() {
735
- /** @var Plugin\Options $oOpts */
736
- $oOpts = $this->getOptions();
737
- return $oOpts->hasImportExportMasterImportUrl();
738
- }
739
-
740
- /**
741
- * @return int
742
- * @deprecated 8.5.2
743
- */
744
- public function getImportExportHandshakeExpiresAt() {
745
- return $this->getOpt( 'importexport_handshake_expires_at', Services::Request()->ts() );
746
- }
747
-
748
- /**
749
- * @return string
750
- * @deprecated 8.5.2
751
- */
752
- public function getImportExportMasterImportUrl() {
753
- return $this->getOpt( 'importexport_masterurl', '' );
754
- }
755
-
756
- /**
757
- * @return bool
758
- * @deprecated 8.5.2
759
- */
760
- public function isImportExportPermitted() {
761
- return $this->isPremium() && $this->isOpt( 'importexport_enable', 'Y' );
762
- }
763
-
764
- /**
765
- * @return bool
766
- * @deprecated 8.5.2
767
- */
768
- public function readyToSendTrackingData() {
769
- return Services::Request()
770
- ->carbon()
771
- ->subWeek()->timestamp > (int)$this->getOptions()->getOpt( 'tracking_last_sent_at', 0 );
772
- }
773
-
774
- /**
775
- * @return bool
776
- * @deprecated 8.5.2
777
- */
778
- public function isTrackingEnabled() {
779
- return $this->isOpt( 'enable_tracking', 'Y' );
780
- }
781
-
782
- /**
783
- * @return bool
784
- * @deprecated 8.5.2
785
- */
786
- public function isTrackingPermissionSet() {
787
- return !$this->isOpt( 'tracking_permission_set_at', 0 );
788
- }
789
-
790
- /**
791
- * @return $this
792
- * @deprecated 8.5.2
793
- */
794
- public function setTrackingLastSentAt() {
795
- return $this->setOpt( 'tracking_last_sent_at', Services::Request()->ts() );
796
- }
797
-
798
- /**
799
- * @return int
800
- * @deprecated 8.5.2
801
- */
802
- public function getTrackingLastSentAt() {
803
- return (int)max( 0, $this->getOptions()->getOpt( 'tracking_last_sent_at', 0 ) );
804
- }
805
-
806
- /**
807
- * @return int
808
- * @deprecated 8.5.2
809
- */
810
- public function getActivatedAt() {
811
- return (int)$this->getOpt( 'activated_at', 0 );
812
- }
813
-
814
- /**
815
- * @return string[]
816
- * @deprecated 8.5.1
817
- */
818
- public function getMyServerIPs() {
819
- return Services::IP()->getServerPublicIPs();
820
- }
821
-
822
- /**
823
- * @return string
824
- * @deprecated 8.5
825
- */
826
- public function getMyServerIp() {
827
- $aIPs = $this->getMyServerIPs();
828
- return array_shift( $aIPs );
829
- }
830
  }
75
  && ( Services::Request()->cookie( $this->getCookieIdBadgeState() ) != 'closed' );
76
  }
77
 
 
 
 
 
 
 
78
  /**
79
  * @param bool $bDisplay
80
  * @return $this
112
  }
113
 
114
  /**
115
+ * @inheritDoc
116
  */
117
+ protected function handleModAction( $sAction ) {
118
+ switch ( $sAction ) {
119
 
120
  case 'export_file_download':
121
  header( 'Set-Cookie: fileDownload=true; path=/' );
173
  return $aConfig;
174
  }
175
 
 
 
 
 
 
 
 
 
 
176
  /**
177
  * @return bool
178
  */
690
  return 'Plugin';
691
  }
692
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
693
  /**
694
  * @return string
695
  */
696
  public function getSurveyEmail() {
697
  return base64_decode( $this->getDef( 'survey_email' ) );
698
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
699
  }
src/features/user_management.php CHANGED
@@ -52,6 +52,21 @@ class ICWP_WPSF_FeatureHandler_UserManagement extends \ICWP_WPSF_FeatureHandler_
52
  $oOpts->getSuspendAutoIdleUserRoles()
53
  ) ) )
54
  );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  }
56
 
57
  /**
@@ -75,37 +90,6 @@ class ICWP_WPSF_FeatureHandler_UserManagement extends \ICWP_WPSF_FeatureHandler_
75
  return $this->isPremium() && $this->isOpt( 'enable_user_login_email_notification', 'Y' );
76
  }
77
 
78
- /**
79
- * @return int days
80
- */
81
- public function getPassExpireDays() {
82
- return ( $this->isPasswordPoliciesEnabled() && $this->isPremium() ) ? (int)$this->getOpt( 'pass_expire' ) : 0;
83
- }
84
-
85
- /**
86
- * @return int seconds
87
- * @deprecated 8.5.2
88
- */
89
- public function getPassExpireTimeout() {
90
- return $this->getPassExpireDays()*DAY_IN_SECONDS;
91
- }
92
-
93
- /**
94
- * @return int
95
- * @deprecated 8.5.2
96
- */
97
- public function getPassMinLength() {
98
- return $this->isPremium() ? (int)$this->getOpt( 'pass_min_length' ) : 0;
99
- }
100
-
101
- /**
102
- * @return int
103
- * @deprecated 8.5.2
104
- */
105
- public function getPassMinStrength() {
106
- return $this->isPremium() ? (int)$this->getOpt( 'pass_min_strength' ) : 0;
107
- }
108
-
109
  /**
110
  * @param int $nStrength
111
  * @return int
@@ -121,94 +105,6 @@ class ICWP_WPSF_FeatureHandler_UserManagement extends \ICWP_WPSF_FeatureHandler_
121
  return $aMap[ max( 0, min( 4, $nStrength ) ) ];
122
  }
123
 
124
- /**
125
- * @return bool
126
- * @deprecated 8.5.2
127
- */
128
- public function isPasswordPoliciesEnabled() {
129
- return $this->isOpt( 'enable_password_policies', 'Y' )
130
- && $this->getOptions()->isOptReqsMet( 'enable_password_policies' );
131
- }
132
-
133
- /**
134
- * @return bool
135
- * @deprecated 8.5.2
136
- */
137
- public function isPassForceUpdateExisting() {
138
- return $this->isOpt( 'pass_force_existing', 'Y' );
139
- }
140
-
141
- /**
142
- * @return bool
143
- * @deprecated 8.5.2
144
- */
145
- public function isPassExpirationEnabled() {
146
- return $this->isPasswordPoliciesEnabled() && ( $this->getPassExpireTimeout() > 0 );
147
- }
148
-
149
- /**
150
- * @return bool
151
- * @deprecated 8.5.2
152
- */
153
- public function isPassPreventPwned() {
154
- return $this->isOpt( 'pass_prevent_pwned', 'Y' );
155
- }
156
-
157
- /**
158
- * @return bool
159
- * @deprecated 8.5.2
160
- */
161
- public function isSuspendEnabled() {
162
- return $this->isPremium() &&
163
- ( $this->isSuspendManualEnabled()
164
- || $this->isSuspendAutoIdleEnabled()
165
- || $this->isSuspendAutoPasswordEnabled()
166
- );
167
- }
168
-
169
- /**
170
- * @return bool
171
- * @deprecated 8.5.2
172
- */
173
- public function isSuspendManualEnabled() {
174
- return $this->isOpt( 'manual_suspend', 'Y' );
175
- }
176
-
177
- /**
178
- * @return int
179
- * @deprecated 8.5.2
180
- */
181
- public function getSuspendAutoIdleTime() {
182
- return $this->getOpt( 'auto_idle_days', 0 )*DAY_IN_SECONDS;
183
- }
184
-
185
- /**
186
- * @return array
187
- * @deprecated 8.5.2
188
- */
189
- public function getSuspendAutoIdleUserRoles() {
190
- $aRoles = $this->getOpt( 'auto_idle_roles', [] );
191
- return is_array( $aRoles ) ? $aRoles : [];
192
- }
193
-
194
- /**
195
- * @return bool
196
- * @deprecated 8.5.2
197
- */
198
- public function isSuspendAutoIdleEnabled() {
199
- return ( $this->getSuspendAutoIdleTime() > 0 )
200
- && ( count( $this->getSuspendAutoIdleUserRoles() ) > 0 );
201
- }
202
-
203
- /**
204
- * @return bool
205
- * @deprecated 8.5.2
206
- */
207
- public function isSuspendAutoPasswordEnabled() {
208
- return $this->isOpt( 'auto_password', 'Y' )
209
- && $this->isPasswordPoliciesEnabled() && $this->getPassExpireTimeout();
210
- }
211
-
212
  /**
213
  * @param int $nUserId
214
  * @param bool $bAdd - set true to add, false to remove
@@ -268,6 +164,8 @@ class ICWP_WPSF_FeatureHandler_UserManagement extends \ICWP_WPSF_FeatureHandler_
268
  * @return array
269
  */
270
  public function addInsightsNoticeData( $aAllNotices ) {
 
 
271
 
272
  $aNotices = [
273
  'title' => __( 'Users', 'wp-simple-firewall' ),
@@ -287,7 +185,7 @@ class ICWP_WPSF_FeatureHandler_UserManagement extends \ICWP_WPSF_FeatureHandler_
287
  }
288
 
289
  {//password policies
290
- if ( !$this->isPasswordPoliciesEnabled() ) {
291
  $aNotices[ 'messages' ][ 'password' ] = [
292
  'title' => __( 'Password Policies', 'wp-simple-firewall' ),
293
  'message' => __( "Strong password policies are not enforced.", 'wp-simple-firewall' ),
@@ -347,9 +245,9 @@ class ICWP_WPSF_FeatureHandler_UserManagement extends \ICWP_WPSF_FeatureHandler_
347
  'href' => $this->getUrl_DirectLinkToOption( 'session_lock_location' ),
348
  ];
349
 
350
- $bPolicies = $this->isPasswordPoliciesEnabled();
351
 
352
- $bPwned = $bPolicies && $this->isPassPreventPwned();
353
  $aThis[ 'key_opts' ][ 'pwned' ] = [
354
  'name' => __( 'Pwned Passwords', 'wp-simple-firewall' ),
355
  'enabled' => $bPwned,
@@ -382,52 +280,4 @@ class ICWP_WPSF_FeatureHandler_UserManagement extends \ICWP_WPSF_FeatureHandler_
382
  protected function getNamespaceBase() {
383
  return 'UserManagement';
384
  }
385
-
386
- /**
387
- * @return int
388
- * @deprecated 8.5
389
- */
390
- public function getMaxSessionTime() {
391
- /** @var UserManagement\Options $oOpts */
392
- $oOpts = $this->getOptions();
393
- return $oOpts->getMaxSessionTime();
394
- }
395
-
396
- /**
397
- * @return int
398
- * @deprecated 8.5
399
- */
400
- public function getIdleTimeoutInterval() {
401
- return $this->getOpt( 'session_idle_timeout_interval' )*HOUR_IN_SECONDS;
402
- }
403
-
404
- /**
405
- * @return bool
406
- * @deprecated 8.5
407
- */
408
- public function hasMaxSessionTimeout() {
409
- /** @var UserManagement\Options $oOpts */
410
- $oOpts = $this->getOptions();
411
- return $oOpts->hasMaxSessionTimeout();
412
- }
413
-
414
- /**
415
- * @return bool
416
- * @deprecated 8.5
417
- */
418
- public function hasSessionIdleTimeout() {
419
- /** @var UserManagement\Options $oOpts */
420
- $oOpts = $this->getOptions();
421
- return $oOpts->hasSessionIdleTimeout();
422
- }
423
-
424
- /**
425
- * @return bool
426
- * @deprecated 8.5
427
- */
428
- public function isLockToIp() {
429
- /** @var UserManagement\Options $oOpts */
430
- $oOpts = $this->getOptions();
431
- return $oOpts->isLockToIp();
432
- }
433
  }
52
  $oOpts->getSuspendAutoIdleUserRoles()
53
  ) ) )
54
  );
55
+
56
+ {
57
+ $aChecks = $oOpts->getEmailValidationChecks();
58
+ if ( !in_array( 'syntax', $aChecks ) ) {
59
+ $aChecks[] = 'syntax';
60
+ }
61
+ // fill in dependencies
62
+ if ( in_array( 'nondisposable', $aChecks ) && !in_array( 'mx', $aChecks ) ) {
63
+ $aChecks[] = 'mx';
64
+ }
65
+ if ( in_array( 'mx', $aChecks ) && !in_array( 'domain', $aChecks ) ) {
66
+ $aChecks[] = 'domain';
67
+ }
68
+ $oOpts->setOpt( 'email_checks', $aChecks );
69
+ }
70
  }
71
 
72
  /**
90
  return $this->isPremium() && $this->isOpt( 'enable_user_login_email_notification', 'Y' );
91
  }
92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  /**
94
  * @param int $nStrength
95
  * @return int
105
  return $aMap[ max( 0, min( 4, $nStrength ) ) ];
106
  }
107
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  /**
109
  * @param int $nUserId
110
  * @param bool $bAdd - set true to add, false to remove
164
  * @return array
165
  */
166
  public function addInsightsNoticeData( $aAllNotices ) {
167
+ /** @var UserManagement\Options $oOpts */
168
+ $oOpts = $this->getOptions();
169
 
170
  $aNotices = [
171
  'title' => __( 'Users', 'wp-simple-firewall' ),
185
  }
186
 
187
  {//password policies
188
+ if ( !$oOpts->isPasswordPoliciesEnabled() ) {
189
  $aNotices[ 'messages' ][ 'password' ] = [
190
  'title' => __( 'Password Policies', 'wp-simple-firewall' ),
191
  'message' => __( "Strong password policies are not enforced.", 'wp-simple-firewall' ),
245
  'href' => $this->getUrl_DirectLinkToOption( 'session_lock_location' ),
246
  ];
247
 
248
+ $bPolicies = $oOpts->isPasswordPoliciesEnabled();
249
 
250
+ $bPwned = $bPolicies && $oOpts->isPassPreventPwned();
251
  $aThis[ 'key_opts' ][ 'pwned' ] = [
252
  'name' => __( 'Pwned Passwords', 'wp-simple-firewall' ),
253
  'enabled' => $bPwned,
280
  protected function getNamespaceBase() {
281
  return 'UserManagement';
282
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
283
  }
src/lib/src/Controller/Controller.php CHANGED
@@ -410,9 +410,7 @@ class Controller extends Shield\Deprecated\Foundation {
410
  /**
411
  */
412
  public function onWpAdminInit() {
413
- if ( $this->getPluginSpec_Property( 'show_dashboard_widget' ) === true ) {
414
- add_action( 'wp_dashboard_setup', [ $this, 'onWpDashboardSetup' ] );
415
- }
416
  add_action( 'admin_enqueue_scripts', [ $this, 'onWpEnqueueAdminCss' ], 100 );
417
  add_action( 'admin_enqueue_scripts', [ $this, 'onWpEnqueueAdminJs' ], 5 );
418
 
@@ -452,18 +450,35 @@ class Controller extends Shield\Deprecated\Foundation {
452
  }
453
 
454
  /**
 
 
 
455
  * @return string - the unique, never-changing site install ID.
456
  */
457
- public function getSiteInstallationId() {
458
  $sOptKey = $this->prefixOption( 'install_id' );
459
- $sId = (string)Services::WpGeneral()->getOption( $sOptKey );
 
 
 
 
 
 
 
 
 
 
 
 
460
 
461
- $sUrl = base64_encode( Services::Data()->urlStripSchema( Services::WpGeneral()->getHomeUrl( '', true ) ) );
462
- if ( empty( $sId ) || strpos( $sId, ':' ) == false || strpos( $sId, $sUrl ) !== 0 ) {
463
- $sId = $sUrl.':'.sha1( uniqid( Services::WpGeneral()->getHomeUrl( '', true ), true ) );
464
- Services::WpGeneral()->updateOption( $sOptKey, $sId );
 
465
  }
466
- return str_replace( $sUrl.':', '', $sId );
 
467
  }
468
 
469
  /**
@@ -483,7 +498,10 @@ class Controller extends Shield\Deprecated\Foundation {
483
  /**
484
  */
485
  public function onWpDashboardSetup() {
486
- if ( $this->isValidAdminArea() ) {
 
 
 
487
  wp_add_dashboard_widget(
488
  $this->prefix( 'dashboard_widget' ),
489
  apply_filters( $this->prefix( 'dashboard_widget_title' ), $this->getHumanName() ),
@@ -494,12 +512,6 @@ class Controller extends Shield\Deprecated\Foundation {
494
  }
495
  }
496
 
497
- /**
498
- * @deprecated 8.5.7
499
- */
500
- public function displayDashboardWidget() {
501
- }
502
-
503
  /**
504
  * @return Shield\Utilities\AdminNotices\Controller
505
  */
@@ -526,12 +538,11 @@ class Controller extends Shield\Deprecated\Foundation {
526
  $sNonceAction = Services::Request()->request( 'exec' );
527
  check_ajax_referer( $sNonceAction, 'exec_nonce' );
528
 
529
- $sAction = Services::WpUsers()->isUserLoggedIn() ? 'ajaxAuthAction' : 'ajaxNonAuthAction';
530
  ob_start();
531
- $aResponseData = apply_filters( $this->prefix( $sAction ), [] );
532
- if ( empty( $aResponseData ) ) {
533
- $aResponseData = apply_filters( $this->prefix( 'ajaxAction' ), $aResponseData );
534
- }
535
  $sNoise = ob_get_clean();
536
 
537
  if ( is_array( $aResponseData ) && isset( $aResponseData[ 'success' ] ) ) {
@@ -963,7 +974,7 @@ class Controller extends Shield\Deprecated\Foundation {
963
  * Hooked to 'shutdown'
964
  */
965
  public function onWpShutdown() {
966
- $this->getSiteInstallationId();
967
  do_action( $this->prefix( 'pre_plugin_shutdown' ) );
968
  do_action( $this->prefix( 'plugin_shutdown' ) );
969
  $this->saveCurrentPluginControllerOptions();
@@ -1632,11 +1643,12 @@ class Controller extends Shield\Deprecated\Foundation {
1632
  * @return bool
1633
  */
1634
  public function isPremiumActive() {
1635
- return apply_filters( $this->getPremiumLicenseFilterName(), false );
1636
  }
1637
 
1638
  /**
1639
  * @return string
 
1640
  */
1641
  public function getPremiumLicenseFilterName() {
1642
  return $this->prefix( 'license_is_valid'.$this->getUniqueRequestId( false ) );
410
  /**
411
  */
412
  public function onWpAdminInit() {
413
+ add_action( 'wp_dashboard_setup', [ $this, 'onWpDashboardSetup' ] );
 
 
414
  add_action( 'admin_enqueue_scripts', [ $this, 'onWpEnqueueAdminCss' ], 100 );
415
  add_action( 'admin_enqueue_scripts', [ $this, 'onWpEnqueueAdminJs' ], 5 );
416
 
450
  }
451
 
452
  /**
453
+ * Only set to rebuild as required if you're doing so at the same point in the WordPress load each time.
454
+ * Certain plugins can modify the ID at different points in the load.
455
+ * @param bool $bRebuildIfRequired
456
  * @return string - the unique, never-changing site install ID.
457
  */
458
+ public function getSiteInstallationId( $bRebuildIfRequired = false ) {
459
  $sOptKey = $this->prefixOption( 'install_id' );
460
+ $aID = Services::WpGeneral()->getOption( $sOptKey );
461
+
462
+ $aPossibleUniqs = [
463
+ 'url' => Services::Data()->urlStripSchema( Services::WpGeneral()->getHomeUrl( '', true ) ),
464
+ 'server' => Services::Data()->getServerHash(),
465
+ ];
466
+
467
+ if ( !is_array( $aID ) ) {
468
+ $aID = [
469
+ 'uniqs' => $aPossibleUniqs,
470
+ 'id' => ( is_string( $aID ) && strpos( $aID, ':' ) ) ? explode( ':', $aID, 2 )[ 1 ] : ''
471
+ ];
472
+ }
473
 
474
+ if ( empty( $aID[ 'id' ] ) || empty( $aID[ 'uniqs' ] ) ||
475
+ ( $bRebuildIfRequired && count( array_intersect( $aPossibleUniqs, $aID[ 'uniqs' ] ) ) === 0 ) ) {
476
+ $aID[ 'id' ] = sha1( uniqid( Services::WpGeneral()->getHomeUrl( '', true ), true ) );
477
+ $aID[ 'uniqs' ] = $aPossibleUniqs;
478
+ Services::WpGeneral()->updateOption( $sOptKey, $aID );
479
  }
480
+
481
+ return $aID[ 'id' ];
482
  }
483
 
484
  /**
498
  /**
499
  */
500
  public function onWpDashboardSetup() {
501
+ $bShow = apply_filters( $this->prefix( 'show_dashboard_widget' ),
502
+ $this->isValidAdminArea() && (bool)$this->getPluginSpec_Property( 'show_dashboard_widget' )
503
+ );
504
+ if ( $bShow ) {
505
  wp_add_dashboard_widget(
506
  $this->prefix( 'dashboard_widget' ),
507
  apply_filters( $this->prefix( 'dashboard_widget_title' ), $this->getHumanName() ),
512
  }
513
  }
514
 
 
 
 
 
 
 
515
  /**
516
  * @return Shield\Utilities\AdminNotices\Controller
517
  */
538
  $sNonceAction = Services::Request()->request( 'exec' );
539
  check_ajax_referer( $sNonceAction, 'exec_nonce' );
540
 
 
541
  ob_start();
542
+ $aResponseData = apply_filters(
543
+ $this->prefix( Services::WpUsers()->isUserLoggedIn() ? 'ajaxAuthAction' : 'ajaxNonAuthAction' ),
544
+ [], $sNonceAction
545
+ );
546
  $sNoise = ob_get_clean();
547
 
548
  if ( is_array( $aResponseData ) && isset( $aResponseData[ 'success' ] ) ) {
974
  * Hooked to 'shutdown'
975
  */
976
  public function onWpShutdown() {
977
+ $this->getSiteInstallationId( true );
978
  do_action( $this->prefix( 'pre_plugin_shutdown' ) );
979
  do_action( $this->prefix( 'plugin_shutdown' ) );
980
  $this->saveCurrentPluginControllerOptions();
1643
  * @return bool
1644
  */
1645
  public function isPremiumActive() {
1646
+ return $this->getModule_License()->getLicenseHandler()->hasValidWorkingLicense();
1647
  }
1648
 
1649
  /**
1650
  * @return string
1651
+ * @deprecated 8.6.2
1652
  */
1653
  public function getPremiumLicenseFilterName() {
1654
  return $this->prefix( 'license_is_valid'.$this->getUniqueRequestId( false ) );
src/lib/src/Crons/BaseCron.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Crons;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield;
6
+
7
+ abstract class BaseCron {
8
+
9
+ use Shield\Crons\StandardCron;
10
+ use Shield\Modules\ModConsumer;
11
+
12
+ /**
13
+ */
14
+ public function run() {
15
+ $this->setupCron();
16
+ }
17
+ }
src/lib/src/Crons/DailyCron.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Crons;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield;
6
+
7
+ class DailyCron extends BaseCron {
8
+
9
+ /**
10
+ * @return string
11
+ */
12
+ protected function getCronFrequency() {
13
+ return 'daily';
14
+ }
15
+
16
+ /**
17
+ * @return string
18
+ * @throws \Exception
19
+ */
20
+ protected function getCronName() {
21
+ return $this->getCon()->prefix( 'daily' );
22
+ }
23
+
24
+ /**
25
+ * Use the included action to hook into the plugin's daily cron
26
+ */
27
+ public function runCron() {
28
+ do_action( $this->getCon()->prefix( 'daily_cron' ) );
29
+ }
30
+ }
src/lib/src/Crons/HourlyCron.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Crons;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield;
6
+
7
+ class HourlyCron extends BaseCron {
8
+
9
+ /**
10
+ * @return string
11
+ */
12
+ protected function getCronFrequency() {
13
+ return 'hourly';
14
+ }
15
+
16
+ /**
17
+ * @return string
18
+ * @throws \Exception
19
+ */
20
+ protected function getCronName() {
21
+ return $this->getCon()->prefix( 'hourly' );
22
+ }
23
+
24
+ /**
25
+ * Use the included action to hook into the plugin's daily cron
26
+ */
27
+ public function runCron() {
28
+ do_action( $this->getCon()->prefix( 'hourly_cron' ) );
29
+ }
30
+ }
src/lib/src/Databases/AuditTrail/Handler.php CHANGED
@@ -54,18 +54,4 @@ class Handler extends Base\Handler {
54
  PRIMARY KEY (id)
55
  ) %s;";
56
  }
57
-
58
- /**
59
- * @param EntryVO[] $aEvents - array of events: key event slug, value created_at timestamp
60
- * @deprecated 8.5
61
- */
62
- public function commitAudits( $aEvents ) {
63
- }
64
-
65
- /**
66
- * @param EntryVO $oEntry
67
- * @deprecated 8.5
68
- */
69
- public function commitAudit( $oEntry ) {
70
- }
71
  }
54
  PRIMARY KEY (id)
55
  ) %s;";
56
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  }
src/lib/src/Databases/Base/BaseQuery.php CHANGED
@@ -32,12 +32,6 @@ abstract class BaseQuery {
32
  */
33
  protected $nPage;
34
 
35
- /**
36
- * @var string
37
- * @deprecated 8.5
38
- */
39
- protected $sOrderBy;
40
-
41
  /**
42
  * @var array
43
  */
@@ -480,12 +474,4 @@ abstract class BaseQuery {
480
  [ '=', '<', '>', '!=', '<>', '<=', '>=', '<=>', 'IN', 'LIKE', 'NOT LIKE' ]
481
  );
482
  }
483
-
484
- /**
485
- * @return string
486
- * @deprecated 8.5
487
- */
488
- public function getOrderBy() {
489
- return '';
490
- }
491
  }
32
  */
33
  protected $nPage;
34
 
 
 
 
 
 
 
35
  /**
36
  * @var array
37
  */
474
  [ '=', '<', '>', '!=', '<>', '<=', '>=', '<=>', 'IN', 'LIKE', 'NOT LIKE' ]
475
  );
476
  }
 
 
 
 
 
 
 
 
477
  }
src/lib/src/Databases/IPs/EntryVO.php CHANGED
@@ -16,43 +16,4 @@ use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
16
  */
17
  class EntryVO extends Base\EntryVO {
18
 
19
- /**
20
- * @return string
21
- * @deprecated 8.5
22
- */
23
- public function getLabel() {
24
- return (string)$this->label;
25
- }
26
-
27
- /**
28
- * @return int
29
- * @deprecated 8.5
30
- */
31
- public function getLastAccessAt() {
32
- return (int)$this->last_access_at;
33
- }
34
-
35
- /**
36
- * @return string
37
- * @deprecated 8.5
38
- */
39
- public function getList() {
40
- return (string)$this->list;
41
- }
42
-
43
- /**
44
- * @return int
45
- * @deprecated 8.5
46
- */
47
- public function getTransgressions() {
48
- return (int)$this->transgressions;
49
- }
50
-
51
- /**
52
- * @return bool
53
- * @deprecated 8.5
54
- */
55
- public function hasTransgressions() {
56
- return (int)$this->transgressions > 0;
57
- }
58
  }
16
  */
17
  class EntryVO extends Base\EntryVO {
18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  }
src/lib/src/Databases/IPs/Select.php CHANGED
@@ -7,47 +7,4 @@ use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
7
  class Select extends Base\Select {
8
 
9
  use CommonFilters;
10
-
11
- /**
12
- * @param string $sIp
13
- * @return bool
14
- * @deprecated 8.5
15
- */
16
- public function getIpOnBlackLists( $sIp ) {
17
- return $this->reset()
18
- ->filterByIp( $sIp )
19
- ->filterByBlacklist()
20
- ->first();
21
- }
22
-
23
- /**
24
- * @return EntryVO[]
25
- */
26
- public function getAllBlocked() {
27
- /** @var EntryVO[] $aRes */
28
- return $this->reset()
29
- ->filterByBlocked( true )
30
- ->filterByBlacklist()
31
- ->query();
32
- }
33
-
34
- /**
35
- * @param string $sList
36
- * @return EntryVO[]
37
- * @deprecated 8.5
38
- */
39
- public function allFromList( $sList ) {
40
- /** @var EntryVO[] $aRes */
41
- return $this->reset()
42
- ->filterByList( $sList )
43
- ->query();
44
- }
45
-
46
- /**
47
- * @return string[]
48
- * @deprecated 8.5
49
- */
50
- public function getDistinctIps() {
51
- return $this->getDistinct_FilterAndSort( 'ip' );
52
- }
53
  }
7
  class Select extends Base\Select {
8
 
9
  use CommonFilters;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  }
src/lib/src/Deprecated/Foundation.php CHANGED
@@ -19,30 +19,6 @@ class Foundation {
19
  return self::DEFAULT_SERVICE_PREFIX.$sSuffix;
20
  }
21
 
22
- /**
23
- * @return \ICWP_WPSF_WpCron
24
- * @deprecated 8.5
25
- */
26
- public static function loadWpCronProcessor() {
27
- $sKey = 'icwp-wpcron';
28
- if ( !self::isServiceReady( $sKey ) ) {
29
- self::setService( $sKey, \ICWP_WPSF_WpCron::GetInstance() );
30
- }
31
- return self::getService( $sKey );
32
- }
33
-
34
- /**
35
- * @return \ICWP_WPSF_ServiceProviders
36
- * @deprecated 8.5.2
37
- */
38
- public function loadServiceProviders() {
39
- $sKey = 'icwp-serviceproviders';
40
- if ( !self::isServiceReady( $sKey ) ) {
41
- self::setService( $sKey, \ICWP_WPSF_ServiceProviders::GetInstance() );
42
- }
43
- return self::getService( $sKey );
44
- }
45
-
46
  /**
47
  * @return array
48
  */
19
  return self::DEFAULT_SERVICE_PREFIX.$sSuffix;
20
  }
21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  /**
23
  * @return array
24
  */
src/lib/src/License/EddLicenseVO.php CHANGED
@@ -9,5 +9,4 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\License;
9
  */
10
  class EddLicenseVO extends \FernleafSystems\Wordpress\Services\Utilities\Licenses\EddLicenseVO {
11
 
12
- use \FernleafSystems\Utilities\Data\Adapter\StdClassAdapter;
13
  }
9
  */
10
  class EddLicenseVO extends \FernleafSystems\Wordpress\Services\Utilities\Licenses\EddLicenseVO {
11
 
 
12
  }
src/lib/src/Modules/Autoupdates/Strings.php CHANGED
@@ -113,7 +113,7 @@ class Strings extends Base\Strings {
113
  $sDescription = __( 'At least automatically upgrading minor versions is recommended (and is the WordPress default).', 'wp-simple-firewall' );
114
  break;
115
 
116
- case 'enable_autoupdate_translations' :
117
  $sName = __( 'Translations', 'wp-simple-firewall' );
118
  $sSummary = __( 'Automatically Update Translations', 'wp-simple-firewall' );
119
  $sDescription = __( 'Note: Automatic updates for translations are enabled on WordPress by default.', 'wp-simple-firewall' );
@@ -137,7 +137,7 @@ class Strings extends Base\Strings {
137
  $sDescription = __( 'Note: Automatic updates for themes are disabled on WordPress by default.', 'wp-simple-firewall' );
138
  break;
139
 
140
- case 'enable_autoupdate_ignore_vcs' :
141
  $sName = __( 'Ignore Version Control', 'wp-simple-firewall' );
142
  $sSummary = __( 'Ignore Version Control Systems Such As GIT and SVN', 'wp-simple-firewall' );
143
  $sDescription = __( 'If you use SVN or GIT and WordPress detects it, automatic updates are disabled by default. Check this box to ignore version control systems and allow automatic updates.', 'wp-simple-firewall' );
113
  $sDescription = __( 'At least automatically upgrading minor versions is recommended (and is the WordPress default).', 'wp-simple-firewall' );
114
  break;
115
 
116
+ case 'enable_autoupdate_translations' : // REMOVED 8.6.2
117
  $sName = __( 'Translations', 'wp-simple-firewall' );
118
  $sSummary = __( 'Automatically Update Translations', 'wp-simple-firewall' );
119
  $sDescription = __( 'Note: Automatic updates for translations are enabled on WordPress by default.', 'wp-simple-firewall' );
137
  $sDescription = __( 'Note: Automatic updates for themes are disabled on WordPress by default.', 'wp-simple-firewall' );
138
  break;
139
 
140
+ case 'enable_autoupdate_ignore_vcs' : // REMOVED 8.6.2
141
  $sName = __( 'Ignore Version Control', 'wp-simple-firewall' );
142
  $sSummary = __( 'Ignore Version Control Systems Such As GIT and SVN', 'wp-simple-firewall' );
143
  $sDescription = __( 'If you use SVN or GIT and WordPress detects it, automatic updates are disabled by default. Check this box to ignore version control systems and allow automatic updates.', 'wp-simple-firewall' );
src/lib/src/Modules/Base/AjaxHandlerBase.php CHANGED
@@ -16,20 +16,28 @@ class AjaxHandlerBase {
16
  /**
17
  */
18
  public function init() {
19
- $oMod = $this->getMod();
20
- if ( $oMod->isModuleRequest() ) {
21
- add_filter( $oMod->prefix( 'ajaxAction' ), [ $this, 'handleAjax' ] );
22
- add_filter( $oMod->prefix( 'ajaxAuthAction' ), [ $this, 'handleAjax' ] );
23
- add_filter( $oMod->prefix( 'ajaxNonAuthAction' ), [ $this, 'handleAjax' ] );
 
 
 
 
 
 
 
24
  }
 
25
  }
26
 
27
  /**
28
- * @param array $aAjaxResponse
 
29
  * @return array
30
  */
31
- public function handleAjax( $aAjaxResponse ) {
32
- $sAjaxAction = Services::Request()->request( 'exec' );
33
  if ( !empty( $sAjaxAction ) && ( empty( $aAjaxResponse ) || !is_array( $aAjaxResponse ) ) ) {
34
  $aAjaxResponse = $this->normaliseAjaxResponse( $this->processAjaxAction( $sAjaxAction ) );
35
  }
@@ -40,7 +48,7 @@ class AjaxHandlerBase {
40
  * @param string $sEncoding
41
  * @return array
42
  */
43
- public function getAjaxFormParams( $sEncoding = 'none' ) {
44
  $oReq = Services::Request();
45
  $aFormParams = [];
46
  $sRaw = $oReq->post( 'form_params', '' );
16
  /**
17
  */
18
  public function init() {
19
+ add_filter( $this->getCon()->prefix( 'ajaxAuthAction' ), [ $this, 'handleAjaxAuth' ], 10, 2 );
20
+ add_filter( $this->getCon()->prefix( 'ajaxNonAuthAction' ), [ $this, 'handleAjaxNonAuth' ], 10, 2 );
21
+ }
22
+
23
+ /**
24
+ * @param array $aAjaxResponse
25
+ * @param string $sAjaxAction
26
+ * @return array
27
+ */
28
+ public function handleAjaxAuth( $aAjaxResponse, $sAjaxAction ) {
29
+ if ( !empty( $sAjaxAction ) && ( empty( $aAjaxResponse ) || !is_array( $aAjaxResponse ) ) ) {
30
+ $aAjaxResponse = $this->normaliseAjaxResponse( $this->processAjaxAction( $sAjaxAction ) );
31
  }
32
+ return $aAjaxResponse;
33
  }
34
 
35
  /**
36
+ * @param array $aAjaxResponse
37
+ * @param string $sAjaxAction
38
  * @return array
39
  */
40
+ public function handleAjaxNonAuth( $aAjaxResponse, $sAjaxAction ) {
 
41
  if ( !empty( $sAjaxAction ) && ( empty( $aAjaxResponse ) || !is_array( $aAjaxResponse ) ) ) {
42
  $aAjaxResponse = $this->normaliseAjaxResponse( $this->processAjaxAction( $sAjaxAction ) );
43
  }
48
  * @param string $sEncoding
49
  * @return array
50
  */
51
+ protected function getAjaxFormParams( $sEncoding = 'none' ) {
52
  $oReq = Services::Request();
53
  $aFormParams = [];
54
  $sRaw = $oReq->post( 'form_params', '' );
src/lib/src/Modules/Base/AjaxHandlerShield.php CHANGED
@@ -2,8 +2,6 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
4
 
5
- use FernleafSystems\Wordpress\Services\Services;
6
-
7
  class AjaxHandlerShield extends AjaxHandlerBase {
8
 
9
  /**
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
4
 
 
 
5
  class AjaxHandlerShield extends AjaxHandlerBase {
6
 
7
  /**
src/lib/src/Modules/Base/BaseProcessor.php CHANGED
@@ -141,6 +141,7 @@ class BaseProcessor extends Deprecated\Foundation {
141
  * @param $sOptionKey
142
  * @param mixed $mDefault
143
  * @return mixed
 
144
  */
145
  public function getOption( $sOptionKey, $mDefault = false ) {
146
  return $this->getMod()->getOpt( $sOptionKey, $mDefault );
141
  * @param $sOptionKey
142
  * @param mixed $mDefault
143
  * @return mixed
144
+ * @deprecated 8.6.2 - leave for a while JIC.
145
  */
146
  public function getOption( $sOptionKey, $mDefault = false ) {
147
  return $this->getMod()->getOpt( $sOptionKey, $mDefault );
src/lib/src/Modules/Base/Options.php CHANGED
@@ -1015,7 +1015,9 @@ class Options {
1015
  * @return string
1016
  */
1017
  private function getConfigStorageKey() {
1018
- return 'shield_mod_config_'.md5( $this->getPathToConfig() );
 
 
1019
  }
1020
 
1021
  /**
1015
  * @return string
1016
  */
1017
  private function getConfigStorageKey() {
1018
+ return 'shield_mod_config_'.md5(
1019
+ str_replace( wp_normalize_path( ABSPATH ), '', wp_normalize_path( $this->getPathToConfig() ) )
1020
+ );
1021
  }
1022
 
1023
  /**
src/lib/src/Modules/Base/Strings.php CHANGED
@@ -56,6 +56,7 @@ class Strings {
56
  'actions_summary' => __( 'Perform actions for this module', 'wp-simple-firewall' ),
57
  'help_title' => __( 'Help', 'wp-simple-firewall' ),
58
  'help_summary' => __( 'Learn More', 'wp-simple-firewall' ),
 
59
  'ip_address' => __( 'IP Address', 'wp-simple-firewall' ),
60
  'select' => __( 'Select' ),
61
  'filters_clear' => __( 'Clear Filters', 'wp-simple-firewall' ),
@@ -96,6 +97,8 @@ class Strings {
96
  'get_pro_protection' => __( 'Upgrade To Pro Protection', 'wp-simple-firewall' ),
97
 
98
  'page_title' => 'Twig Page',
 
 
99
  ],
100
  $this->getAdditionalDisplayStrings()
101
  );
56
  'actions_summary' => __( 'Perform actions for this module', 'wp-simple-firewall' ),
57
  'help_title' => __( 'Help', 'wp-simple-firewall' ),
58
  'help_summary' => __( 'Learn More', 'wp-simple-firewall' ),
59
+ 'installation_id' => __( 'Installation ID', 'wp-simple-firewall' ),
60
  'ip_address' => __( 'IP Address', 'wp-simple-firewall' ),
61
  'select' => __( 'Select' ),
62
  'filters_clear' => __( 'Clear Filters', 'wp-simple-firewall' ),
97
  'get_pro_protection' => __( 'Upgrade To Pro Protection', 'wp-simple-firewall' ),
98
 
99
  'page_title' => 'Twig Page',
100
+
101
+ 'wphashes_token' => 'WPHashes.com API Token',
102
  ],
103
  $this->getAdditionalDisplayStrings()
104
  );
src/lib/src/Modules/CommentsFilter/Options.php CHANGED
@@ -20,6 +20,13 @@ class Options extends Base\ShieldOptions {
20
  return $this->getCon()->prefixOption( $this->getDef( 'spambot_comments_filter_table_name' ) );
21
  }
22
 
 
 
 
 
 
 
 
23
  /**
24
  * @return int
25
  */
20
  return $this->getCon()->prefixOption( $this->getDef( 'spambot_comments_filter_table_name' ) );
21
  }
22
 
23
+ /**
24
+ * @return int
25
+ */
26
+ public function getTokenCooldown() {
27
+ return (int)$this->getOpt( 'comments_cooldown_interval' );
28
+ }
29
+
30
  /**
31
  * @return int
32
  */
src/lib/src/Modules/CommentsFilter/Scan/Bot.php CHANGED
@@ -2,6 +2,7 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter\Scan;
4
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
  use FernleafSystems\Wordpress\Services\Services;
7
 
@@ -14,8 +15,8 @@ class Bot {
14
  * @return true|\WP_Error
15
  */
16
  public function scan( $nPostId ) {
17
- /** @var \ICWP_WPSF_FeatureHandler_CommentsFilter $oMod */
18
- $oMod = $this->getMod();
19
 
20
  $oReq = Services::Request();
21
  $sFieldCheckboxName = $oReq->post( 'cb_nombre' );
@@ -23,8 +24,8 @@ class Bot {
23
  $nCommentTs = (int)$oReq->post( 'botts' );
24
  $sCommentToken = $oReq->post( 'comment_token' );
25
 
26
- $nCooldown = $oMod->getTokenCooldown();
27
- $nExpire = $oMod->getTokenExpireInterval();
28
 
29
  $sKey = null;
30
  $sExplanation = null;
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter\Scan;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
  use FernleafSystems\Wordpress\Services\Services;
8
 
15
  * @return true|\WP_Error
16
  */
17
  public function scan( $nPostId ) {
18
+ /** @var CommentsFilter\Options $oOpts */
19
+ $oOpts = $this->getOptions();
20
 
21
  $oReq = Services::Request();
22
  $sFieldCheckboxName = $oReq->post( 'cb_nombre' );
24
  $nCommentTs = (int)$oReq->post( 'botts' );
25
  $sCommentToken = $oReq->post( 'comment_token' );
26
 
27
+ $nCooldown = $oOpts->getTokenCooldown();
28
+ $nExpire = $oOpts->getTokenExpireInterval();
29
 
30
  $sKey = null;
31
  $sExplanation = null;
src/lib/src/Modules/CommentsFilter/Token/Create.php CHANGED
@@ -2,6 +2,7 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter\Token;
4
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
  use FernleafSystems\Wordpress\Services\Services;
7
 
@@ -15,15 +16,15 @@ class Create {
15
  * @return string
16
  */
17
  public function run( $nTs, $nPostId ) {
18
- /** @var \ICWP_WPSF_FeatureHandler_CommentsFilter $oMod */
19
- $oMod = $this->getMod();
20
 
21
  $sToken = $this->generateNewToken( $nTs, $nPostId );
22
 
23
  Services::WpGeneral()->setTransient(
24
- $oMod->prefix( 'comtok-'.md5( sprintf( '%s-%s-%s', $nPostId, $nTs, Services::IP()->getRequestIp() ) ) ),
25
  $sToken,
26
- $oMod->getTokenExpireInterval()
27
  );
28
 
29
  return $sToken;
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter\Token;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
  use FernleafSystems\Wordpress\Services\Services;
8
 
16
  * @return string
17
  */
18
  public function run( $nTs, $nPostId ) {
19
+ /** @var CommentsFilter\Options $oOpts */
20
+ $oOpts = $this->getOptions();
21
 
22
  $sToken = $this->generateNewToken( $nTs, $nPostId );
23
 
24
  Services::WpGeneral()->setTransient(
25
+ $this->getCon()->prefix( 'comtok-'.md5( sprintf( '%s-%s-%s', $nPostId, $nTs, Services::IP()->getRequestIp() ) ) ),
26
  $sToken,
27
+ $oOpts->getTokenExpireInterval()
28
  );
29
 
30
  return $sToken;
src/lib/src/Modules/HackGuard/Lib/Snapshots/StoreAction/BuildAll.php DELETED
@@ -1,53 +0,0 @@
1
- <?php
2
-
3
- namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\Snapshots\StoreAction;
4
-
5
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\Snapshots\FindAssetsToSnap;
6
- use FernleafSystems\Wordpress\Services\Core\VOs;
7
-
8
- /**
9
- * Class BuildAll
10
- * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\Snapshots\StoreAction
11
- * @deprecated 8.5.2
12
- */
13
- class BuildAll extends BaseBulk {
14
-
15
- public function build() {
16
- foreach ( $this->getAssetsThatNeedBuilt() as $oAsset ) {
17
- try {
18
- ( new Build() )
19
- ->setMod( $this->getMod() )
20
- ->setAsset( $oAsset )
21
- ->run();
22
- }
23
- catch ( \Exception $oE ) {
24
- }
25
- }
26
- }
27
-
28
- /**
29
- * Only those that don't have a meta file or the versions are different
30
- * @return VOs\WpPluginVo[]|VOs\WpThemeVo[]
31
- */
32
- private function getAssetsThatNeedBuilt() {
33
- return array_filter(
34
- ( new FindAssetsToSnap() )
35
- ->setMod( $this->getMod() )
36
- ->run(),
37
- function ( $oAsset ) {
38
- /** @var VOs\WpPluginVo|VOs\WpThemeVo $oAsset */
39
- try {
40
- $aMeta = ( new Load() )
41
- ->setMod( $this->getMod() )
42
- ->setAsset( $oAsset )
43
- ->run()
44
- ->getSnapMeta();
45
- }
46
- catch ( \Exception $oE ) {
47
- $aMeta = null;
48
- }
49
- return ( empty( $aMeta ) || $oAsset->version !== $aMeta[ 'version' ] );
50
- }
51
- );
52
- }
53
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/src/Modules/HackGuard/Options.php CHANGED
@@ -446,20 +446,4 @@ class Options extends Base\ShieldOptions {
446
  }
447
  ) );
448
  }
449
-
450
- /**
451
- * @return int
452
- * @deprecated 8.5
453
- */
454
- public function getPtgLastBuildAt() {
455
- return $this->getOpt( 'ptg_last_build_at' );
456
- }
457
-
458
- /**
459
- * @return string|false
460
- * @deprecated 8.5
461
- */
462
- public function getPtgSnapsBaseDir() {
463
- return $this->getCon()->getPluginCachePath( 'ptguard/' );
464
- }
465
  }
446
  }
447
  ) );
448
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
449
  }
src/lib/src/Modules/IPs/AjaxHandler.php CHANGED
@@ -68,10 +68,7 @@ class AjaxHandler extends Shield\Modules\Base\AjaxHandlerShield {
68
  elseif ( $bIsBlackList && !$oMod->isPremium() ) {
69
  $sMessage = __( "Please upgrade to Pro if you'd like to add IPs to the black list manually.", 'wp-simple-firewall' );
70
  }
71
- elseif ( $bIsBlackList && $oIpServ->isValidIp4Range( $sIp ) ) { // TODO
72
- $sMessage = __( "IP ranges aren't currently supported for blacklisting.", 'wp-simple-firewall' );
73
- }
74
- elseif ( $bIsBlackList && $oIpServ->checkIp( $sIp, $oIpServ->getRequestIp() ) ) {
75
  $sMessage = __( "Manually black listing your current IP address is not supported.", 'wp-simple-firewall' );
76
  }
77
  elseif ( $bIsBlackList && in_array( $sIp, Services::IP()->getServerPublicIPs() ) ) {
@@ -79,28 +76,35 @@ class AjaxHandler extends Shield\Modules\Base\AjaxHandlerShield {
79
  }
80
  else {
81
  $sLabel = isset( $aFormParams[ 'label' ] ) ? $aFormParams[ 'label' ] : '';
 
82
  switch ( $sList ) {
83
-
84
  case $oMod::LIST_MANUAL_WHITE:
85
- $oIp = ( new Shield\Modules\IPs\Lib\Ops\AddIp() )
86
- ->setMod( $oMod )
87
- ->setIP( $sIp )
88
- ->toManualWhitelist( $sLabel );
 
 
 
 
89
  break;
90
 
91
  case $oMod::LIST_MANUAL_BLACK:
92
- $oIp = ( new Shield\Modules\IPs\Lib\Ops\AddIp() )
93
- ->setMod( $oMod )
94
- ->setIP( $sIp )
95
- ->toManualBlacklist( $sLabel );
 
 
 
 
96
  break;
97
 
98
  default:
99
- $oIp = null;
100
  break;
101
  }
102
 
103
- if ( !empty( $oIp ) ) {
104
  $sMessage = __( 'IP address added successfully', 'wp-simple-firewall' );
105
  $bSuccess = true;
106
  }
68
  elseif ( $bIsBlackList && !$oMod->isPremium() ) {
69
  $sMessage = __( "Please upgrade to Pro if you'd like to add IPs to the black list manually.", 'wp-simple-firewall' );
70
  }
71
+ elseif ( $bIsBlackList && $oIpServ->checkIp( $oIpServ->getRequestIp(), $sIp ) ) {
 
 
 
72
  $sMessage = __( "Manually black listing your current IP address is not supported.", 'wp-simple-firewall' );
73
  }
74
  elseif ( $bIsBlackList && in_array( $sIp, Services::IP()->getServerPublicIPs() ) ) {
76
  }
77
  else {
78
  $sLabel = isset( $aFormParams[ 'label' ] ) ? $aFormParams[ 'label' ] : '';
79
+ $oIP = null;
80
  switch ( $sList ) {
 
81
  case $oMod::LIST_MANUAL_WHITE:
82
+ try {
83
+ $oIP = ( new Shield\Modules\IPs\Lib\Ops\AddIp() )
84
+ ->setMod( $oMod )
85
+ ->setIP( $sIp )
86
+ ->toManualWhitelist( $sLabel );
87
+ }
88
+ catch ( \Exception $oE ) {
89
+ }
90
  break;
91
 
92
  case $oMod::LIST_MANUAL_BLACK:
93
+ try {
94
+ $oIP = ( new Shield\Modules\IPs\Lib\Ops\AddIp() )
95
+ ->setMod( $oMod )
96
+ ->setIP( $sIp )
97
+ ->toManualBlacklist( $sLabel );
98
+ }
99
+ catch ( \Exception $oE ) {
100
+ }
101
  break;
102
 
103
  default:
 
104
  break;
105
  }
106
 
107
+ if ( !empty( $oIP ) ) {
108
  $sMessage = __( 'IP address added successfully', 'wp-simple-firewall' );
109
  $bSuccess = true;
110
  }
src/lib/src/Modules/IPs/Components/ProcessOffense.php CHANGED
@@ -25,18 +25,23 @@ class ProcessOffense {
25
  /** @var IPs\Options $oOpts */
26
  $oOpts = $oMod->getOptions();
27
 
28
- $oIP = ( new IPs\Lib\Ops\AddIp() )
29
- ->setMod( $oMod )
30
- ->setIP( $this->getIP() )
31
- ->toAutoBlacklist();
 
 
 
 
 
32
 
33
  if ( $oIP instanceof Databases\IPs\EntryVO ) {
34
  $nCurrent = $oIP->transgressions;
35
 
36
  $oTracker = $oMod->loadOffenseTracker();
37
- $bToBlock = $oTracker->isBlocked() ||
38
- ( $oIP->blocked_at == 0 && ( $oOpts->getOffenseLimit() - $nCurrent == 1 ) );
39
  $nNewTotal = $oIP->transgressions + $oTracker->getOffenseCount();
 
 
40
 
41
  /** @var Databases\IPs\Update $oUp */
42
  $oUp = $oMod->getDbHandler_IPs()->getQueryUpdater();
25
  /** @var IPs\Options $oOpts */
26
  $oOpts = $oMod->getOptions();
27
 
28
+ try {
29
+ $oIP = ( new IPs\Lib\Ops\AddIp() )
30
+ ->setMod( $oMod )
31
+ ->setIP( $this->getIP() )
32
+ ->toAutoBlacklist();
33
+ }
34
+ catch ( \Exception $oE ) {
35
+ $oIP = null;
36
+ }
37
 
38
  if ( $oIP instanceof Databases\IPs\EntryVO ) {
39
  $nCurrent = $oIP->transgressions;
40
 
41
  $oTracker = $oMod->loadOffenseTracker();
 
 
42
  $nNewTotal = $oIP->transgressions + $oTracker->getOffenseCount();
43
+ $bToBlock = $oTracker->isBlocked() ||
44
+ ( $oIP->blocked_at == 0 && ( $nNewTotal >= $oOpts->getOffenseLimit() ) );
45
 
46
  /** @var Databases\IPs\Update $oUp */
47
  $oUp = $oMod->getDbHandler_IPs()->getQueryUpdater();
src/lib/src/Modules/IPs/Components/QueryIpBlock.php CHANGED
@@ -37,11 +37,6 @@ class QueryIpBlock {
37
  /** @var Databases\IPs\Update $oUp */
38
  $oUp = $oMod->getDbHandler_IPs()->getQueryUpdater();
39
  $oUp->updateLastAccessAt( $oIP );
40
-
41
- // TODO: 8.6: remove eventually and lose transgressions comparison and query for "blocked" only (see below)
42
- if ( $oIP->blocked_at == 0 ) {
43
- $oUp->reset()->setBlocked( $oIP );
44
- }
45
  }
46
  return $bIpBlocked;
47
  }
@@ -58,7 +53,7 @@ class QueryIpBlock {
58
  ->setDbHandler( $oMod->getDbHandler_IPs() )
59
  ->setIP( $this->getIP() )
60
  ->setListTypeBlack()
61
- // ->setIsIpBlocked( true ) TODO: 8.6
62
  ->lookup();
63
 
64
  if ( $oIP instanceof Databases\IPs\EntryVO ) {
@@ -74,7 +69,7 @@ class QueryIpBlock {
74
  ->setIP( Services::IP()->getRequestIp() )
75
  ->fromBlacklist();
76
  }
77
- elseif ( $oIP->blocked_at > 0 || (int)$oIP->transgressions >= $oOpts->getOffenseLimit() ) {
78
  $oBlockIP = $oIP;
79
  }
80
  }
37
  /** @var Databases\IPs\Update $oUp */
38
  $oUp = $oMod->getDbHandler_IPs()->getQueryUpdater();
39
  $oUp->updateLastAccessAt( $oIP );
 
 
 
 
 
40
  }
41
  return $bIpBlocked;
42
  }
53
  ->setDbHandler( $oMod->getDbHandler_IPs() )
54
  ->setIP( $this->getIP() )
55
  ->setListTypeBlack()
56
+ ->setIsIpBlocked( true )
57
  ->lookup();
58
 
59
  if ( $oIP instanceof Databases\IPs\EntryVO ) {
69
  ->setIP( Services::IP()->getRequestIp() )
70
  ->fromBlacklist();
71
  }
72
+ else {
73
  $oBlockIP = $oIP;
74
  }
75
  }
src/lib/src/Modules/IPs/Lib/BlacklistHandler.php ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
+ use FernleafSystems\Wordpress\Services\Services;
8
+
9
+ class BlacklistHandler {
10
+
11
+ use ModConsumer;
12
+
13
+ public function run() {
14
+ /** @var \ICWP_WPSF_FeatureHandler_Ips $oMod */
15
+ $oMod = $this->getMod();
16
+ /** @var IPs\Options $oOpts */
17
+ $oOpts = $this->getOptions();
18
+ if ( $oOpts->isEnabledAutoBlackList() ) {
19
+
20
+ ( new IPs\Components\UnblockIpByFlag() )
21
+ ->setMod( $oMod )
22
+ ->run();
23
+
24
+ add_action( 'init', [ $this, 'loadBotDetectors' ] ); // hook in the bot detection
25
+
26
+ if ( !$oMod->isVisitorWhitelisted() && !$this->isRequestWhitelisted() && !$oMod->isVerifiedBot() ) {
27
+ ( new BlockRequest() )
28
+ ->setMod( $oMod )
29
+ ->run();
30
+ ( new BlackmarkRequest() )
31
+ ->setMod( $oMod )
32
+ ->run();
33
+ }
34
+ }
35
+ }
36
+
37
+ public function loadBotDetectors() {
38
+ /** @var \ICWP_WPSF_FeatureHandler_Ips $oMod */
39
+ $oMod = $this->getMod();
40
+ /** @var IPs\Options $oOpts */
41
+ $oOpts = $oMod->getOptions();
42
+
43
+ if ( !Services::WpUsers()->isUserLoggedIn() ) {
44
+
45
+ if ( !$oMod->isVerifiedBot() ) {
46
+ if ( $oOpts->isEnabledTrackXmlRpc() ) {
47
+ ( new IPs\BotTrack\TrackXmlRpc() )
48
+ ->setMod( $oMod )
49
+ ->run();
50
+ }
51
+ if ( $oOpts->isEnabledTrack404() ) {
52
+ ( new IPs\BotTrack\Track404() )
53
+ ->setMod( $oMod )
54
+ ->run();
55
+ }
56
+ if ( $oOpts->isEnabledTrackLoginFailed() ) {
57
+ ( new IPs\BotTrack\TrackLoginFailed() )
58
+ ->setMod( $oMod )
59
+ ->run();
60
+ }
61
+ if ( $oOpts->isEnabledTrackLoginInvalid() ) {
62
+ ( new IPs\BotTrack\TrackLoginInvalid() )
63
+ ->setMod( $oMod )
64
+ ->run();
65
+ }
66
+ if ( $oOpts->isEnabledTrackFakeWebCrawler() ) {
67
+ ( new IPs\BotTrack\TrackFakeWebCrawler() )
68
+ ->setMod( $oMod )
69
+ ->run();
70
+ }
71
+ }
72
+
73
+ /** Always run link cheese regardless of the verified bot or not */
74
+ if ( $oOpts->isEnabledTrackLinkCheese() ) {
75
+ ( new IPs\BotTrack\TrackLinkCheese() )
76
+ ->setMod( $oMod )
77
+ ->run();
78
+ }
79
+ }
80
+ }
81
+
82
+ /**
83
+ * @return bool
84
+ */
85
+ private function isRequestWhitelisted() {
86
+ /** @var IPs\Options $oOpts */
87
+ $oOpts = $this->getOptions();
88
+ $bWhitelisted = false;
89
+ $aWhitelist = $oOpts->getRequestWhitelistAsRegex();
90
+ if ( !empty( $aWhitelist ) ) {
91
+ $sPath = strtolower( '/'.ltrim( (string)Services::Request()->getPath(), '/' ) );
92
+ foreach ( $aWhitelist as $sRule ) {
93
+ if ( preg_match( $sRule, $sPath ) ) {
94
+ $bWhitelisted = true;
95
+ break;
96
+ }
97
+ }
98
+ }
99
+ return $bWhitelisted;
100
+ }
101
+ }
src/lib/src/Modules/IPs/Lib/BlackmarkRequest.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
+ use FernleafSystems\Wordpress\Services\Services;
8
+
9
+ class BlackmarkRequest {
10
+
11
+ use ModConsumer;
12
+
13
+ public function run() {
14
+ /** @var \ICWP_WPSF_FeatureHandler_Ips $oMod */
15
+ $oMod = $this->getMod();
16
+
17
+ $oMod->loadOffenseTracker()->setIfCommit( true );
18
+
19
+ $oCon = $this->getCon();
20
+ add_filter( $oCon->prefix( 'firewall_die_message' ), [ $this, 'augmentFirewallDieMessage' ] );
21
+ add_action( $oCon->prefix( 'pre_plugin_shutdown' ), function () {
22
+ $this->processOffense();
23
+ } );
24
+ add_action( 'shield_security_offense', [ $this, 'processCustomShieldOffense' ], 10, 3 );
25
+ }
26
+
27
+ private function processOffense() {
28
+ /** @var \ICWP_WPSF_FeatureHandler_Ips $oMod */
29
+ $oMod = $this->getMod();
30
+
31
+ $oTracker = $oMod->loadOffenseTracker();
32
+ if ( !$this->getCon()->isPluginDeleting() && $oTracker->hasVisitorOffended() && $oTracker->isCommit() ) {
33
+ ( new IPs\Components\ProcessOffense() )
34
+ ->setMod( $oMod )
35
+ ->setIp( Services::IP()->getRequestIp() )
36
+ ->run();
37
+ }
38
+ }
39
+
40
+ /**
41
+ * @param array $aMessages
42
+ * @return array
43
+ */
44
+ public function augmentFirewallDieMessage( $aMessages ) {
45
+ if ( !is_array( $aMessages ) ) {
46
+ $aMessages = [];
47
+ }
48
+
49
+ $aMessages[] = sprintf( '<p>%s</p>', sprintf(
50
+ $this->getMod()->getTextOpt( 'text_remainingtrans' ),
51
+ ( new IPs\Components\QueryRemainingOffenses() )
52
+ ->setMod( $this->getMod() )
53
+ ->setIP( Services::IP()->getRequestIp() )
54
+ ->run()
55
+ ) );
56
+
57
+ return $aMessages;
58
+ }
59
+
60
+ /**
61
+ * Allows 3rd parties to trigger Shield offenses
62
+ * @param string $sMessage
63
+ * @param int $nOffenseCount
64
+ * @param bool $bIncludeLoggedIn
65
+ */
66
+ public function processCustomShieldOffense( $sMessage, $nOffenseCount = 1, $bIncludeLoggedIn = true ) {
67
+ if ( $this->getCon()->isPremiumActive() ) {
68
+ if ( empty( $sMessage ) ) {
69
+ $sMessage = __( 'No custom message provided.', 'wp-simple-firewall' );
70
+ }
71
+
72
+ if ( $bIncludeLoggedIn || !did_action( 'init' ) || !Services::WpUsers()->isUserLoggedIn() ) {
73
+ $this->getCon()
74
+ ->fireEvent(
75
+ 'custom_offense',
76
+ [
77
+ 'audit' => [ 'message' => $sMessage ],
78
+ 'offense_count' => $nOffenseCount
79
+ ]
80
+ );
81
+ }
82
+ }
83
+ }
84
+ }
src/lib/src/Modules/IPs/Lib/BlockRequest.php ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
+ use FernleafSystems\Wordpress\Services\Services;
8
+
9
+ class BlockRequest {
10
+
11
+ use ModConsumer;
12
+
13
+ public function run() {
14
+ /** @var \ICWP_WPSF_FeatureHandler_Ips $oMod */
15
+ $oMod = $this->getMod();
16
+
17
+ $bIpBlocked = ( new IPs\Components\QueryIpBlock() )
18
+ ->setMod( $oMod )
19
+ ->setIp( Services::IP()->getRequestIp() )
20
+ ->run();
21
+
22
+ if ( $bIpBlocked ) {
23
+ // $this->setIfLogRequest( false ); // TODO don't log traffic from killed requests
24
+ try {
25
+ if ( $this->processAutoUnblockRequest() ) {
26
+ return;
27
+ }
28
+ }
29
+ catch ( \Exception $oE ) {
30
+ }
31
+ $this->getCon()->fireEvent( 'conn_kill' );
32
+ $this->renderKillPage();
33
+ }
34
+ }
35
+
36
+ /**
37
+ * @throws \Exception
38
+ */
39
+ private function processAutoUnblockRequest() {
40
+ /** @var \ICWP_WPSF_FeatureHandler_Ips $oMod */
41
+ $oMod = $this->getMod();
42
+ /** @var IPs\Options $oOpts */
43
+ $oOpts = $oMod->getOptions();
44
+ $oReq = Services::Request();
45
+
46
+ if ( $oOpts->isEnabledAutoUserRecover() && $oReq->isPost()
47
+ && $oReq->request( 'action' ) == $oMod->prefix() && $oReq->request( 'exec' ) == 'uau' ) {
48
+
49
+ if ( check_admin_referer( $oReq->request( 'exec' ), 'exec_nonce' ) !== 1 ) {
50
+ throw new \Exception( 'Nonce failed' );
51
+ }
52
+ if ( strlen( $oReq->post( 'icwp_wpsf_login_email' ) ) > 0 ) {
53
+ throw new \Exception( 'Email should not be provided in honeypot' );
54
+ }
55
+
56
+ $sIp = Services::IP()->getRequestIp();
57
+ if ( $oReq->post( 'ip' ) != $sIp ) {
58
+ throw new \Exception( 'IP does not match' );
59
+ }
60
+
61
+ $oLoginMod = $this->getCon()->getModule_LoginGuard();
62
+ $sGasp = $oReq->post( $oLoginMod->getGaspKey() );
63
+ if ( empty( $sGasp ) ) {
64
+ throw new \Exception( 'GASP failed' );
65
+ }
66
+
67
+ if ( !$oOpts->getCanIpRequestAutoUnblock( $sIp ) ) {
68
+ throw new \Exception( 'IP already processed in the last 24hrs' );
69
+ }
70
+ $oMod->updateIpRequestAutoUnblockTs( $sIp );
71
+
72
+ ( new IPs\Lib\Ops\DeleteIp() )
73
+ ->setDbHandler( $oMod->getDbHandler_IPs() )
74
+ ->setIP( $sIp )
75
+ ->fromBlacklist();
76
+ Services::Response()->redirectToHome();
77
+ }
78
+
79
+ return false;
80
+ }
81
+
82
+ private function renderKillPage() {
83
+ /** @var \ICWP_WPSF_FeatureHandler_Ips $oMod */
84
+ $oMod = $this->getMod();
85
+ /** @var IPs\Options $oOpts */
86
+ $oOpts = $oMod->getOptions();
87
+ $oCon = $this->getCon();
88
+ $oLoginMod = $oCon->getModule_LoginGuard();
89
+
90
+ $sUniqId = 'uau'.uniqid();
91
+
92
+ $sIp = Services::IP()->getRequestIp();
93
+ $nTimeRemaining = max( floor( $oOpts->getAutoExpireTime()/60 ), 0 );
94
+ $aData = [
95
+ 'strings' => [
96
+ 'title' => sprintf( __( "You've been blocked by the %s plugin", 'wp-simple-firewall' ),
97
+ sprintf( '<a href="%s" target="_blank">%s</a>',
98
+ $oCon->getPluginSpec()[ 'meta' ][ 'url_repo_home' ],
99
+ $oCon->getHumanName()
100
+ )
101
+ ),
102
+ 'lines' => [
103
+ sprintf( __( 'Time remaining on black list: %s', 'wp-simple-firewall' ),
104
+ sprintf( _n( '%s minute', '%s minutes', $nTimeRemaining, 'wp-simple-firewall' ), $nTimeRemaining )
105
+ ),
106
+ sprintf( __( 'You tripped the security plugin defenses a total of %s times making you a suspect.', 'wp-simple-firewall' ), $oOpts->getOffenseLimit() ),
107
+ sprintf( __( 'If you believe this to be in error, please contact the site owner and quote your IP address below.', 'wp-simple-firewall' ) ),
108
+ ],
109
+ 'your_ip' => 'Your IP address',
110
+ 'unblock' => [
111
+ 'title' => __( 'Auto-Unblock Your IP', 'wp-simple-firewall' ),
112
+ 'you_can' => __( 'You can automatically unblock your IP address by clicking the button below.', 'wp-simple-firewall' ),
113
+ 'button' => __( 'Unblock My IP Address', 'wp-simple-firewall' ),
114
+ ],
115
+ ],
116
+ 'vars' => [
117
+ 'nonce' => $oMod->getNonceActionData( 'uau' ),
118
+ 'ip' => $sIp,
119
+ 'gasp_element' => $oMod->renderTemplate(
120
+ 'snippets/gasp_js.php',
121
+ [
122
+ 'sCbName' => $oLoginMod->getGaspKey(),
123
+ 'sLabel' => $oLoginMod->getTextImAHuman(),
124
+ 'sAlert' => $oLoginMod->getTextPleaseCheckBox(),
125
+ 'sMustJs' => __( 'You MUST enable Javascript to be able to login', 'wp-simple-firewall' ),
126
+ 'sUniqId' => $sUniqId,
127
+ 'sUniqElem' => 'icwp_wpsf_login_p'.$sUniqId,
128
+ 'strings' => [
129
+ 'loading' => __( 'Loading', 'wp-simple-firewall' )
130
+ ]
131
+ ]
132
+ ),
133
+ ],
134
+ 'flags' => [
135
+ 'is_autorecover' => $oOpts->isEnabledAutoUserRecover(),
136
+ 'is_uau_permitted' => $oOpts->getCanIpRequestAutoUnblock( $sIp ),
137
+ ],
138
+ ];
139
+ Services::WpGeneral()
140
+ ->wpDie(
141
+ $oMod->renderTemplate( '/snippets/blacklist_die.twig', $aData, true )
142
+ );
143
+ }
144
+ }
src/lib/src/Modules/IPs/Lib/Ops/AddIp.php CHANGED
@@ -2,8 +2,8 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Ops;
4
 
5
- use FernleafSystems\Wordpress\Plugin\Shield\Modules;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Databases;
 
7
  use FernleafSystems\Wordpress\Services\Services;
8
 
9
  /**
@@ -17,17 +17,24 @@ class AddIp {
17
 
18
  /**
19
  * @return Databases\IPs\EntryVO|null
 
20
  */
21
  public function toAutoBlacklist() {
22
  /** @var \ICWP_WPSF_FeatureHandler_Ips $oMod */
23
  $oMod = $this->getMod();
 
 
 
 
 
 
24
 
25
  $oIP = null;
26
- if ( !in_array( $this->getIP(), Services::IP()->getServerPublicIPs() ) ) {
27
  $oIP = ( new LookupIpOnList() )
28
  ->setDbHandler( $oMod->getDbHandler_IPs() )
29
  ->setListTypeBlack()
30
- ->setIP( $this->getIP() )
31
  ->lookup( false );
32
  if ( !$oIP instanceof Databases\IPs\EntryVO ) {
33
  $oIP = $this->add( $oMod::LIST_AUTO_BLACK, 'auto' );
@@ -45,18 +52,32 @@ class AddIp {
45
  /**
46
  * @param string $sLabel
47
  * @return Databases\IPs\EntryVO|null
 
48
  */
49
  public function toManualBlacklist( $sLabel = '' ) {
50
  /** @var \ICWP_WPSF_FeatureHandler_Ips $oMod */
51
  $oMod = $this->getMod();
 
 
 
 
 
 
52
 
53
  $oIP = null;
54
- if ( !in_array( $this->getIP(), Services::IP()->getServerPublicIPs() ) ) {
 
 
 
 
 
 
 
55
 
56
  $oIP = ( new LookupIpOnList() )
57
  ->setDbHandler( $oMod->getDbHandler_IPs() )
58
  ->setListTypeBlack()
59
- ->setIP( $this->getIP() )
60
  ->lookup( false );
61
 
62
  if ( !$oIP instanceof Databases\IPs\EntryVO ) {
@@ -88,10 +109,25 @@ class AddIp {
88
  /**
89
  * @param string $sLabel
90
  * @return Databases\IPs\EntryVO|null
 
91
  */
92
  public function toManualWhitelist( $sLabel = '' ) {
93
  /** @var \ICWP_WPSF_FeatureHandler_Ips $oMod */
94
  $oMod = $this->getMod();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  $oIP = ( new LookupIpOnList() )
96
  ->setDbHandler( $oMod->getDbHandler_IPs() )
97
  ->setIP( $this->getIP() )
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Ops;
4
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Databases;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules;
7
  use FernleafSystems\Wordpress\Services\Services;
8
 
9
  /**
17
 
18
  /**
19
  * @return Databases\IPs\EntryVO|null
20
+ * @throws \Exception
21
  */
22
  public function toAutoBlacklist() {
23
  /** @var \ICWP_WPSF_FeatureHandler_Ips $oMod */
24
  $oMod = $this->getMod();
25
+ $oIpServ = Services::IP();
26
+
27
+ $sIP = $this->getIP();
28
+ if ( !$oIpServ->isValidIp( $sIP ) ) {
29
+ throw new \Exception( 'IP address is not valid' );
30
+ }
31
 
32
  $oIP = null;
33
+ if ( !in_array( $sIP, Services::IP()->getServerPublicIPs() ) ) {
34
  $oIP = ( new LookupIpOnList() )
35
  ->setDbHandler( $oMod->getDbHandler_IPs() )
36
  ->setListTypeBlack()
37
+ ->setIP( $sIP )
38
  ->lookup( false );
39
  if ( !$oIP instanceof Databases\IPs\EntryVO ) {
40
  $oIP = $this->add( $oMod::LIST_AUTO_BLACK, 'auto' );
52
  /**
53
  * @param string $sLabel
54
  * @return Databases\IPs\EntryVO|null
55
+ * @throws \Exception
56
  */
57
  public function toManualBlacklist( $sLabel = '' ) {
58
  /** @var \ICWP_WPSF_FeatureHandler_Ips $oMod */
59
  $oMod = $this->getMod();
60
+ $oIpServ = Services::IP();
61
+
62
+ $sIP = $this->getIP();
63
+ if ( !$oIpServ->isValidIp( $sIP ) && !$oIpServ->isValidIpRange( $sIP ) ) {
64
+ throw new \Exception( 'IP address is not valid' );
65
+ }
66
 
67
  $oIP = null;
68
+ if ( !in_array( $sIP, $oIpServ->getServerPublicIPs() ) ) {
69
+
70
+ if ( $oIpServ->isValidIpRange( $sIP ) ) {
71
+ ( new DeleteIp() )
72
+ ->setDbHandler( $oMod->getDbHandler_IPs() )
73
+ ->setIP( $sIP )
74
+ ->fromBlacklist();
75
+ }
76
 
77
  $oIP = ( new LookupIpOnList() )
78
  ->setDbHandler( $oMod->getDbHandler_IPs() )
79
  ->setListTypeBlack()
80
+ ->setIP( $sIP )
81
  ->lookup( false );
82
 
83
  if ( !$oIP instanceof Databases\IPs\EntryVO ) {
109
  /**
110
  * @param string $sLabel
111
  * @return Databases\IPs\EntryVO|null
112
+ * @throws \Exception
113
  */
114
  public function toManualWhitelist( $sLabel = '' ) {
115
  /** @var \ICWP_WPSF_FeatureHandler_Ips $oMod */
116
  $oMod = $this->getMod();
117
+ $oIpServ = Services::IP();
118
+
119
+ $sIP = $this->getIP();
120
+ if ( !$oIpServ->isValidIp( $sIP ) && !$oIpServ->isValidIpRange( $sIP ) ) {
121
+ throw new \Exception( 'IP address is not valid' );
122
+ }
123
+
124
+ if ( $oIpServ->isValidIpRange( $sIP ) ) {
125
+ ( new DeleteIp() )
126
+ ->setDbHandler( $oMod->getDbHandler_IPs() )
127
+ ->setIP( $sIP )
128
+ ->fromWhiteList();
129
+ }
130
+
131
  $oIP = ( new LookupIpOnList() )
132
  ->setDbHandler( $oMod->getDbHandler_IPs() )
133
  ->setIP( $this->getIP() )
src/lib/src/Modules/IPs/Lib/Ops/LookupIpOnList.php CHANGED
@@ -24,10 +24,11 @@ class LookupIpOnList {
24
  /**
25
  * @param bool $bIncludeRanges
26
  * @return Databases\IPs\EntryVO|null
 
27
  */
28
  public function lookup( $bIncludeRanges = true ) {
29
- $oIp = $this->lookupIp();
30
- if ( $bIncludeRanges && !$oIp instanceof Databases\IPs\EntryVO ) {
31
  foreach ( $this->lookupRange() as $oMaybeIp ) {
32
  try {
33
  if ( Services::IP()->checkIp( $this->getIP(), $oMaybeIp->ip ) ) {
@@ -39,7 +40,7 @@ class LookupIpOnList {
39
  }
40
  }
41
  }
42
- return $oIp;
43
  }
44
 
45
  /**
@@ -123,21 +124,4 @@ class LookupIpOnList {
123
  $this->sListType = 'white';
124
  return $this;
125
  }
126
-
127
- /**
128
- * @return string
129
- * @deprecated 8.5
130
- */
131
- public function getList() {
132
- return '';
133
- }
134
-
135
- /**
136
- * @param string $sList
137
- * @return $this
138
- * @deprecated 8.5
139
- */
140
- public function setList( $sList ) {
141
- return $this;
142
- }
143
  }
24
  /**
25
  * @param bool $bIncludeRanges
26
  * @return Databases\IPs\EntryVO|null
27
+ * @version 8.6.0 - switched to lookup ranges first
28
  */
29
  public function lookup( $bIncludeRanges = true ) {
30
+ $oIp = null;
31
+ if ( $bIncludeRanges ) {
32
  foreach ( $this->lookupRange() as $oMaybeIp ) {
33
  try {
34
  if ( Services::IP()->checkIp( $this->getIP(), $oMaybeIp->ip ) ) {
40
  }
41
  }
42
  }
43
+ return ( $oIp instanceof Databases\IPs\EntryVO ) ? $oIp : $this->lookupIp();
44
  }
45
 
46
  /**
124
  $this->sListType = 'white';
125
  return $this;
126
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  }
src/lib/src/Modules/License/AdminNotices.php ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\License;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
+
8
+ class AdminNotices extends Shield\Modules\Base\AdminNotices {
9
+
10
+ /**
11
+ * @param Shield\Utilities\AdminNotices\NoticeVO $oNotice
12
+ * @throws \Exception
13
+ */
14
+ protected function processNotice( $oNotice ) {
15
+ switch ( $oNotice->id ) {
16
+ case 'wphashes-token-fail':
17
+ $this->buildNotice_WpHashesTokenFailure( $oNotice );
18
+ break;
19
+ default:
20
+ parent::processNotice( $oNotice );
21
+ break;
22
+ }
23
+ }
24
+
25
+ /**
26
+ * @param Shield\Utilities\AdminNotices\NoticeVO $oNotice
27
+ */
28
+ private function buildNotice_WpHashesTokenFailure( $oNotice ) {
29
+ $oNotice->render_data = [
30
+ 'notice_attributes' => [],
31
+ 'strings' => [
32
+ 'title' => sprintf( '%s: %s', __( 'Warning', 'wp-simple-firewall' ),
33
+ sprintf( __( '%s API Token Missing', 'wp-simple-firewall' ), 'WPHashes.com' ) ),
34
+ 'messages' => [
35
+ __( "This site appears to be activated for PRO, but there's been a problem obtaining an API token for WPHashes.com.", 'wp-simple-firewall' ),
36
+ implode( ' ', [
37
+ __( 'The WPHashes API is used for many premium features including Malware scanning.', 'wp-simple-firewall' ),
38
+ __( 'Without a valid API Token, certain Premium features wont work as expected.', 'wp-simple-firewall' ),
39
+ ] ),
40
+ __( "Please contact us in our support channel if this doesn't sound right, or upgrade to PRO.", 'wp-simple-firewall' ),
41
+ ],
42
+ 'jump_to_support' => __( 'Click to jump to the relevant option', 'wp-simple-firewall' )
43
+ ],
44
+ 'hrefs' => [
45
+ 'jump_to_support' => $this->getMod()->getUrl_DirectLinkToSection( 'global_enable_plugin_features' )
46
+ ]
47
+ ];
48
+ }
49
+
50
+ /**
51
+ * @param Shield\Utilities\AdminNotices\NoticeVO $oNotice
52
+ * @return bool
53
+ */
54
+ protected function isDisplayNeeded( $oNotice ) {
55
+ $oCon = $this->getCon();
56
+ /** @var \ICWP_WPSF_FeatureHandler_License $oMod */
57
+ $oMod = $this->getMod();
58
+
59
+ switch ( $oNotice->id ) {
60
+
61
+ case 'wphashes-token-fail':
62
+ $bNeeded = $oCon->isPremiumActive() && !$oMod->getWpHashesTokenManager()->hasToken()
63
+ && ( Services::Request()->ts() > 1583712000 ); // @deprecated 8.6.3 i.e. remove it
64
+ break;
65
+
66
+ default:
67
+ $bNeeded = parent::isDisplayNeeded( $oNotice );
68
+ break;
69
+ }
70
+ return $bNeeded;
71
+ }
72
+ }
src/lib/src/Modules/License/AjaxHandler.php CHANGED
@@ -4,6 +4,7 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\License;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield;
6
  use FernleafSystems\Wordpress\Services\Services;
 
7
 
8
  class AjaxHandler extends Shield\Modules\Base\AjaxHandlerShield {
9
 
@@ -32,39 +33,26 @@ class AjaxHandler extends Shield\Modules\Base\AjaxHandlerShield {
32
  * @return array
33
  */
34
  private function ajaxExec_ConnectionDebug() {
35
- /** @var \ICWP_WPSF_FeatureHandler_License $oMod */
36
- $oMod = $this->getMod();
37
- $bSuccess = false;
 
 
 
 
38
 
39
- $oHttpReq = Services::HttpRequest()
40
- ->request(
41
- add_query_arg( [ 'license_ping' => 'Y' ], $oMod->getLicenseStoreUrl() ),
42
- [
43
- 'body' => [ 'ping' => 'pong' ]
44
- ],
45
- 'POST'
46
- );
47
-
48
- if ( !$oHttpReq->isSuccess() ) {
49
- $sResult = implode( '; ', $oHttpReq->lastError->get_error_messages() );
50
  }
51
- elseif ( !empty( $oHttpReq->lastResponse->body ) ) {
52
- $aResult = @json_decode( $oHttpReq->lastResponse->body, true );
53
- if ( isset( $aResult[ 'success' ] ) && $aResult[ 'success' ] ) {
54
- $bSuccess = true;
55
- $sResult = 'Successful - no problems detected communicating with license server.';
56
- }
57
- else {
58
- $sResult = 'Unknown failure due to unexpected response: '.$oHttpReq->lastResponse->body;
59
- }
60
  }
61
  else {
62
- $sResult = 'Unknown error as we could not get a response back from the server.';
63
  }
64
-
65
  return [
66
  'success' => $bSuccess,
67
- 'message' => $sResult
68
  ];
69
  }
70
 
@@ -74,6 +62,7 @@ class AjaxHandler extends Shield\Modules\Base\AjaxHandlerShield {
74
  private function ajaxExec_LicenseHandling() {
75
  /** @var \ICWP_WPSF_FeatureHandler_License $oMod */
76
  $oMod = $this->getMod();
 
77
 
78
  $bSuccess = false;
79
  $sMessage = 'Unsupported license action';
@@ -82,14 +71,14 @@ class AjaxHandler extends Shield\Modules\Base\AjaxHandlerShield {
82
 
83
  if ( $sLicenseAction == 'clear' ) {
84
  $bSuccess = true;
85
- $oMod->deactivate( 'cleared' );
86
- $oMod->clearLicenseData();
87
  $sMessage = __( 'Success', 'wp-simple-firewall' ).'! '
88
  .__( 'Reloading page', 'wp-simple-firewall' ).'...';
89
  }
90
  elseif ( $sLicenseAction == 'check' ) {
91
 
92
- $nCheckInterval = $oMod->getLicenseNotCheckedForInterval();
93
  if ( $nCheckInterval < 20 ) {
94
  $nWait = 20 - $nCheckInterval;
95
  $sMessage = sprintf(
@@ -98,9 +87,14 @@ class AjaxHandler extends Shield\Modules\Base\AjaxHandlerShield {
98
  );
99
  }
100
  else {
101
- $bSuccess = $oMod->verifyLicense( true )
102
- ->hasValidWorkingLicense();
103
- $sMessage = $bSuccess ? __( 'Valid license found.', 'wp-simple-firewall' ) : __( "Valid license couldn't be found.", 'wp-simple-firewall' );
 
 
 
 
 
104
  }
105
  }
106
 
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield;
6
  use FernleafSystems\Wordpress\Services\Services;
7
+ use FernleafSystems\Wordpress\Services\Utilities\Licenses\Keyless;
8
 
9
  class AjaxHandler extends Shield\Modules\Base\AjaxHandlerShield {
10
 
33
  * @return array
34
  */
35
  private function ajaxExec_ConnectionDebug() {
36
+ $oIP = Services::IP();
37
+
38
+ $oPing = new Keyless\Ping();
39
+ $oPing->lookup_url_stub = $this->getOptions()->getDef( 'license_store_url_api' );
40
+ $bSuccess = $oPing->ping();
41
+
42
+ $sHost = wp_parse_url( $oPing->lookup_url_stub, PHP_URL_HOST );
43
 
44
+ if ( $bSuccess ) {
45
+ $sMessage = 'Successfully connected to license server.';
 
 
 
 
 
 
 
 
 
46
  }
47
+ elseif ( !$oIP->isValidIp( gethostbyname( $sHost ) ) ) {
48
+ $sMessage = sprintf( 'Could not resolve host IP address: %s', $sHost );
 
 
 
 
 
 
 
49
  }
50
  else {
51
+ $sMessage = 'Failed to connect to license server.';
52
  }
 
53
  return [
54
  'success' => $bSuccess,
55
+ 'message' => $sMessage
56
  ];
57
  }
58
 
62
  private function ajaxExec_LicenseHandling() {
63
  /** @var \ICWP_WPSF_FeatureHandler_License $oMod */
64
  $oMod = $this->getMod();
65
+ $sHandler = $oMod->getLicenseHandler();
66
 
67
  $bSuccess = false;
68
  $sMessage = 'Unsupported license action';
71
 
72
  if ( $sLicenseAction == 'clear' ) {
73
  $bSuccess = true;
74
+ $sHandler->deactivate( false );
75
+ $sHandler->clearLicense();
76
  $sMessage = __( 'Success', 'wp-simple-firewall' ).'! '
77
  .__( 'Reloading page', 'wp-simple-firewall' ).'...';
78
  }
79
  elseif ( $sLicenseAction == 'check' ) {
80
 
81
+ $nCheckInterval = $sHandler->getLicenseNotCheckedForInterval();
82
  if ( $nCheckInterval < 20 ) {
83
  $nWait = 20 - $nCheckInterval;
84
  $sMessage = sprintf(
87
  );
88
  }
89
  else {
90
+ try {
91
+ $bSuccess = $sHandler->verify( true )
92
+ ->hasValidWorkingLicense();
93
+ $sMessage = $bSuccess ? __( 'Valid license found.', 'wp-simple-firewall' ) : __( "Valid license couldn't be found.", 'wp-simple-firewall' );
94
+ }
95
+ catch ( \Exception $oE ) {
96
+ $sMessage = $oE->getMessage();
97
+ }
98
  }
99
  }
100
 
src/lib/src/Modules/License/Lib/LicenseEmails.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\License\Lib;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
+
8
+ class LicenseEmails {
9
+
10
+ use ModConsumer;
11
+
12
+ public function sendLicenseWarningEmail() {
13
+ /** @var \ICWP_WPSF_FeatureHandler_License $oMod */
14
+ $oMod = $this->getMod();
15
+ $oOpts = $this->getOptions();
16
+
17
+ $bCanSend = Services::Request()
18
+ ->carbon()
19
+ ->subDay( 1 )->timestamp > $oOpts->getOpt( 'last_warning_email_sent_at' );
20
+
21
+ if ( $bCanSend ) {
22
+ $oOpts->setOptAt( 'last_warning_email_sent_at' );
23
+ $oMod->saveModOptions();
24
+
25
+ $aMessage = [
26
+ __( 'Attempts to verify Shield Pro license has just failed.', 'wp-simple-firewall' ),
27
+ sprintf( __( 'Please check your license on-site: %s', 'wp-simple-firewall' ), $oMod->getUrl_AdminPage() ),
28
+ sprintf( __( 'If this problem persists, please contact support: %s', 'wp-simple-firewall' ), 'https://support.onedollarplugin.com/' )
29
+ ];
30
+ $oMod->getEmailProcessor()
31
+ ->sendEmailWithWrap(
32
+ $oMod->getPluginDefaultRecipientAddress(),
33
+ 'Pro License Check Has Failed',
34
+ $aMessage
35
+ );
36
+ $this->getCon()->fireEvent( 'lic_fail_email' );
37
+ }
38
+ }
39
+
40
+ public function sendLicenseDeactivatedEmail() {
41
+ /** @var \ICWP_WPSF_FeatureHandler_License $oMod */
42
+ $oMod = $this->getMod();
43
+ $oOpts = $this->getOptions();
44
+
45
+ $bCanSend = Services::Request()
46
+ ->carbon()
47
+ ->subDay( 1 )->timestamp > $oOpts->getOpt( 'last_deactivated_email_sent_at' );
48
+
49
+ if ( $bCanSend ) {
50
+ $oOpts->setOptAt( 'last_deactivated_email_sent_at' );
51
+ $oMod->saveModOptions();
52
+
53
+ $aMessage = [
54
+ __( 'All attempts to verify Shield Pro license have failed.', 'wp-simple-firewall' ),
55
+ sprintf( __( 'Please check your license on-site: %s', 'wp-simple-firewall' ), $oMod->getUrl_AdminPage() ),
56
+ sprintf( __( 'If this problem persists, please contact support: %s', 'wp-simple-firewall' ), 'https://support.onedollarplugin.com/' )
57
+ ];
58
+ $oMod->getEmailProcessor()
59
+ ->sendEmailWithWrap(
60
+ $oMod->getPluginDefaultRecipientAddress(),
61
+ '[Action May Be Required] Pro License Has Been Deactivated',
62
+ $aMessage
63
+ );
64
+ }
65
+ }
66
+ }
src/lib/src/Modules/License/Lib/LicenseHandler.php ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
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\ModConsumer;
7
+ use FernleafSystems\Wordpress\Services\Services;
8
+
9
+ class LicenseHandler {
10
+
11
+ use ModConsumer;
12
+
13
+ /**
14
+ * @return bool
15
+ */
16
+ private function canCheck() {
17
+ return !in_array( $this->getCon()->getShieldAction(), [ 'keyless_handshake', 'license_check' ] )
18
+ && $this->getIsLicenseNotCheckedFor( 20 )
19
+ && $this->canLicenseCheck_FileFlag();
20
+ }
21
+
22
+ /**
23
+ * @return $this
24
+ */
25
+ public function clearLicense() {
26
+ $this->getMod()->clearLastErrors();
27
+ $this->getOptions()->setOpt( 'license_data', [] );
28
+ return $this;
29
+ }
30
+
31
+ /**
32
+ * @param bool $bSendEmail
33
+ */
34
+ public function deactivate( $bSendEmail = true ) {
35
+ if ( $this->isActive() ) {
36
+ $this->clearLicense();
37
+ $this->getOptions()->setOptAt( 'license_deactivated_at' );
38
+ if ( $bSendEmail ) {
39
+ ( new LicenseEmails() )
40
+ ->setMod( $this->getMod() )
41
+ ->sendLicenseDeactivatedEmail();
42
+ }
43
+ $this->getCon()->fireEvent( 'lic_fail_deactivate' );
44
+ }
45
+ // force all options to resave i.e. reset premium to defaults.
46
+ add_filter( $this->getCon()->prefix( 'force_options_resave' ), '__return_true' );
47
+ }
48
+
49
+ /**
50
+ * @return int
51
+ */
52
+ protected function getActivatedAt() {
53
+ return $this->getOptions()->getOpt( 'license_activated_at' );
54
+ }
55
+
56
+ /**
57
+ * @return int
58
+ */
59
+ protected function getDeactivatedAt() {
60
+ return $this->getOptions()->getOpt( 'license_deactivated_at' );
61
+ }
62
+
63
+ /**
64
+ * @return EddLicenseVO
65
+ */
66
+ public function getLicense() {
67
+ $aData = $this->getOptions()->getOpt( 'license_data', [] );
68
+ return ( new EddLicenseVO() )->applyFromArray( is_array( $aData ) ? $aData : [] );
69
+ }
70
+
71
+ /**
72
+ * @return int
73
+ */
74
+ public function getLicenseNotCheckedForInterval() {
75
+ return Services::Request()->ts() - $this->getOptions()->getOpt( 'license_last_checked_at' );
76
+ }
77
+
78
+ /**
79
+ * Use the grace period (currently 3 days) to adjust when the license registration
80
+ * expires on this site. We consider a registration as expired if the last verified
81
+ * date is past, or the actual license is expired - whichever happens earlier -
82
+ * plus the grace period.
83
+ * @return int
84
+ */
85
+ public function getRegistrationExpiresAt() {
86
+ /** @var \ICWP_WPSF_FeatureHandler_License $oMod */
87
+ $oMod = $this->getMod();
88
+ $oOpts = $this->getOptions();
89
+
90
+ $nVerifiedExpiredDays = $oOpts->getDef( 'lic_verify_expire_days' )
91
+ + $oOpts->getDef( 'lic_verify_expire_grace_days' );
92
+
93
+ $oLic = $oMod->getLicenseHandler()->getLicense();
94
+ return (int)min(
95
+ $oLic->getExpiresAt() + $oOpts->getDef( 'lic_verify_expire_grace_days' )*DAY_IN_SECONDS,
96
+ $oLic->last_verified_at + $nVerifiedExpiredDays*DAY_IN_SECONDS
97
+ );
98
+ }
99
+
100
+ /**
101
+ * IMPORTANT: Method used by Shield Central. Modify with care.
102
+ * We test various data points:
103
+ * 1) the key is valid format
104
+ * 2) the official license status is 'valid'
105
+ * 3) the license is marked as "active"
106
+ * 4) the license hasn't expired
107
+ * 5) the time since the last check hasn't expired
108
+ * @return bool
109
+ */
110
+ public function hasValidWorkingLicense() {
111
+ $oLic = $this->getLicense();
112
+ return $oLic->isValid() && $this->isActive();
113
+ }
114
+
115
+ /**
116
+ * @return bool
117
+ */
118
+ public function isActive() {
119
+ return ( $this->getActivatedAt() > 0 )
120
+ && ( $this->getDeactivatedAt() < $this->getActivatedAt() );
121
+ }
122
+
123
+ /**
124
+ * @return bool
125
+ */
126
+ public function isLastVerifiedExpired() {
127
+ return ( Services::Request()->ts() - $this->getLicense()->last_verified_at )
128
+ > $this->getOptions()->getDef( 'lic_verify_expire_days' )*DAY_IN_SECONDS;
129
+ }
130
+
131
+ /**
132
+ * @return bool
133
+ */
134
+ public function isLastVerifiedGraceExpired() {
135
+ $oOpts = $this->getOptions();
136
+ $nGracePeriod = ( $oOpts->getDef( 'lic_verify_expire_days' )
137
+ + $oOpts->getDef( 'lic_verify_expire_grace_days' ) )*DAY_IN_SECONDS;
138
+ return ( Services::Request()->ts() - $this->getLicense()->last_verified_at ) > $nGracePeriod;
139
+ }
140
+
141
+ /**
142
+ * @return bool
143
+ */
144
+ private function isMaybeExpiring() {
145
+ return $this->isActive() &&
146
+ (
147
+ abs( Services::Request()->ts() - $this->getLicense()->getExpiresAt() )
148
+ < ( DAY_IN_SECONDS/2 )
149
+ );
150
+ }
151
+
152
+ /**
153
+ * @return bool
154
+ */
155
+ public function isWithinVerifiedGraceExpired() {
156
+ return $this->isLastVerifiedExpired() && !$this->isLastVerifiedGraceExpired();
157
+ }
158
+
159
+ /**
160
+ * @return bool
161
+ */
162
+ private function isVerifyRequired() {
163
+ return ( $this->isMaybeExpiring() && $this->getIsLicenseNotCheckedFor( HOUR_IN_SECONDS*4 ) )
164
+ || ( $this->isActive()
165
+ && !$this->getLicense()->isReady() && $this->getIsLicenseNotCheckedFor( HOUR_IN_SECONDS ) )
166
+ || ( $this->hasValidWorkingLicense() && $this->isLastVerifiedExpired()
167
+ && $this->getIsLicenseNotCheckedFor( HOUR_IN_SECONDS*4 ) );
168
+ }
169
+
170
+ /**
171
+ * @param bool $bForceCheck
172
+ * @return $this
173
+ * @throws \Exception
174
+ */
175
+ public function verify( $bForceCheck = true ) {
176
+ if ( $bForceCheck || ( $this->isVerifyRequired() && $this->canCheck() ) ) {
177
+ ( new Verify() )
178
+ ->setMod( $this->getMod() )
179
+ ->run();
180
+ }
181
+ return $this;
182
+ }
183
+
184
+ /**
185
+ * @param int $nTimePeriod
186
+ * @return bool
187
+ */
188
+ private function getIsLicenseNotCheckedFor( $nTimePeriod ) {
189
+ return $this->getLicenseNotCheckedForInterval() > $nTimePeriod;
190
+ }
191
+
192
+ /**
193
+ * @return bool
194
+ */
195
+ private function canLicenseCheck_FileFlag() {
196
+ $nMtime = (int)Services::WpFs()->getModifiedTime(
197
+ $this->getCon()->getPath_Flags( 'license_check' )
198
+ );
199
+ return ( Services::Request()->ts() - $nMtime ) > MINUTE_IN_SECONDS;
200
+ }
201
+ }
src/lib/src/Modules/License/Lib/LookupRequest.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\License\Lib;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
+ use FernleafSystems\Wordpress\Services\Utilities\Licenses\Keyless\Lookup;
8
+
9
+ class LookupRequest {
10
+
11
+ use ModConsumer;
12
+
13
+ /**
14
+ * @return \FernleafSystems\Wordpress\Services\Utilities\Licenses\EddLicenseVO
15
+ */
16
+ public function lookup() {
17
+ $oCon = $this->getCon();
18
+ $oOpts = $this->getOptions();
19
+
20
+ $sPass = wp_generate_password( 16, false );
21
+ $sUrl = Services::WpGeneral()->getHomeUrl( '', true );
22
+
23
+ $this->setKeylessHandshakeNonce( sha1( $sPass.$sUrl ) );
24
+
25
+ {
26
+ $oLook = new Lookup();
27
+ $oLook->lookup_url_stub = $oOpts->getDef( 'license_store_url_api' );
28
+ $oLook->item_id = $oOpts->getDef( 'license_item_id' );
29
+ $oLook->install_id = $oCon->getSiteInstallationId();
30
+ $oLook->url = $sUrl;
31
+ $oLook->nonce = $sPass;
32
+ $oLook->meta = [
33
+ 'version_shield' => $oCon->getVersion(),
34
+ 'version_php' => Services::Data()->getPhpVersionCleaned()
35
+ ];
36
+ $oLicense = $oLook->lookup();
37
+ }
38
+
39
+ // clear the handshake data after the request has gone through
40
+ $this->setKeylessHandshakeNonce( '' );
41
+
42
+ return $oLicense;
43
+ }
44
+
45
+ /**
46
+ * @param string $sNonce - empty string to clear the nonce
47
+ */
48
+ private function setKeylessHandshakeNonce( $sNonce = '' ) {
49
+ $oOpts = $this->getOptions();
50
+ $oOpts->setOpt( 'keyless_handshake_hash', $sNonce )
51
+ ->setOpt( 'keyless_handshake_until',
52
+ empty( $sNonce ) ? 0 : Services::Request()->ts() + $oOpts->getDef( 'keyless_handshake_expire' )
53
+ );
54
+ $this->getMod()->saveModOptions();
55
+ }
56
+ }
src/lib/src/Modules/License/Lib/Verify.php ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\License\Lib;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\License;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
+ use FernleafSystems\Wordpress\Services\Services;
8
+
9
+ class Verify {
10
+
11
+ use ModConsumer;
12
+
13
+ /**
14
+ * @throws \Exception
15
+ */
16
+ public function run() {
17
+ $oCon = $this->getCon();
18
+ /** @var \ICWP_WPSF_FeatureHandler_License $oMod */
19
+ $oMod = $this->getMod();
20
+ /** @var License\Options $oOpts */
21
+ $oOpts = $this->getOptions();
22
+ $oHandler = $oMod->getLicenseHandler();
23
+
24
+ $this->preVerify();
25
+
26
+ $oExisting = $oHandler->getLicense();
27
+
28
+ $oLookupLicense = ( new LookupRequest() )
29
+ ->setMod( $oMod )
30
+ ->lookup();
31
+
32
+ $bSuccessfulApiRequest = false;
33
+
34
+ if ( $oLookupLicense->isValid() ) {
35
+ $bSuccessfulApiRequest = true;
36
+ $oExisting = $oLookupLicense;
37
+ $oExisting->updateLastVerifiedAt( true );
38
+ if ( !$oHandler->isActive() ) {
39
+ $oOpts->setOptAt( 'license_activated_at' );
40
+ }
41
+ $oMod->clearLastErrors();
42
+ $oOpts->setOpt( 'license_data', $oExisting->getRawDataAsArray() ); // need to do this before event
43
+ $oCon->fireEvent( 'lic_check_success' );
44
+ }
45
+ elseif ( $oLookupLicense->isReady() ) {
46
+ $bSuccessfulApiRequest = true;
47
+ // License lookup failed but request was successful - so use what we get
48
+ $oHandler->deactivate();
49
+ $oExisting = $oHandler->getLicense();
50
+ }
51
+ elseif ( $oExisting->isReady() ) { // Has a stored license but license HTTP request failed
52
+
53
+ $oMod->setLastErrors( [
54
+ __( 'The most recent request to verify the site license encountered a problem.', 'wp-simple-firewall' )
55
+ ] );
56
+
57
+ if ( Services::Request()->ts() > $oHandler->getRegistrationExpiresAt() ) {
58
+ $oHandler->deactivate();
59
+ $oExisting = $oHandler->getLicense();
60
+ }
61
+ elseif ( $oHandler->isLastVerifiedExpired() ) {
62
+ /**
63
+ * At this stage we have a license stored, but we couldn't
64
+ * verify it, but we're within the grace period for checking.
65
+ *
66
+ * We don't remove the license yet, but we warn the user
67
+ */
68
+ ( new LicenseEmails() )
69
+ ->setMod( $oMod )
70
+ ->sendLicenseWarningEmail();
71
+ }
72
+ }
73
+ else { // all else fails, clear any license details entirely
74
+ $oHandler->clearLicense();
75
+ $oExisting = $oHandler->getLicense();
76
+ }
77
+
78
+ $oExisting->last_request_at = Services::Request()->ts();
79
+ $oOpts->setOpt( 'license_data', $oExisting->getRawDataAsArray() );
80
+ $this->getMod()->saveModOptions();
81
+
82
+ if ( !$bSuccessfulApiRequest ) {
83
+ throw new \Exception( 'License API HTTP Request Failed.' );
84
+ }
85
+ }
86
+
87
+ private function preVerify() {
88
+ /** @var License\Options $oOpts */
89
+ $oOpts = $this->getOptions();
90
+ Services::WpFs()->touch( $this->getCon()->getPath_Flags( 'license_check' ) );
91
+ $oOpts->setOptAt( 'license_last_checked_at' );
92
+ $this->getMod()->saveModOptions();
93
+ }
94
+ }
src/lib/src/Modules/License/Lib/WpHashes/ApiTokenManager.php ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\License\Lib\WpHashes;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
+ use FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes\Token;
8
+
9
+ class ApiTokenManager {
10
+
11
+ use ModConsumer;
12
+
13
+ /**
14
+ * @var bool
15
+ */
16
+ private $bCanRequestOverride = false;
17
+
18
+ public function run() {
19
+ add_action( $this->getCon()->prefix( 'event' ), function ( $sEventTag ) {
20
+ switch ( $sEventTag ) {
21
+ case 'lic_check_success':
22
+ $this->setCanRequestOverride( true )->getToken();
23
+ break;
24
+ case 'lic_fail_deactivate':
25
+ $this->storeToken( [] );
26
+ break;
27
+ default:
28
+ break;
29
+ }
30
+ } );
31
+ }
32
+
33
+ /**
34
+ * @return bool
35
+ */
36
+ public function hasToken() {
37
+ $sTok = $this->getTheToken();
38
+ return strlen( $sTok ) == 40 && !$this->isExpired();
39
+ }
40
+
41
+ /**
42
+ * @return string
43
+ */
44
+ public function getToken() {
45
+
46
+ if ( $this->getCon()->getModule_License()->getLicenseHandler()->getLicense()->isValid() ) {
47
+ $aT = $this->loadToken();
48
+ if ( $this->isExpired() && $this->canRequestNewToken() ) {
49
+ $aT = $this->loadToken();
50
+ try {
51
+ $aT = array_merge( $aT, $this->solicitApiToken() );
52
+ }
53
+ catch ( \Exception $oE ) {
54
+ }
55
+ $aT[ 'attempt_at' ] = Services::Request()->ts();
56
+ $this->storeToken( $aT );
57
+ }
58
+ }
59
+ else {
60
+ $this->storeToken( [] );
61
+ }
62
+
63
+ return empty( $aT[ 'token' ] ) ? '' : $aT[ 'token' ];
64
+ }
65
+
66
+ /**
67
+ * @return string
68
+ */
69
+ private function getTheToken() {
70
+ return $this->loadToken()[ 'token' ];
71
+ }
72
+
73
+ /**
74
+ * @return array - return Token exactly as it's saved currently
75
+ */
76
+ private function loadToken() {
77
+ return array_merge(
78
+ [
79
+ 'token' => '',
80
+ 'expires_at' => 0,
81
+ 'attempt_at' => 0,
82
+ 'valid_license' => false,
83
+ ],
84
+ $this->getOptions()->getOpt( 'wphashes_api_token', [] )
85
+ );
86
+ }
87
+
88
+ /**
89
+ * @return bool
90
+ */
91
+ private function canRequestNewToken() {
92
+ return $this->getCanRequestOverride() ||
93
+ (
94
+ Services::Request()->carbon()->subHours( 6 )->timestamp > $this->loadToken()[ 'attempt_at' ]
95
+ && $this->getCon()->getModule_License()->getLicenseHandler()->getLicense()->isValid()
96
+ );
97
+ }
98
+
99
+ /**
100
+ * @return bool
101
+ */
102
+ public function getCanRequestOverride() {
103
+ return (bool)$this->bCanRequestOverride;
104
+ }
105
+
106
+ /**
107
+ * @return bool
108
+ */
109
+ public function isExpired() {
110
+ return Services::Request()->ts() > $this->loadToken()[ 'expires_at' ];
111
+ }
112
+
113
+ /**
114
+ * @param array $aToken
115
+ * @return $this
116
+ */
117
+ private function storeToken( array $aToken = [] ) {
118
+ $this->getOptions()->setOpt( 'wphashes_api_token', $aToken );
119
+ return $this;
120
+ }
121
+
122
+ /**
123
+ * @param bool $bCanRequest
124
+ * @return $this
125
+ */
126
+ public function setCanRequestOverride( $bCanRequest ) {
127
+ $this->bCanRequestOverride = (bool)$bCanRequest;
128
+ return $this;
129
+ }
130
+
131
+ /**
132
+ * @return array
133
+ * @throws \Exception
134
+ */
135
+ private function solicitApiToken() {
136
+ $aResp = ( new Token\Solicit() )->retrieve(
137
+ Services::WpGeneral()->getHomeUrl(),
138
+ $this->getCon()->getSiteInstallationId()
139
+ );
140
+ if ( !is_array( $aResp ) || empty( $aResp[ 'token' ] ) || strlen( $aResp[ 'token' ] ) != 40 ) {
141
+ throw new \Exception( 'Could not retrieve token' );
142
+ }
143
+ return $aResp;
144
+ }
145
+ }
src/lib/src/Modules/LoginGuard/AjaxHandler.php CHANGED
@@ -3,6 +3,7 @@
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield;
 
6
  use FernleafSystems\Wordpress\Services\Services;
7
 
8
  class AjaxHandler extends Shield\Modules\Base\AjaxHandlerShield {
@@ -41,11 +42,12 @@ class AjaxHandler extends Shield\Modules\Base\AjaxHandlerShield {
41
  * @return array
42
  */
43
  protected function ajaxExec_GenBackupCodes() {
44
- /** @var \ICWP_WPSF_Processor_LoginProtect $oPro */
45
- $oPro = $this->getMod()->getProcessor();
46
- $sPass = $oPro->getSubProIntent()
47
- ->getProcessorBackupCodes()
48
- ->resetSecret( Services::WpUsers()->getCurrentWpUser() );
 
49
 
50
  foreach ( [ 20, 15, 10, 5 ] as $nPos ) {
51
  $sPass = substr_replace( $sPass, '-', $nPos, 0 );
@@ -63,11 +65,10 @@ class AjaxHandler extends Shield\Modules\Base\AjaxHandlerShield {
63
  private function ajaxExec_DeleteBackupCodes() {
64
  /** @var \ICWP_WPSF_FeatureHandler_LoginProtect $oMod */
65
  $oMod = $this->getMod();
66
- /** @var \ICWP_WPSF_Processor_LoginProtect $oPro */
67
- $oPro = $oMod->getProcessor();
68
- $oPro->getSubProIntent()
69
- ->getProcessorBackupCodes()
70
- ->deleteSecret( Services::WpUsers()->getCurrentWpUser() );
71
  $oMod->setFlashAdminNotice( __( 'Multi-factor login backup code has been removed from your profile', 'wp-simple-firewall' ) );
72
  return [
73
  'success' => true
@@ -94,13 +95,15 @@ class AjaxHandler extends Shield\Modules\Base\AjaxHandlerShield {
94
  private function ajaxExec_ResendEmailVerification() {
95
  /** @var \ICWP_WPSF_FeatureHandler_LoginProtect $oMod */
96
  $oMod = $this->getMod();
 
 
97
  $bSuccess = true;
98
 
99
- if ( !$oMod->isEmailAuthenticationOptionOn() ) {
100
  $sMessage = __( 'Email 2FA option is not currently enabled.', 'wp-simple-firewall' );
101
  $bSuccess = false;
102
  }
103
- elseif ( $oMod->getIfCanSendEmailVerified() ) {
104
  $sMessage = __( 'Email sending has already been verified.', 'wp-simple-firewall' );
105
  }
106
  else {
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor;
7
  use FernleafSystems\Wordpress\Services\Services;
8
 
9
  class AjaxHandler extends Shield\Modules\Base\AjaxHandlerShield {
42
  * @return array
43
  */
44
  protected function ajaxExec_GenBackupCodes() {
45
+ /** @var \ICWP_WPSF_FeatureHandler_LoginProtect $oMod */
46
+ $oMod = $this->getMod();
47
+ /** @var TwoFactor\Provider\Backup $oBU */
48
+ $oBU = $oMod->getLoginIntentController()
49
+ ->getProviders()[ TwoFactor\Provider\Backup::SLUG ];
50
+ $sPass = $oBU->resetSecret( Services::WpUsers()->getCurrentWpUser() );
51
 
52
  foreach ( [ 20, 15, 10, 5 ] as $nPos ) {
53
  $sPass = substr_replace( $sPass, '-', $nPos, 0 );
65
  private function ajaxExec_DeleteBackupCodes() {
66
  /** @var \ICWP_WPSF_FeatureHandler_LoginProtect $oMod */
67
  $oMod = $this->getMod();
68
+ /** @var TwoFactor\Provider\Backup $oBU */
69
+ $oBU = $oMod->getLoginIntentController()
70
+ ->getProviders()[ TwoFactor\Provider\Backup::SLUG ];
71
+ $oBU->deleteSecret( Services::WpUsers()->getCurrentWpUser() );
 
72
  $oMod->setFlashAdminNotice( __( 'Multi-factor login backup code has been removed from your profile', 'wp-simple-firewall' ) );
73
  return [
74
  'success' => true
95
  private function ajaxExec_ResendEmailVerification() {
96
  /** @var \ICWP_WPSF_FeatureHandler_LoginProtect $oMod */
97
  $oMod = $this->getMod();
98
+ /** @var Options $oOpts */
99
+ $oOpts = $this->getOptions();
100
  $bSuccess = true;
101
 
102
+ if ( !$oOpts->isEnabledEmailAuth() ) {
103
  $sMessage = __( 'Email 2FA option is not currently enabled.', 'wp-simple-firewall' );
104
  $bSuccess = false;
105
  }
106
+ elseif ( $oOpts->getIfCanSendEmailVerified() ) {
107
  $sMessage = __( 'Email sending has already been verified.', 'wp-simple-firewall' );
108
  }
109
  else {
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/LoginIntentPage.php ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor;
8
+ use FernleafSystems\Wordpress\Plugin\Shield\Utilities\AdminNotices\NoticeVO;
9
+ use FernleafSystems\Wordpress\Services\Services;
10
+
11
+ class LoginIntentPage {
12
+
13
+ use MfaControllerConsumer;
14
+
15
+ /**
16
+ */
17
+ public function loadPage() {
18
+ echo $this->renderPage();
19
+ }
20
+
21
+ /**
22
+ * @return string
23
+ */
24
+ public function renderForm() {
25
+ $oIC = $this->getMfaCon();
26
+ /** @var \ICWP_WPSF_FeatureHandler_LoginProtect $oMod */
27
+ $oMod = $oIC->getMod();
28
+ /** @var LoginGuard\Options $oOpts */
29
+ $oOpts = $oIC->getOptions();
30
+ $oCon = $oIC->getCon();
31
+ $oReq = Services::Request();
32
+ $oWP = Services::WpGeneral();
33
+
34
+ $aLoginIntentFields = array_map(
35
+ function ( $oProvider ) {
36
+ /** @var TwoFactor\Provider\BaseProvider $oProvider */
37
+ return $oProvider->getFormField();
38
+ },
39
+ $oIC->getProvidersForUser( Services::WpUsers()->getCurrentWpUser(), true )
40
+ );
41
+
42
+ $oNotice = $oCon->getAdminNotices()->getFlashNotice();
43
+ if ( $oNotice instanceof NoticeVO ) {
44
+ $sMessage = $oNotice->render_data[ 'message' ];
45
+ }
46
+ else {
47
+ $sMessage = $oOpts->isChainedAuth() ?
48
+ __( 'Please supply all authentication codes', 'wp-simple-firewall' )
49
+ : __( 'Please supply at least 1 authentication code', 'wp-simple-firewall' );
50
+ }
51
+
52
+ $sReferUrl = $oReq->server( 'HTTP_REFERER', '' );
53
+ if ( strpos( $sReferUrl, '?' ) ) {
54
+ list( $sReferUrl, $sReferQuery ) = explode( '?', $sReferUrl, 2 );
55
+ }
56
+ else {
57
+ $sReferQuery = '';
58
+ }
59
+
60
+ $sRedirectTo = '';
61
+ if ( !empty( $sReferQuery ) ) {
62
+ parse_str( $sReferQuery, $aReferQueryItems );
63
+ if ( !empty( $aReferQueryItems[ 'redirect_to' ] ) ) {
64
+ $sRedirectTo = rawurlencode( $aReferQueryItems[ 'redirect_to' ] );
65
+ }
66
+ }
67
+ if ( empty( $sRedirectTo ) ) {
68
+ $sRedirectTo = rawurlencode( $oReq->post( 'redirect_to', $oReq->getUri() ) );
69
+ }
70
+
71
+ $sCancelHref = $oReq->post( 'cancel_href', '' );
72
+ if ( empty( $sCancelHref ) && Services::Data()->isValidWebUrl( $sReferUrl ) ) {
73
+ $sCancelHref = rawurlencode( parse_url( $sReferUrl, PHP_URL_PATH ) );
74
+ }
75
+
76
+ $nMfaSkip = $oOpts->getMfaSkip();
77
+ $nTimeRemaining = $oMod->getSession()->login_intent_expires_at - $oReq->ts();
78
+ $aDisplayData = [
79
+ 'strings' => [
80
+ 'cancel' => __( 'Cancel Login', 'wp-simple-firewall' ),
81
+ 'time_remaining' => __( 'Time Remaining', 'wp-simple-firewall' ),
82
+ 'calculating' => __( 'Calculating', 'wp-simple-firewall' ).' ...',
83
+ 'seconds' => strtolower( __( 'Seconds', 'wp-simple-firewall' ) ),
84
+ 'login_expired' => __( 'Login Expired', 'wp-simple-firewall' ),
85
+ 'verify_my_login' => __( 'Verify My Login', 'wp-simple-firewall' ),
86
+ 'message' => $sMessage,
87
+ 'skip_mfa' => sprintf(
88
+ __( "Don't ask again on this browser for %s.", 'wp-simple-firewall' ),
89
+ sprintf( _n( '%s day', '%s days', $nMfaSkip, 'wp-simple-firewall' ), $nMfaSkip )
90
+ )
91
+ ],
92
+ 'data' => [
93
+ 'login_fields' => $aLoginIntentFields,
94
+ 'time_remaining' => $nTimeRemaining,
95
+ 'message_type' => 'info',
96
+ 'login_intent_flag' => $oMod->getLoginIntentRequestFlag(),
97
+ ],
98
+ 'hrefs' => [
99
+ 'form_action' => parse_url( $oWP->getAdminUrl( '', true ), PHP_URL_PATH ),
100
+ 'redirect_to' => $sRedirectTo,
101
+ 'cancel_href' => $sCancelHref
102
+ ],
103
+ 'flags' => [
104
+ 'can_skip_mfa' => $oMod->getMfaSkipEnabled(),
105
+ 'show_branded_links' => !$oMod->isWlEnabled(), // white label mitigation
106
+ ]
107
+ ];
108
+
109
+ return $oMod->renderTemplate( '/snippets/login_intent/form.twig',
110
+ Services::DataManipulation()->mergeArraysRecursive( $oMod->getBaseDisplayData(), $aDisplayData ), true );
111
+ }
112
+
113
+ /**
114
+ * @return string
115
+ */
116
+ private function renderPage() {
117
+ $oIC = $this->getMfaCon();
118
+ /** @var \ICWP_WPSF_FeatureHandler_LoginProtect $oMod */
119
+ $oMod = $oIC->getMod();
120
+ $oCon = $oIC->getCon();
121
+ $oReq = Services::Request();
122
+
123
+ $aLabels = $oCon->getLabels();
124
+ $sBannerUrl = empty( $aLabels[ 'url_login2fa_logourl' ] ) ? $oCon->getPluginUrl_Image( 'pluginlogo_banner-772x250.png' ) : $aLabels[ 'url_login2fa_logourl' ];
125
+ $nTimeRemaining = $oMod->getSession()->login_intent_expires_at - $oReq->ts();
126
+ $aDisplayData = [
127
+ 'strings' => [
128
+ 'what_is_this' => __( 'What is this?', 'wp-simple-firewall' ),
129
+ 'page_title' => sprintf( __( '%s Login Verification', 'wp-simple-firewall' ), $oCon->getHumanName() ),
130
+ ],
131
+ 'data' => [
132
+ 'time_remaining' => $nTimeRemaining,
133
+ ],
134
+ 'hrefs' => [
135
+ 'css_bootstrap' => $oCon->getPluginUrl_Css( 'bootstrap4.min' ),
136
+ 'js_bootstrap' => $oCon->getPluginUrl_Js( 'bootstrap4.min' ),
137
+ 'shield_logo' => 'https://ps.w.org/wp-simple-firewall/assets/banner-772x250.png',
138
+ 'what_is_this' => 'https://icontrolwp.freshdesk.com/support/solutions/articles/3000064840',
139
+ ],
140
+ 'imgs' => [
141
+ 'banner' => $sBannerUrl,
142
+ 'favicon' => $oCon->getPluginUrl_Image( 'pluginlogo_24x24.png' ),
143
+ ],
144
+ 'flags' => [
145
+ 'show_branded_links' => !$oMod->isWlEnabled(), // white label mitigation
146
+ ],
147
+ 'content' => [
148
+ 'form' => $this->renderForm(),
149
+ ]
150
+ ];
151
+
152
+ return $oMod->renderTemplate( '/pages/login_intent/index.twig',
153
+ Services::DataManipulation()->mergeArraysRecursive( $oMod->getBaseDisplayData(), $aDisplayData ), true );
154
+ }
155
+ }
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/MfaController.php ADDED
@@ -0,0 +1,328 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Databases\Session\Update;
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 {
12
+
13
+ use Shield\Modules\ModConsumer;
14
+
15
+ /**
16
+ * @var Provider\BaseProvider[]
17
+ */
18
+ private $aProviders;
19
+
20
+ /**
21
+ * @var bool
22
+ */
23
+ protected $bLoginAttemptCaptured;
24
+
25
+ /**
26
+ * @var LoginIntentPage
27
+ */
28
+ private $oLoginIntentPageHandler;
29
+
30
+ public function run() {
31
+ add_action( 'init', [ $this, 'onWpInit' ], 10, 2 );
32
+ add_action( 'wp_login', [ $this, 'onWpLogin' ], 10, 2 );
33
+ if ( !Services::WpUsers()->isProfilePage() ) { // This can be fired during profile update.
34
+ add_action( 'set_logged_in_cookie', [ $this, 'onWpSetLoggedInCookie' ], 5, 4 );
35
+ }
36
+ add_action( 'wp_loaded', [ $this, 'onWpLoaded' ], 10, 2 );
37
+ }
38
+
39
+ public function onWpInit() {
40
+ $this->assessLoginIntent();
41
+ }
42
+
43
+ /**
44
+ * @param string $sUsername
45
+ * @param \WP_User $oUser
46
+ */
47
+ public function onWpLogin( $sUsername, $oUser ) {
48
+ $this->captureLoginIntent( $oUser );
49
+ }
50
+
51
+ public function onWpLoaded() {
52
+ ( new UserProfile() )
53
+ ->setMfaController( $this )
54
+ ->run();
55
+
56
+ add_shortcode( 'SHIELD_2FA_LOGIN', function () {
57
+ return $this->getLoginIntentPageHandler()->renderForm();
58
+ } );
59
+ }
60
+
61
+ /**
62
+ * @param string $sCookie
63
+ * @param int $nExpire
64
+ * @param int $nExpiration
65
+ * @param int $nUserId
66
+ */
67
+ public function onWpSetLoggedInCookie( $sCookie, $nExpire, $nExpiration, $nUserId ) {
68
+ $this->captureLoginIntent( Services::WpUsers()->getUserById( $nUserId ) );
69
+ }
70
+
71
+ /**
72
+ * @param \WP_User $oUser
73
+ */
74
+ private function captureLoginIntent( $oUser ) {
75
+ if ( empty( $this->bLoginAttemptCaptured ) && $oUser instanceof \WP_User ) {
76
+ $this->bLoginAttemptCaptured = true;
77
+
78
+ /** @var LoginGuard\Options $oOpts */
79
+ $oOpts = $this->getOptions();
80
+ if ( $this->isSubjectToLoginIntent( $oUser ) && !$this->canUserMfaSkip( $oUser ) ) {
81
+
82
+ $aProviders = $this->getProvidersForUser( $oUser );
83
+ if ( !empty( $aProviders ) ) {
84
+ foreach ( $aProviders as $oProvider ) {
85
+ $oProvider->captureLoginAttempt( $oUser );
86
+ }
87
+
88
+ $nTimeout = (int)apply_filters(
89
+ $this->getCon()->prefix( 'login_intent_timeout' ),
90
+ $oOpts->getDef( 'login_intent_timeout' )
91
+ );
92
+ $this->setLoginIntentExpiresAt(
93
+ Services::Request()->carbon()->addMinutes( $nTimeout )->timestamp
94
+ );
95
+ }
96
+ }
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Deals with the scenario when the user session has a login intent.
102
+ */
103
+ private function assessLoginIntent() {
104
+ $oUser = Services::WpUsers()->getCurrentWpUser();
105
+ if ( $oUser instanceof \WP_User && $this->hasLoginIntent() ) {
106
+
107
+ if ( $this->isSubjectToLoginIntent( $oUser ) ) {
108
+
109
+ if ( $this->getLoginIntentExpiresAt() > Services::Request()->ts() ) {
110
+ $this->processActiveLoginIntent();
111
+ }
112
+ else {
113
+ Services::WpUsers()->logoutUser(); // clears the login and login intent
114
+ Services::Response()->redirectHere();
115
+ }
116
+ }
117
+ else {
118
+ // This handles the case where an admin changes a setting while a user is logged-in
119
+ // So to prevent this, we remove any intent for a user that isn't subject to it right now
120
+ $this->removeLoginIntent();
121
+ }
122
+ }
123
+ }
124
+
125
+ /**
126
+ * @return LoginIntentPage
127
+ */
128
+ private function getLoginIntentPageHandler() {
129
+ if ( !isset( $this->oLoginIntentPageHandler ) ) {
130
+ $this->oLoginIntentPageHandler =( new LoginIntentPage() )->setMfaController( $this );
131
+ }
132
+ return $this->oLoginIntentPageHandler;
133
+ }
134
+
135
+ /**
136
+ * @return Provider\BaseProvider[]
137
+ */
138
+ public function getProviders() {
139
+ if ( !is_array( $this->aProviders ) ) {
140
+ $this->aProviders = [
141
+ Provider\Email::SLUG => ( new Provider\Email() )->setMod( $this->getMod() ),
142
+ Provider\GoogleAuth::SLUG => ( new Provider\GoogleAuth() )->setMod( $this->getMod() ),
143
+ Provider\Yubikey::SLUG => ( new Provider\Yubikey() )->setMod( $this->getMod() ),
144
+ Provider\Backup::SLUG => ( new Provider\Backup() )->setMod( $this->getMod() ),
145
+ ];
146
+ }
147
+ return $this->aProviders;
148
+ }
149
+
150
+ /**
151
+ * Ensures that BackupCode provider isn't supplied on its own, and the user profile is setup for each.
152
+ * @param \WP_User $oUser
153
+ * @param bool $bOnlyActiveProfiles
154
+ * @return Provider\BaseProvider[]
155
+ */
156
+ public function getProvidersForUser( $oUser, $bOnlyActiveProfiles = false ) {
157
+ $aProviders = array_filter( $this->getProviders(),
158
+ function ( $oProvider ) use ( $oUser, $bOnlyActiveProfiles ) {
159
+ /** @var Provider\BaseProvider $oProvider */
160
+ return $oProvider->isProviderAvailableToUser( $oUser )
161
+ && ( !$bOnlyActiveProfiles || $oProvider->isProfileActive( $oUser ) );
162
+ }
163
+ );
164
+ // Backups should NEVER be the only 1 available.
165
+ if ( count( $aProviders ) === 1 && isset( $aProviders[ Provider\Backup::SLUG ] ) ) {
166
+ unset( $aProviders[ Provider\Backup::SLUG ] );
167
+ }
168
+ return $aProviders;
169
+ }
170
+
171
+ /**
172
+ * hooked to 'init' and only run if a user is logged-in (not on the login request)
173
+ */
174
+ private function processActiveLoginIntent() {
175
+ /** @var LoginGuard\Options $oOpts */
176
+ $oOpts = $this->getOptions();
177
+ $oCon = $this->getCon();
178
+ $oReq = Services::Request();
179
+ $oWpResp = Services::Response();
180
+ $oUser = Services::WpUsers()->getCurrentWpUser();
181
+
182
+ // Is 2FA/login-intent submit
183
+ if ( $oReq->request( $this->getLoginIntentRequestFlag() ) == 1 ) {
184
+
185
+ if ( $oReq->post( 'cancel' ) == 1 ) {
186
+ Services::WpUsers()->logoutUser(); // clears the login and login intent
187
+ $sRedirectHref = $oReq->post( 'cancel_href' );
188
+ empty( $sRedirectHref ) ? $oWpResp->redirectToLogin() : $oWpResp->redirect( rawurldecode( $sRedirectHref ) );
189
+ }
190
+ elseif ( $this->validateLoginIntentRequest() ) {
191
+
192
+ if ( $oReq->post( 'skip_mfa' ) === 'Y' ) { // store the browser hash
193
+ $oCon->getUserMeta( $oUser )
194
+ ->addMfaSkipAgent( $oReq->getUserAgent(), $oOpts->getMfaSkip() );
195
+ }
196
+ $oCon->fireEvent( '2fa_success' );
197
+
198
+ $sFlash = __( 'Success', 'wp-simple-firewall' ).'! '.__( 'Thank you for authenticating your login.', 'wp-simple-firewall' );
199
+ if ( $oOpts->isEnabledBackupCodes() ) {
200
+ $sFlash .= ' '.__( 'If you used your Backup Code, you will need to reset it.', 'wp-simple-firewall' ); //TODO::
201
+ }
202
+ $this->getMod()->setFlashAdminNotice( $sFlash );
203
+
204
+ $this->removeLoginIntent();
205
+
206
+ $sRedirectHref = $oReq->post( 'redirect_to' );
207
+ empty( $sRedirectHref ) ? $oWpResp->redirectHere() : $oWpResp->redirect( rawurldecode( $sRedirectHref ) );
208
+ }
209
+ else {
210
+ $oCon->getAdminNotices()
211
+ ->addFlash(
212
+ __( 'One or more of your authentication codes failed or was missing.', 'wp-simple-firewall' ),
213
+ true
214
+ );
215
+ // We don't protect against loops here to prevent by-passing of the login intent page.
216
+ Services::Response()->redirect( Services::Request()->getUri(), [], true, false );
217
+ }
218
+ }
219
+ elseif ( $oOpts->isUseLoginIntentPage() ) {
220
+ $this->getLoginIntentPageHandler()->loadPage();
221
+ }
222
+ die();
223
+ }
224
+
225
+ /**
226
+ * assume that a user is logged in.
227
+ * @return bool
228
+ */
229
+ private function validateLoginIntentRequest() {
230
+ try {
231
+ $bValid = ( new ValidateLoginIntentRequest() )
232
+ ->setMfaController( $this )
233
+ ->run();
234
+ }
235
+ catch ( \Exception $oE ) {
236
+ $bValid = true;
237
+ }
238
+ return $bValid;
239
+ }
240
+
241
+ /**
242
+ * @param \WP_User $oUser
243
+ * @return bool
244
+ */
245
+ private function canUserMfaSkip( $oUser ) {
246
+ /** @var LoginGuard\Options $oOpts */
247
+ $oOpts = $this->getOptions();
248
+ $oReq = Services::Request();
249
+
250
+ $oMeta = $this->getCon()->getUserMeta( $oUser );
251
+ if ( $oOpts->isMfaSkip() ) {
252
+ $aHashes = is_array( $oMeta->hash_loginmfa ) ? $oMeta->hash_loginmfa : [];
253
+ $sAgentHash = md5( $oReq->getUserAgent() );
254
+ $bCanSkip = isset( $aHashes[ $sAgentHash ] )
255
+ && ( (int)$aHashes[ $sAgentHash ] + $oOpts->getMfaSkip() ) > $oReq->ts();
256
+ }
257
+ elseif ( $this->getCon()->isPremiumActive() && @class_exists( 'WC_Social_Login' ) ) {
258
+ // custom support for WooCommerce Social login
259
+ $oMeta = $this->getCon()->getUserMeta( $oUser );
260
+ $bCanSkip = isset( $oMeta->wc_social_login_valid ) ? $oMeta->wc_social_login_valid : false;
261
+ }
262
+ else {
263
+ /**
264
+ * TODO: remove the HTTP_REFERER bit once iCWP plugin is updated.
265
+ * We want logins from iCWP to skip 2FA. To achieve this, iCWP plugin needs
266
+ * to add a TRUE filter on 'odp-shield-2fa_skip' at the point of login.
267
+ * Until then, we'll use the HTTP referrer as an indicator
268
+ */
269
+ $bCanSkip = apply_filters(
270
+ 'odp-shield-2fa_skip',
271
+ strpos( $oReq->server( 'HTTP_REFERER' ), 'https://app.icontrolwp.com/' ) === 0
272
+ );
273
+ }
274
+ return $bCanSkip;
275
+ }
276
+
277
+ /**
278
+ * @param \WP_User $oUser
279
+ * @return bool
280
+ */
281
+ private function isSubjectToLoginIntent( $oUser ) {
282
+ return count( $this->getProvidersForUser( $oUser, true ) ) > 0;
283
+ }
284
+
285
+ /**
286
+ * @return int
287
+ */
288
+ private function getLoginIntentExpiresAt() {
289
+ return $this->getMod()->hasSession() ? $this->getMod()->getSession()->login_intent_expires_at : 0;
290
+ }
291
+
292
+ /**
293
+ * @return bool
294
+ */
295
+ protected function hasLoginIntent() {
296
+ return $this->getLoginIntentExpiresAt() > 0;
297
+ }
298
+
299
+ /**
300
+ * Use this ONLY when the login intent has been successfully verified.
301
+ * @return $this
302
+ */
303
+ private function removeLoginIntent() {
304
+ return $this->setLoginIntentExpiresAt( 0 );
305
+ }
306
+
307
+ /**
308
+ * @param int $nExpirationTime
309
+ * @return $this
310
+ */
311
+ protected function setLoginIntentExpiresAt( $nExpirationTime ) {
312
+ /** @var \ICWP_WPSF_FeatureHandler_LoginProtect $oMod */
313
+ $oMod = $this->getMod();
314
+ if ( $oMod->hasSession() ) {
315
+ /** @var Update $oUpd */
316
+ $oUpd = $oMod->getDbHandler_Sessions()->getQueryUpdater();
317
+ $oUpd->updateLoginIntentExpiresAt( $oMod->getSession(), $nExpirationTime );
318
+ }
319
+ return $this;
320
+ }
321
+
322
+ /**
323
+ * @return string
324
+ */
325
+ private function getLoginIntentRequestFlag() {
326
+ return $this->getCon()->prefix( 'login-intent-request' );
327
+ }
328
+ }
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/MfaControllerConsumer.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield;
6
+
7
+ /**
8
+ * Trait MfaControllerConsumer
9
+ * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor
10
+ */
11
+ trait MfaControllerConsumer {
12
+
13
+ /**
14
+ * @var MfaController
15
+ */
16
+ private $oMfaController;
17
+
18
+ /**
19
+ * @return MfaController
20
+ */
21
+ public function getMfaCon() {
22
+ return $this->oMfaController;
23
+ }
24
+
25
+ /**
26
+ * @param MfaController $oCon
27
+ * @return $this
28
+ */
29
+ public function setMfaController( MfaController $oCon ) {
30
+ $this->oMfaController = $oCon;
31
+ return $this;
32
+ }
33
+ }
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Backup.php ADDED
@@ -0,0 +1,169 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor\Provider;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
+
8
+ class Backup extends BaseProvider {
9
+
10
+ const SLUG = 'backupcode';
11
+
12
+ /**
13
+ * @inheritDoc
14
+ */
15
+ public function renderUserProfileOptions( \WP_User $oUser ) {
16
+ $oCon = $this->getCon();
17
+
18
+ $aData = [
19
+ 'strings' => [
20
+ 'button_gen_code' => __( 'Generate ONE-Time Backup 2FA Login Code', 'wp-simple-firewall' ),
21
+ 'button_del_code' => __( 'Delete Login Backup Code', 'wp-simple-firewall' ),
22
+ 'not_available' => __( 'Backup login codes are not available if you do not have any other two-factor authentication modes active.', 'wp-simple-firewall' ),
23
+ 'description_code' => __( 'Click to generate a backup login code for your two-factor authentication.', 'wp-simple-firewall' ),
24
+ 'description_code_ext1' => sprintf( '%s: %s',
25
+ __( 'Important', 'wp-simple-firewall' ),
26
+ __( 'This code will be displayed only once and you may use it to verify your login only once.', 'wp-simple-firewall' )
27
+ .' '.__( 'Store it somewhere safe.', 'wp-simple-firewall' ) ),
28
+ 'description_code_ext2' => __( 'Generating a new code will replace your existing code.', 'wp-simple-firewall' ),
29
+ 'label_enter_code' => __( 'Create Backup 2FA Login Code', 'wp-simple-firewall' ),
30
+ 'title' => __( 'Backup Login Code', 'wp-simple-firewall' ),
31
+ 'cant_add_other_user' => sprintf( __( "Sorry, %s may not be added to another user's account.", 'wp-simple-firewall' ), 'Backup Codes' ),
32
+ 'cant_remove_admins' => sprintf( __( "Sorry, %s may only be removed from another user's account by a Security Administrator.", 'wp-simple-firewall' ), __( 'Backup Codes', 'wp-simple-firewall' ) ),
33
+ 'provided_by' => sprintf( __( 'Provided by %s', 'wp-simple-firewall' ), $oCon->getHumanName() ),
34
+ 'remove_more_info' => sprintf( __( 'Understand how to remove Google Authenticator', 'wp-simple-firewall' ) )
35
+ ]
36
+ ];
37
+
38
+ return $this->getMod()
39
+ ->renderTemplate(
40
+ '/snippets/user/profile/mfa/mfa_backup.twig',
41
+ Services::DataManipulation()->mergeArraysRecursive( $this->getCommonData( $oUser ), $aData ),
42
+ true
43
+ );
44
+ }
45
+
46
+ /**
47
+ * @inheritDoc
48
+ */
49
+ public function renderUserEditProfileOptions( \WP_User $oUser ) {
50
+ // Allow no actions to be taken on other user profiles
51
+ }
52
+
53
+ /**
54
+ * @return array
55
+ */
56
+ public function getFormField() {
57
+ return [
58
+ 'name' => $this->getLoginFormParameter(),
59
+ 'type' => 'text',
60
+ 'value' => '',
61
+ 'placeholder' => __( 'Please use your Backup Code to login.', 'wp-simple-firewall' ),
62
+ 'text' => __( 'Login Backup Code', 'wp-simple-firewall' ),
63
+ 'help_link' => '',
64
+ ];
65
+ }
66
+
67
+ /**
68
+ * @param \WP_User $oUser
69
+ * @return bool
70
+ */
71
+ public function hasValidatedProfile( $oUser ) {
72
+ return $this->hasValidSecret( $oUser );
73
+ }
74
+
75
+ /**
76
+ * @param \WP_User $oUser
77
+ * @return $this
78
+ */
79
+ public function postSuccessActions( \WP_User $oUser ) {
80
+ $this->deleteSecret( $oUser );
81
+ $this->sendBackupCodeUsedEmail( $oUser );
82
+ return $this;
83
+ }
84
+
85
+ /**
86
+ * Backup Code are 1-time only and if you have MFA, then we need to remove all the other tracking factors
87
+ * @param \WP_User $oUser
88
+ * @param string $sOtpCode
89
+ * @return bool
90
+ */
91
+ protected function processOtp( $oUser, $sOtpCode ) {
92
+ return $this->validateBackupCode( $oUser, $sOtpCode );
93
+ }
94
+
95
+ /**
96
+ * @param \WP_User $oUser
97
+ * @param string $sOtpCode
98
+ * @return bool
99
+ */
100
+ private function validateBackupCode( $oUser, $sOtpCode ) {
101
+ return wp_check_password( str_replace( '-', '', $sOtpCode ), $this->getSecret( $oUser ) );
102
+ }
103
+
104
+ /**
105
+ * @param \WP_User $oUser
106
+ * @param bool $bIsSuccess
107
+ */
108
+ protected function auditLogin( $oUser, $bIsSuccess ) {
109
+ $this->getCon()->fireEvent(
110
+ $bIsSuccess ? '2fa_backupcode_verified' : '2fa_backupcode_fail',
111
+ [
112
+ 'audit' => [
113
+ 'user_login' => $oUser->user_login,
114
+ 'method' => 'Backup Code',
115
+ ]
116
+ ]
117
+ );
118
+ }
119
+
120
+ /**
121
+ * @param \WP_User $oUser
122
+ * @return string
123
+ */
124
+ protected function genNewSecret( \WP_User $oUser ) {
125
+ return wp_generate_password( 25, false );
126
+ }
127
+
128
+ /**
129
+ * @return bool
130
+ */
131
+ public function isProviderEnabled() {
132
+ /** @var LoginGuard\Options $oOpts */
133
+ $oOpts = $this->getOptions();
134
+ return $oOpts->isEnabledBackupCodes();
135
+ }
136
+
137
+ /**
138
+ * @param \WP_User $oUser
139
+ * @param string $sNewSecret
140
+ * @return $this
141
+ */
142
+ protected function setSecret( $oUser, $sNewSecret ) {
143
+ parent::setSecret( $oUser, wp_hash_password( $sNewSecret ) );
144
+ return $this;
145
+ }
146
+
147
+ /**
148
+ * @param \WP_User $oUser
149
+ */
150
+ private function sendBackupCodeUsedEmail( $oUser ) {
151
+ $aEmailContent = [
152
+ __( 'This is a quick notice to inform you that your Backup Login code was just used.', 'wp-simple-firewall' ),
153
+ __( "Your WordPress account had only 1 backup login code.", 'wp-simple-firewall' )
154
+ .' '.__( "You must go to your profile and regenerate a new code if you want to use this method again.", 'wp-simple-firewall' ),
155
+ '',
156
+ sprintf( '<strong>%s</strong>', __( 'Login Details', 'wp-simple-firewall' ) ),
157
+ sprintf( '%s: %s', __( 'URL', 'wp-simple-firewall' ), Services::WpGeneral()->getHomeUrl() ),
158
+ sprintf( '%s: %s', __( 'Username', 'wp-simple-firewall' ), $oUser->user_login ),
159
+ sprintf( '%s: %s', __( 'IP Address', 'wp-simple-firewall' ), Services::IP()->getRequestIp() ),
160
+ '',
161
+ __( 'Thank You.', 'wp-simple-firewall' ),
162
+ ];
163
+
164
+ $sTitle = sprintf( __( "Notice: %s", 'wp-simple-firewall' ), __( "Backup Login Code Just Used", 'wp-simple-firewall' ) );
165
+ $this->getMod()
166
+ ->getEmailProcessor()
167
+ ->sendEmailWithWrap( $oUser->user_email, $sTitle, $aEmailContent );
168
+ }
169
+ }
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/BaseProvider.php ADDED
@@ -0,0 +1,258 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor\Provider;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
+
8
+ abstract class BaseProvider {
9
+
10
+ use Modules\ModConsumer;
11
+ const SLUG = '';
12
+
13
+ /**
14
+ * Assumes this is only called on active profiles
15
+ * @param \WP_User $oUser
16
+ * @return bool
17
+ */
18
+ public function validateLoginIntent( \WP_User $oUser ) {
19
+ $bOtpSuccess = false;
20
+ $sReqOtpCode = $this->fetchCodeFromRequest();
21
+ if ( !empty( $sReqOtpCode ) ) {
22
+ $bOtpSuccess = $this->processOtp( $oUser, $sReqOtpCode );
23
+ $this->postOtpProcessAction( $oUser, $bOtpSuccess );
24
+ }
25
+ return $bOtpSuccess;
26
+ }
27
+
28
+ /**
29
+ * @param \WP_User $oUser
30
+ * @return string
31
+ */
32
+ protected function getSecret( \WP_User $oUser ) {
33
+ $sSecret = $this->getCon()->getUserMeta( $oUser )->{static::SLUG.'_secret'};
34
+ return empty( $sSecret ) ? '' : $sSecret;
35
+ }
36
+
37
+ /**
38
+ * @param \WP_User $oUser
39
+ * @return bool
40
+ */
41
+ public function hasValidatedProfile( $oUser ) {
42
+ return $this->getCon()->getUserMeta( $oUser )->{static::SLUG.'_validated'} === true;
43
+ }
44
+
45
+ /**
46
+ * @param \WP_User $oUser
47
+ * @return bool
48
+ */
49
+ protected function hasValidSecret( \WP_User $oUser ) {
50
+ return $this->isSecretValid( $this->getSecret( $oUser ) );
51
+ }
52
+
53
+ /**
54
+ * @param \WP_User $oUser
55
+ * @return bool
56
+ */
57
+ protected function isEnforced( $oUser ) {
58
+ return false;
59
+ }
60
+
61
+ /**
62
+ * @param \WP_User $oUser
63
+ * @return bool
64
+ */
65
+ public function isProfileActive( \WP_User $oUser ) {
66
+ return $this->hasValidSecret( $oUser );
67
+ }
68
+
69
+ /**
70
+ * @param \WP_User $oUser
71
+ * @return bool
72
+ */
73
+ public function isProviderAvailableToUser( \WP_User $oUser ) {
74
+ return $this->isProviderEnabled();
75
+ }
76
+
77
+ /**
78
+ * @return bool
79
+ */
80
+ abstract public function isProviderEnabled();
81
+
82
+ /**
83
+ * @param string $sSecret
84
+ * @return bool
85
+ */
86
+ protected function isSecretValid( $sSecret ) {
87
+ return !empty( $sSecret ) && is_string( $sSecret );
88
+ }
89
+
90
+ /**
91
+ * @param \WP_User $oUser
92
+ * @return $this
93
+ */
94
+ public function deleteSecret( $oUser ) {
95
+ $this->getCon()
96
+ ->getUserMeta( $oUser )->{static::SLUG.'_secret'} = null;
97
+ return $this;
98
+ }
99
+
100
+ /**
101
+ * @param \WP_User $oUser
102
+ * @return string
103
+ */
104
+ public function resetSecret( \WP_User $oUser ) {
105
+ $sNewSecret = $this->genNewSecret( $oUser );
106
+ $this->setSecret( $oUser, $sNewSecret );
107
+ return $sNewSecret;
108
+ }
109
+
110
+ /**
111
+ * @param \WP_User $oUser
112
+ * @param bool $bValidated set true for validated, false for invalidated
113
+ * @return $this
114
+ */
115
+ public function setProfileValidated( $oUser, $bValidated = true ) {
116
+ $this->getCon()
117
+ ->getUserMeta( $oUser )->{static::SLUG.'_validated'} = $bValidated;
118
+ return $this;
119
+ }
120
+
121
+ /**
122
+ * @param \WP_User $oUser
123
+ * @param string $sNewSecret
124
+ * @return $this
125
+ */
126
+ protected function setSecret( $oUser, $sNewSecret ) {
127
+ $this->getCon()
128
+ ->getUserMeta( $oUser )->{static::SLUG.'_secret'} = $sNewSecret;
129
+ return $this;
130
+ }
131
+
132
+ /**
133
+ * @param \WP_User $oUser
134
+ * @return string
135
+ */
136
+ protected function genNewSecret( \WP_User $oUser ) {
137
+ return '';
138
+ }
139
+
140
+ /**
141
+ * @param \WP_User $oUser
142
+ * @param string $sOtpCode
143
+ * @return bool
144
+ */
145
+ abstract protected function processOtp( $oUser, $sOtpCode );
146
+
147
+ /**
148
+ * Only to be fired if and when Login has been completely verified.
149
+ * @param \WP_User $oUser
150
+ * @return $this
151
+ */
152
+ public function postSuccessActions( \WP_User $oUser ) {
153
+ return $this;
154
+ }
155
+
156
+ /**
157
+ * This MUST only ever be hooked into when the User is looking at their OWN profile, so we can use "current user"
158
+ * functions. Otherwise we need to be careful of mixing up users.
159
+ * @param \WP_User $oUser
160
+ * @return string
161
+ */
162
+ public function renderUserProfileOptions( \WP_User $oUser ) {
163
+ return '';
164
+ }
165
+
166
+ /**
167
+ * ONLY TO BE HOOKED TO USER PROFILE EDIT
168
+ * @param \WP_User $oUser
169
+ * @return string
170
+ */
171
+ public function renderUserEditProfileOptions( \WP_User $oUser ) {
172
+ return $this->renderUserProfileOptions( $oUser );
173
+ }
174
+
175
+ /**
176
+ * @param \WP_User $oUser
177
+ */
178
+ public function handleEditOtherUserProfileSubmit( \WP_User $oUser ) {
179
+ }
180
+
181
+ /**
182
+ * @param \WP_User $oUser
183
+ */
184
+ protected function processRemovalFromAccount( $oUser ) {
185
+ }
186
+
187
+ /**
188
+ * This MUST only ever be hooked into when the User is looking at their OWN profile,
189
+ * so we can use "current user" functions. Otherwise we need to be careful of mixing up users.
190
+ * @param \WP_User $oUser
191
+ */
192
+ public function handleUserProfileSubmit( \WP_User $oUser ) {
193
+ }
194
+
195
+ /**
196
+ * @param \WP_User $oUser
197
+ */
198
+ public function captureLoginAttempt( $oUser ) {
199
+ }
200
+
201
+ /**
202
+ * @return array
203
+ */
204
+ abstract public function getFormField();
205
+
206
+ /**
207
+ * @param \WP_User $oUser
208
+ * @param bool $bIsSuccess
209
+ */
210
+ abstract protected function auditLogin( $oUser, $bIsSuccess );
211
+
212
+ /**
213
+ * @param \WP_User $oUser
214
+ * @param bool $bIsOtpSuccess
215
+ * @return $this
216
+ */
217
+ protected function postOtpProcessAction( $oUser, $bIsOtpSuccess ) {
218
+ $this->auditLogin( $oUser, $bIsOtpSuccess );
219
+ return $this;
220
+ }
221
+
222
+ /**
223
+ * @return string
224
+ */
225
+ protected function getLoginFormParameter() {
226
+ return $this->getCon()->prefixOption( static::SLUG.'_otp' );
227
+ }
228
+
229
+ /**
230
+ * @return string
231
+ */
232
+ protected function fetchCodeFromRequest() {
233
+ return esc_attr( Services::Request()->request( $this->getLoginFormParameter(), false, '' ) );
234
+ }
235
+
236
+ /**
237
+ * @param \WP_User $oUser
238
+ * @return array
239
+ */
240
+ protected function getCommonData( \WP_User $oUser ) {
241
+ return [
242
+ 'flags' => [
243
+ 'has_validated_profile' => $this->hasValidatedProfile( $oUser ),
244
+ 'is_enforced' => $this->isEnforced( $oUser ),
245
+ 'is_profile_active' => $this->isProfileActive( $oUser ),
246
+ 'is_my_user_profile' => $oUser->ID == Services::WpUsers()->getCurrentWpUserId(),
247
+ 'i_am_valid_admin' => $this->getCon()->isPluginAdmin(),
248
+ 'user_to_edit_is_admin' => Services::WpUsers()->isUserAdmin( $oUser ),
249
+ ],
250
+ 'vars' => [
251
+ 'otp_field_name' => $this->getLoginFormParameter(),
252
+ ],
253
+ 'strings' => [
254
+ 'is_enforced' => __( 'This setting is enforced by your security administrator.', 'wp-simple-firewall' ),
255
+ ],
256
+ ];
257
+ }
258
+ }
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Email.php ADDED
@@ -0,0 +1,237 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor\Provider;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
+
8
+ class Email extends BaseProvider {
9
+
10
+ const SLUG = 'email';
11
+
12
+ /**
13
+ * @param \WP_User $oUser
14
+ */
15
+ public function captureLoginAttempt( $oUser ) {
16
+ /** @var \ICWP_WPSF_FeatureHandler_LoginProtect $oMod */
17
+ $oMod = $this->getMod();
18
+
19
+ /** @var \FernleafSystems\Wordpress\Plugin\Shield\Databases\Session\Update $oUpd */
20
+ $oUpd = $oMod->getDbHandler_Sessions()->getQueryUpdater();
21
+ $oUpd->setLoginIntentCodeEmail( $oMod->getSession(), $this->getSecret( $oUser ) );
22
+
23
+ // Now send email with authentication link for user.
24
+ $this->sendEmailTwoFactorVerify( $oUser );
25
+ }
26
+
27
+ /**
28
+ * @param \WP_User $oUser
29
+ * @param bool $bIsSuccess
30
+ */
31
+ protected function auditLogin( $oUser, $bIsSuccess ) {
32
+ $this->getCon()->fireEvent(
33
+ $bIsSuccess ? 'email_verified' : 'email_fail',
34
+ [
35
+ 'audit' => [
36
+ 'user_login' => $oUser->user_login,
37
+ 'method' => 'Email',
38
+ ]
39
+ ]
40
+ );
41
+ }
42
+
43
+ /**
44
+ * @param \WP_User $oUser
45
+ * @return $this
46
+ */
47
+ public function postSuccessActions( \WP_User $oUser ) {
48
+ /** @var \ICWP_WPSF_FeatureHandler_LoginProtect $oMod */
49
+ $oMod = $this->getMod();
50
+ /** @var \FernleafSystems\Wordpress\Plugin\Shield\Databases\Session\Update $oUpd */
51
+ $oUpd = $oMod->getDbHandler_Sessions()->getQueryUpdater();
52
+ $oUpd->clearLoginIntentCodeEmail( $oMod->getSession() );
53
+ return $this;
54
+ }
55
+
56
+ /**
57
+ * @param \WP_User $oUser
58
+ * @param string $sOtpCode
59
+ * @return bool
60
+ */
61
+ protected function processOtp( $oUser, $sOtpCode ) {
62
+ return $sOtpCode == $this->getStoredSessionHashCode();
63
+ }
64
+
65
+ /**
66
+ * @return array
67
+ */
68
+ public function getFormField() {
69
+ return [
70
+ 'name' => $this->getLoginFormParameter(),
71
+ 'type' => 'text',
72
+ 'value' => $this->fetchCodeFromRequest(),
73
+ 'placeholder' => __( 'This code was just sent to your registered Email address.', 'wp-simple-firewall' ),
74
+ 'text' => __( 'Email OTP', 'wp-simple-firewall' ),
75
+ 'help_link' => 'https://shsec.io/3t'
76
+ ];
77
+ }
78
+
79
+ /**
80
+ * We don't use user meta as it's dependent on the particular user sessions in-use
81
+ * @param \WP_User $oUser
82
+ * @return string
83
+ */
84
+ protected function getSecret( \WP_User $oUser ) {
85
+ /** @var \ICWP_WPSF_FeatureHandler_LoginProtect $oMod */
86
+ $oMod = $this->getMod();
87
+ return strtoupper( substr(
88
+ hash_hmac( 'sha1', $this->getCon()->getUniqueRequestId(), $oMod->getTwoAuthSecretKey() ),
89
+ 0, 6
90
+ ) );
91
+ }
92
+
93
+ /**
94
+ * @return string The unique 2FA 6-digit code
95
+ */
96
+ protected function getStoredSessionHashCode() {
97
+ /** @var \ICWP_WPSF_FeatureHandler_LoginProtect $oMod */
98
+ $oMod = $this->getMod();
99
+ return $oMod->hasSession() ? $oMod->getSession()->getLoginIntentCodeEmail() : '';
100
+ }
101
+
102
+ /**
103
+ * @inheritDoc
104
+ */
105
+ public function handleUserProfileSubmit( \WP_User $oUser ) {
106
+
107
+ $bWasEnabled = $this->isProfileActive( $oUser );
108
+ $bToEnable = Services::Request()->post( 'shield_enable_mfaemail' ) === 'Y';
109
+
110
+ $sMsg = null;
111
+ $bError = false;
112
+ if ( $bToEnable ) {
113
+ $this->setProfileValidated( $oUser );
114
+ if ( !$bWasEnabled ) {
115
+ $sMsg = __( 'Email Two-Factor Authentication has been enabled.', 'wp-simple-firewall' );
116
+ }
117
+ }
118
+ elseif ( $this->isEnforced( $oUser ) ) {
119
+ $sMsg = __( "Email Two-Factor Authentication couldn't be disabled because it is enforced based on your user roles.", 'wp-simple-firewall' );
120
+ $bError = true;
121
+ }
122
+ else {
123
+ $this->setProfileValidated( $oUser, false );
124
+ $sMsg = __( 'Email Two-Factor Authentication was has been disabled.', 'wp-simple-firewall' );
125
+ }
126
+
127
+ if ( !empty( $sMsg ) ) {
128
+ $this->getMod()->setFlashAdminNotice( $sMsg, $bError );
129
+ }
130
+ }
131
+
132
+ /**
133
+ * @param \WP_User $oUser
134
+ * @return bool
135
+ */
136
+ public function isProfileActive( \WP_User $oUser ) {
137
+ /** @var LoginGuard\Options $oOpts */
138
+ $oOpts = $this->getOptions();
139
+ return parent::isProfileActive( $oUser ) &&
140
+ ( $this->isEnforced( $oUser ) ||
141
+ ( $this->hasValidatedProfile( $oUser ) && $oOpts->isEnabledEmailAuthAnyUserSet() ) );
142
+ }
143
+
144
+ /**
145
+ * @param \WP_User $oUser
146
+ * @return bool
147
+ */
148
+ protected function isEnforced( $oUser ) {
149
+ /** @var LoginGuard\Options $oOpts */
150
+ $oOpts = $this->getOptions();
151
+ return count( array_intersect( $oOpts->getEmail2FaRoles(), $oUser->roles ) ) > 0;
152
+ }
153
+
154
+ /**
155
+ * @param \WP_User $oUser
156
+ * @return $this
157
+ */
158
+ private function sendEmailTwoFactorVerify( \WP_User $oUser ) {
159
+ $aMessage = [
160
+ __( 'Someone attempted to login into this WordPress site using your account.', 'wp-simple-firewall' ),
161
+ __( 'Login requires verification with the following code.', 'wp-simple-firewall' ),
162
+ '',
163
+ sprintf( __( 'Verification Code: %s', 'wp-simple-firewall' ), sprintf( '<strong>%s</strong>', $this->getSecret( $oUser ) ) ),
164
+ '',
165
+ sprintf( '<strong>%s</strong>', __( 'Login Details', 'wp-simple-firewall' ) ),
166
+ sprintf( '%s: %s', __( 'URL', 'wp-simple-firewall' ), Services::WpGeneral()->getHomeUrl() ),
167
+ sprintf( '%s: %s', __( 'Username', 'wp-simple-firewall' ), $oUser->user_login ),
168
+ sprintf( '%s: %s', __( 'IP Address', 'wp-simple-firewall' ), Services::IP()->getRequestIp() ),
169
+ '',
170
+ ];
171
+
172
+ if ( !$this->getCon()->isRelabelled() ) {
173
+ $aMessage[] = sprintf( '- <a href="%s" target="_blank">%s</a>', 'https://shsec.io/96', __( 'Why no login link?', 'wp-simple-firewall' ) );
174
+ $aContent[] = '';
175
+ }
176
+
177
+ $bResult = $this->getMod()
178
+ ->getEmailProcessor()
179
+ ->sendEmailWithWrap(
180
+ $oUser->user_email,
181
+ __( 'Two-Factor Login Verification', 'wp-simple-firewall' ),
182
+ $aMessage
183
+ );
184
+
185
+ $this->getCon()->fireEvent(
186
+ $bResult ? '2fa_email_send_success' : '2fa_email_send_fail',
187
+ [
188
+ 'audit' => [
189
+ 'user_login' => $oUser->user_login,
190
+ ]
191
+ ]
192
+ );
193
+ return $this;
194
+ }
195
+
196
+ /**
197
+ * @inheritDoc
198
+ */
199
+ public function renderUserProfileOptions( \WP_User $oUser ) {
200
+ $aData = [
201
+ 'strings' => [
202
+ 'label_email_authentication' => __( 'Email Authentication', 'wp-simple-firewall' ),
203
+ 'title' => __( 'Email Authentication', 'wp-simple-firewall' ),
204
+ 'description_email_authentication_checkbox' => __( 'Check the box to enable email-based login authentication.', 'wp-simple-firewall' ),
205
+ 'provided_by' => sprintf( __( 'Provided by %s', 'wp-simple-firewall' ), $this->getCon()
206
+ ->getHumanName() )
207
+ ]
208
+ ];
209
+
210
+ return $this->getMod()
211
+ ->renderTemplate(
212
+ '/snippets/user/profile/mfa/mfa_email.twig',
213
+ Services::DataManipulation()->mergeArraysRecursive( $this->getCommonData( $oUser ), $aData ),
214
+ true
215
+ );
216
+ }
217
+
218
+ /**
219
+ * @return bool
220
+ */
221
+ public function isProviderEnabled() {
222
+ /** @var LoginGuard\Options $oOpts */
223
+ $oOpts = $this->getOptions();
224
+ return $oOpts->isEmailAuthenticationActive();
225
+ }
226
+
227
+ /**
228
+ * @param \WP_User $oUser
229
+ * @return bool
230
+ */
231
+ public function isProviderAvailableToUser( \WP_User $oUser ) {
232
+ /** @var LoginGuard\Options $oOpts */
233
+ $oOpts = $this->getOptions();
234
+ return parent::isProviderAvailableToUser( $oUser )
235
+ && ( $this->isEnforced( $oUser ) || $oOpts->isEnabledEmailAuthAnyUserSet() );
236
+ }
237
+ }
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/GoogleAuth.php ADDED
@@ -0,0 +1,260 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor\Provider;
4
+
5
+ use Dolondro\GoogleAuthenticator;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
7
+ use FernleafSystems\Wordpress\Services\Services;
8
+
9
+ class GoogleAuth extends BaseProvider {
10
+
11
+ const SLUG = 'ga';
12
+
13
+ /**
14
+ * @var GoogleAuthenticator\Secret
15
+ */
16
+ private $oWorkingSecret;
17
+
18
+ /**
19
+ * @param \WP_User $oUser
20
+ * @return bool
21
+ */
22
+ public function isProfileActive( \WP_User $oUser ) {
23
+ return $this->hasValidSecret( $oUser ) && $this->hasValidatedProfile( $oUser );
24
+ }
25
+
26
+ /**
27
+ * @inheritDoc
28
+ */
29
+ public function renderUserProfileOptions( \WP_User $oUser ) {
30
+ $oCon = $this->getCon();
31
+
32
+ $bValidatedProfile = $this->hasValidatedProfile( $oUser );
33
+
34
+ $aData = [
35
+ 'hrefs' => [
36
+ 'src_chart_url' => $bValidatedProfile ? '' : $this->getGaRegisterChartUrl( $oUser ),
37
+ ],
38
+ 'vars' => [
39
+ 'ga_secret' => $bValidatedProfile ? $this->getSecret( $oUser ) : $this->resetSecret( $oUser ),
40
+ ],
41
+ 'strings' => [
42
+ 'enter_auth_app_code' => __( 'Enter the 6-digit code from your Authenticator App', 'wp-simple-firewall' ),
43
+ 'description_otp_code' => __( 'Provide the current code generated by your Google Authenticator app.', 'wp-simple-firewall' ),
44
+ 'description_chart_url' => __( 'Use your Google Authenticator app to scan this QR code and enter the 6-digit one time password.', 'wp-simple-firewall' ),
45
+ 'description_ga_secret' => __( 'If you have a problem with scanning the QR code enter the long code manually into the app.', 'wp-simple-firewall' ),
46
+ 'desc_remove' => __( 'Check the box to remove Google Authenticator login authentication.', 'wp-simple-firewall' ),
47
+ 'label_check_to_remove' => sprintf( __( 'Remove %s', 'wp-simple-firewall' ), __( 'Google Authenticator', 'wp-simple-firewall' ) ),
48
+ 'label_enter_code' => __( 'Google Authenticator Code', 'wp-simple-firewall' ),
49
+ 'label_ga_secret' => __( 'Manual Code', 'wp-simple-firewall' ),
50
+ 'label_scan_qr_code' => __( 'Scan This QR Code', 'wp-simple-firewall' ),
51
+ 'title' => __( 'Google Authenticator', 'wp-simple-firewall' ),
52
+ 'cant_add_other_user' => sprintf( __( "Sorry, %s may not be added to another user's account.", 'wp-simple-firewall' ), 'Google Authenticator' ),
53
+ 'cant_remove_admins' => sprintf( __( "Sorry, %s may only be removed from another user's account by a Security Administrator.", 'wp-simple-firewall' ), __( 'Google Authenticator', 'wp-simple-firewall' ) ),
54
+ 'provided_by' => sprintf( __( 'Provided by %s', 'wp-simple-firewall' ), $oCon->getHumanName() ),
55
+ 'remove_more_info' => sprintf( __( 'Understand how to remove Google Authenticator', 'wp-simple-firewall' ) )
56
+ ],
57
+ ];
58
+
59
+ return $this->getMod()
60
+ ->renderTemplate(
61
+ '/snippets/user/profile/mfa/mfa_ga.twig',
62
+ Services::DataManipulation()->mergeArraysRecursive( $this->getCommonData( $oUser ), $aData ),
63
+ true
64
+ );
65
+ }
66
+
67
+ /**
68
+ * @param \WP_User $oUser
69
+ * @return string
70
+ */
71
+ public function getGaRegisterChartUrl( $oUser ) {
72
+ $sUrl = '';
73
+ if ( !empty( $oUser ) ) {
74
+ try {
75
+ $sUrl = ( new GoogleAuthenticator\QrImageGenerator\GoogleQrImageGenerator () )
76
+ ->generateUri(
77
+ $this->getGaSecret( $oUser )
78
+ );
79
+ }
80
+ catch ( \InvalidArgumentException $e ) {
81
+ }
82
+ }
83
+ return $sUrl;
84
+ }
85
+
86
+ /**
87
+ * The only thing we can do is REMOVE Google Authenticator from an account that is not our own
88
+ * But, only admins can do this. If Security Admin feature is enabled, then only they can do it.
89
+ * @inheritDoc
90
+ */
91
+ public function handleEditOtherUserProfileSubmit( \WP_User $oUser ) {
92
+
93
+ // Can only edit other users if you're admin/security-admin
94
+ if ( $this->getCon()->isPluginAdmin() && Services::Request()->post( 'shield_turn_off_ga' ) === 'Y' ) {
95
+ $this->processRemovalFromAccount( $oUser );
96
+ $sMsg = __( 'Google Authenticator was successfully removed from the account.', 'wp-simple-firewall' );
97
+ $this->getMod()->setFlashAdminNotice( $sMsg );
98
+ }
99
+ }
100
+
101
+ /**
102
+ * @param \WP_User $oUser
103
+ * @return $this
104
+ */
105
+ protected function processRemovalFromAccount( $oUser ) {
106
+ $this->setProfileValidated( $oUser, false )
107
+ ->resetSecret( $oUser );
108
+ return $this;
109
+ }
110
+
111
+ /**
112
+ * @inheritDoc
113
+ */
114
+ public function handleUserProfileSubmit( \WP_User $oUser ) {
115
+ $sOtp = $this->fetchCodeFromRequest();
116
+
117
+ if ( Services::Request()->post( 'shield_turn_off_ga' ) === 'Y' ) {
118
+ $sFlash = __( 'Google Authenticator was successfully removed from the account.', 'wp-simple-firewall' );
119
+ $this->processRemovalFromAccount( $oUser );
120
+ $this->getMod()->setFlashAdminNotice( $sFlash );
121
+ /**
122
+ * $sFlash = __( 'An email has been sent to you in order to confirm Google Authenticator removal', 'wp-simple-firewall' );
123
+ * $sFlash = __( 'We tried to send an email for you to confirm Google Authenticator removal but it failed.', 'wp-simple-firewall' );
124
+ */
125
+ }
126
+ elseif ( !empty( $sOtp ) && !$this->hasValidatedProfile( $oUser ) ) { // Add GA to profile
127
+ $bValidOtp = $this->processOtp( $oUser, $sOtp );
128
+ if ( $bValidOtp ) {
129
+ $this->setProfileValidated( $oUser );
130
+ $sFlash = sprintf(
131
+ __( '%s was successfully added to your account.', 'wp-simple-firewall' ),
132
+ __( 'Google Authenticator', 'wp-simple-firewall' )
133
+ );
134
+ }
135
+ else {
136
+ $this->resetSecret( $oUser );
137
+ $sFlash = __( 'One Time Password (OTP) was not valid.', 'wp-simple-firewall' )
138
+ .' '.__( 'Please try again.', 'wp-simple-firewall' );
139
+ }
140
+ $this->getMod()->setFlashAdminNotice( $sFlash, !$bValidOtp );
141
+ }
142
+ }
143
+
144
+ /**
145
+ * @return array
146
+ */
147
+ public function getFormField() {
148
+ return [
149
+ 'name' => $this->getLoginFormParameter(),
150
+ 'type' => 'text',
151
+ 'value' => '',
152
+ 'placeholder' => __( 'Please use your Google Authenticator App to retrieve your code.', 'wp-simple-firewall' ),
153
+ 'text' => __( 'Google Authenticator Code', 'wp-simple-firewall' ),
154
+ 'help_link' => 'https://shsec.io/wpsf42',
155
+ 'extras' => [
156
+ 'onkeyup' => "this.value=this.value.replace(/[^\d]/g,'')"
157
+ ]
158
+ ];
159
+ }
160
+
161
+ /**
162
+ * @param \WP_User $oUser
163
+ * @param string $sOtpCode
164
+ * @return bool
165
+ */
166
+ protected function processOtp( $oUser, $sOtpCode ) {
167
+ return $this->validateGaCode( $oUser, $sOtpCode );
168
+ }
169
+
170
+ /**
171
+ * @param \WP_User $oUser
172
+ * @param string $sOtpCode
173
+ * @return bool
174
+ */
175
+ public function validateGaCode( $oUser, $sOtpCode ) {
176
+ $bValidOtp = false;
177
+ if ( preg_match( '#^[0-9]{6}$#', $sOtpCode ) ) {
178
+ try {
179
+ $bValidOtp = ( new GoogleAuthenticator\GoogleAuthenticator() )
180
+ ->authenticate( $this->getSecret( $oUser ), $sOtpCode );
181
+ }
182
+ catch ( \Exception $oE ) {
183
+ }
184
+ catch ( \Psr\Cache\CacheException $oE ) {
185
+ }
186
+ }
187
+ return $bValidOtp;
188
+ }
189
+
190
+ /**
191
+ * @param \WP_User $oUser
192
+ * @param bool $bIsSuccess
193
+ */
194
+ protected function auditLogin( $oUser, $bIsSuccess ) {
195
+ $this->getCon()->fireEvent(
196
+ $bIsSuccess ? 'googleauth_verified' : 'googleauth_fail',
197
+ [
198
+ 'audit' => [
199
+ 'user_login' => $oUser->user_login,
200
+ 'method' => 'Google Authenticator',
201
+ ]
202
+ ]
203
+ );
204
+ }
205
+
206
+ /**
207
+ * @param \WP_User $oUser
208
+ * @return string
209
+ */
210
+ protected function genNewSecret( \WP_User $oUser ) {
211
+ try {
212
+ return $this->getGaSecret( $oUser )->getSecretKey();
213
+ }
214
+ catch ( \InvalidArgumentException $oE ) {
215
+ return '';
216
+ }
217
+ }
218
+
219
+ /**
220
+ * @param \WP_User $oUser
221
+ * @return GoogleAuthenticator\Secret
222
+ * @throws \InvalidArgumentException
223
+ */
224
+ private function getGaSecret( $oUser ) {
225
+ if ( !isset( $this->oWorkingSecret ) ) {
226
+ $this->oWorkingSecret = ( new GoogleAuthenticator\SecretFactory() )
227
+ ->create(
228
+ sanitize_user( $oUser->user_login ),
229
+ preg_replace( '#[^0-9a-z]#i', '', Services::WpGeneral()->getSiteName() )
230
+ );
231
+ }
232
+ return $this->oWorkingSecret;
233
+ }
234
+
235
+ /**
236
+ * @param \WP_User $oUser
237
+ * @return string
238
+ */
239
+ protected function getSecret( \WP_User $oUser ) {
240
+ $sSec = parent::getSecret( $oUser );
241
+ return empty( $sSec ) ? $this->resetSecret( $oUser ) : $sSec;
242
+ }
243
+
244
+ /**
245
+ * @param string $sSecret
246
+ * @return bool
247
+ */
248
+ protected function isSecretValid( $sSecret ) {
249
+ return parent::isSecretValid( $sSecret ) && ( strlen( $sSecret ) == 16 );
250
+ }
251
+
252
+ /**
253
+ * @return bool
254
+ */
255
+ public function isProviderEnabled() {
256
+ /** @var LoginGuard\Options $oOpts */
257
+ $oOpts = $this->getOptions();
258
+ return $oOpts->isEnabledGoogleAuthenticator();
259
+ }
260
+ }
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Yubikey.php ADDED
@@ -0,0 +1,254 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor\Provider;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
+
8
+ class Yubikey extends BaseProvider {
9
+
10
+ const SLUG = 'yubi';
11
+ const OTP_LENGTH = 12;
12
+ const URL_YUBIKEY_VERIFY = 'https://api.yubico.com/wsapi/2.0/verify';
13
+
14
+ /**
15
+ * @param \WP_User $oUser
16
+ * @return bool
17
+ */
18
+ public function isProfileActive( \WP_User $oUser ) {
19
+ return $this->hasValidSecret( $oUser );
20
+ }
21
+
22
+ /**
23
+ * @inheritDoc
24
+ */
25
+ public function renderUserProfileOptions( \WP_User $oUser ) {
26
+ $oCon = $this->getCon();
27
+
28
+ $aData = [
29
+ 'vars' => [
30
+ 'yubi_ids' => $this->getYubiIds( $oUser ),
31
+ ],
32
+ 'strings' => [
33
+ 'current_yubi_ids' => __( 'Registered Yubikey devices', 'wp-simple-firewall' ),
34
+ 'no_active_yubi_ids' => __( 'There are no registered Yubikey devices on this profile.', 'wp-simple-firewall' ),
35
+ 'enter_otp' => __( 'To register a new Yubikey device, enter a One Time Password from the Yubikey.', 'wp-simple-firewall' ),
36
+ 'to_remove_device' => __( 'To remove a Yubikey device, enter the registered device ID and save.', 'wp-simple-firewall' ),
37
+ 'multiple_for_pro' => sprintf( '[%s] %s', __( 'Pro Only', 'wp-simple-firewall' ),
38
+ __( 'You may add as many Yubikey devices to your profile as you need to.', 'wp-simple-firewall' ) ),
39
+ 'description_otp_code' => __( 'This is your unique Yubikey Device ID.', 'wp-simple-firewall' ),
40
+ 'description_otp' => __( 'Provide a One Time Password from your Yubikey.', 'wp-simple-firewall' ),
41
+ 'label_enter_code' => __( 'Yubikey ID', 'wp-simple-firewall' ),
42
+ 'label_enter_otp' => __( 'Yubikey OTP', 'wp-simple-firewall' ),
43
+ 'title' => __( 'Yubikey Authentication', 'wp-simple-firewall' ),
44
+ 'cant_add_other_user' => sprintf( __( "Sorry, %s may not be added to another user's account.", 'wp-simple-firewall' ), 'Yubikey' ),
45
+ 'cant_remove_admins' => sprintf( __( "Sorry, %s may only be removed from another user's account by a Security Administrator.", 'wp-simple-firewall' ), __( 'Yubikey', 'wp-simple-firewall' ) ),
46
+ 'provided_by' => sprintf( __( 'Provided by %s', 'wp-simple-firewall' ), $oCon->getHumanName() ),
47
+ 'remove_more_info' => sprintf( __( 'Understand how to remove Google Authenticator', 'wp-simple-firewall' ) )
48
+ ],
49
+ ];
50
+
51
+ return $this->getMod()
52
+ ->renderTemplate(
53
+ '/snippets/user/profile/mfa/mfa_yubikey.twig',
54
+ Services::DataManipulation()->mergeArraysRecursive( $this->getCommonData( $oUser ), $aData ),
55
+ true
56
+ );
57
+ }
58
+
59
+ /**
60
+ * @inheritDoc
61
+ */
62
+ public function handleUserProfileSubmit( \WP_User $oUser ) {
63
+
64
+ // If it's your own account, you CANT do anything without your OTP (except turn off via email).
65
+ $sOtpOrDeviceId = trim( (string)$this->fetchCodeFromRequest() );
66
+ if ( empty( $sOtpOrDeviceId ) ) {
67
+ return;
68
+ }
69
+
70
+ $bError = true;
71
+ $aRegisteredDevices = $this->getYubiIds( $oUser );
72
+
73
+ if ( strlen( $sOtpOrDeviceId ) < self::OTP_LENGTH ) {
74
+ $sMsg = __( 'The Yubikey device ID was not valid.', 'wp-simple-firewall' )
75
+ .' '.__( 'Please try again.', 'wp-simple-firewall' );
76
+ }
77
+ else {
78
+ $sDeviceId = substr( $sOtpOrDeviceId, 0, self::OTP_LENGTH );
79
+ $bDeviceRegistered = in_array( $sDeviceId, $aRegisteredDevices );
80
+
81
+ if ( $bDeviceRegistered || strlen( $sOtpOrDeviceId ) == self::OTP_LENGTH ) { // attempt to remove device
82
+
83
+ if ( $bDeviceRegistered ) {
84
+ $this->addRemoveRegisteredYubiId( $oUser, $sDeviceId, false );
85
+ $sMsg = sprintf(
86
+ __( '%s was removed from your profile.', 'wp-simple-firewall' ),
87
+ __( 'Yubikey Device', 'wp-simple-firewall' ).sprintf( ' (%s)', $sDeviceId )
88
+ );
89
+ $bError = false;
90
+ }
91
+ else {
92
+ $sMsg = __( "That Yubikey device ID wasn't found on your profile", 'wp-simple-firewall' );
93
+ }
94
+ }
95
+ elseif ( $this->sendYubiOtpRequest( $sOtpOrDeviceId ) ) { // A full OTP was provided so we're adding a new one
96
+ if ( count( $aRegisteredDevices ) == 0 || $this->getCon()->isPremiumActive() ) {
97
+ $this->addRemoveRegisteredYubiId( $oUser, $sDeviceId, true );
98
+ $sMsg = sprintf(
99
+ __( '%s was added to your profile.', 'wp-simple-firewall' ),
100
+ __( 'Yubikey Device', 'wp-simple-firewall' ).sprintf( ' (%s)', $sDeviceId )
101
+ );
102
+ $bError = false;
103
+ }
104
+ else {
105
+ $sMsg = __( 'No further Yubikey devices may be added to your account at this time.', 'wp-simple-firewall' );
106
+ }
107
+ }
108
+ else {
109
+ $sMsg = __( 'One Time Password (OTP) was not valid.', 'wp-simple-firewall' )
110
+ .' '.__( 'Please try again.', 'wp-simple-firewall' );
111
+ }
112
+ }
113
+
114
+ $this->setProfileValidated( $oUser, $this->hasValidSecret( $oUser ) );
115
+ $this->getMod()->setFlashAdminNotice( $sMsg, $bError );
116
+ }
117
+
118
+ /**
119
+ * @param \WP_User $oUser
120
+ * @return array
121
+ */
122
+ private function getYubiIds( \WP_User $oUser ) {
123
+ return explode( ',', $this->getSecret( $oUser ) );
124
+ }
125
+
126
+ /**
127
+ * @param \WP_User $oUser
128
+ * @param string $sOneTimePassword
129
+ * @return bool
130
+ */
131
+ protected function processOtp( $oUser, $sOneTimePassword ) {
132
+ $bSuccess = false;
133
+
134
+ foreach ( $this->getYubiIds( $oUser ) as $sKey ) {
135
+ if ( strpos( $sOneTimePassword, $sKey ) === 0
136
+ && $this->sendYubiOtpRequest( $sOneTimePassword ) ) {
137
+ $bSuccess = true;
138
+ break;
139
+ }
140
+ if ( !$this->getCon()->isPremiumActive() ) { // Test 1 key if not Pro
141
+ break;
142
+ }
143
+ }
144
+
145
+ return $bSuccess;
146
+ }
147
+
148
+ /**
149
+ * @param string $sOTP
150
+ * @return bool
151
+ */
152
+ private function sendYubiOtpRequest( $sOTP ) {
153
+ /** @var LoginGuard\Options $oOpts */
154
+ $oOpts = $this->getOptions();
155
+ $sOTP = trim( $sOTP );
156
+ $bSuccess = false;
157
+
158
+ if ( preg_match( '#^[a-z]{44}$#', $sOTP ) ) {
159
+ $aParts = [
160
+ 'otp' => $sOTP,
161
+ 'nonce' => md5( uniqid( $this->getCon()->getUniqueRequestId() ) ),
162
+ 'id' => $oOpts->getYubikeyAppId()
163
+ ];
164
+
165
+ $sResp = Services::HttpRequest()->getContent(
166
+ add_query_arg( $aParts, self::URL_YUBIKEY_VERIFY )
167
+ );
168
+
169
+ unset( $aParts[ 'id' ] );
170
+ $aParts[ 'status' ] = 'OK';
171
+
172
+ $bSuccess = true;
173
+ foreach ( $aParts as $sKey => $mVal ) {
174
+ if ( !preg_match( sprintf( '#%s=%s#', $sKey, $mVal ), $sResp ) ) {
175
+ $bSuccess = false;
176
+ break;
177
+ }
178
+ }
179
+ }
180
+
181
+ return $bSuccess;
182
+ }
183
+
184
+ /**
185
+ * @param \WP_User $oUser
186
+ * @param string $sKey
187
+ * @param bool $bAdd - true to add; false to remove
188
+ * @return $this
189
+ */
190
+ private function addRemoveRegisteredYubiId( \WP_User $oUser, $sKey, $bAdd = true ) {
191
+ $aIDs = $this->getYubiIds( $oUser );
192
+ if ( $bAdd ) {
193
+ $aIDs[] = $sKey;
194
+ }
195
+ else {
196
+ $aIDs = Services::DataManipulation()->removeFromArrayByValue( $aIDs, $sKey );
197
+ }
198
+ return $this->setSecret( $oUser, implode( ',', array_unique( array_filter( $aIDs ) ) ) );
199
+ }
200
+
201
+ /**
202
+ * @param \WP_User $oUser
203
+ * @param bool $bIsSuccess
204
+ */
205
+ protected function auditLogin( $oUser, $bIsSuccess ) {
206
+ $this->getCon()->fireEvent(
207
+ $bIsSuccess ? 'yubikey_verified' : 'yubikey_fail',
208
+ [
209
+ 'audit' => [
210
+ 'user_login' => $oUser->user_login,
211
+ 'method' => 'Yubikey',
212
+ ]
213
+ ]
214
+ );
215
+ }
216
+
217
+ /**
218
+ * @return array
219
+ */
220
+ public function getFormField() {
221
+ return [
222
+ 'name' => $this->getLoginFormParameter(),
223
+ 'type' => 'text',
224
+ 'placeholder' => __( 'Use your Yubikey to generate a new code.', 'wp-simple-firewall' ),
225
+ 'value' => '',
226
+ 'text' => __( 'Yubikey OTP', 'wp-simple-firewall' ),
227
+ 'help_link' => 'https://shsec.io/4i'
228
+ ];
229
+ }
230
+
231
+ /**
232
+ * @return bool
233
+ */
234
+ public function isProviderEnabled() {
235
+ /** @var LoginGuard\Options $oOpts */
236
+ $oOpts = $this->getOptions();
237
+ return $oOpts->isEnabledYubikey();
238
+ }
239
+
240
+ /**
241
+ * @param string $sSecret
242
+ * @return bool
243
+ */
244
+ protected function isSecretValid( $sSecret ) {
245
+ $bValid = parent::isSecretValid( $sSecret );
246
+ if ( $bValid ) {
247
+ foreach ( explode( ',', $sSecret ) as $sId ) {
248
+ $bValid = $bValid &&
249
+ preg_match( sprintf( '#^[a-z]{%s}$#', self::OTP_LENGTH ), $sId );
250
+ }
251
+ }
252
+ return $bValid;
253
+ }
254
+ }
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/UserProfile.php ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
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() ) { // TODO: standalone UI based on shortcodes
14
+ add_action( 'show_user_profile', [ $this, 'addOptionsToUserProfile' ] );
15
+ add_action( 'personal_options_update', [ $this, 'handleUserProfileSubmit' ] );
16
+ if ( $this->getMfaCon()->getCon()->isPluginAdmin() ) {
17
+ add_action( 'edit_user_profile', [ $this, 'addOptionsToUserEditProfile' ] );
18
+ add_action( 'edit_user_profile_update', [ $this, 'handleEditOtherUserProfileSubmit' ] );
19
+ }
20
+ }
21
+ }
22
+
23
+ /**
24
+ * This MUST only ever be hooked into when the User is looking at their OWN profile, so we can use "current user"
25
+ * functions. Otherwise we need to be careful of mixing up users.
26
+ * @param \WP_User $oUser
27
+ */
28
+ public function addOptionsToUserProfile( $oUser ) {
29
+ $oMC = $this->getMfaCon();
30
+ $oWpUsers = Services::WpUsers();
31
+ $aProviders = $oMC->getProvidersForUser( $oUser );
32
+ if ( count( $aProviders ) > 0 ) {
33
+ $aRows = [];
34
+ foreach ( $aProviders as $oProvider ) {
35
+ $aRows[ $oProvider::SLUG ] = $oProvider->renderUserProfileOptions( $oUser );
36
+ }
37
+
38
+ $aData = [
39
+ 'is_my_user_profile' => ( $oUser->ID == $oWpUsers->getCurrentWpUserId() ),
40
+ 'i_am_valid_admin' => $oMC->getCon()->isPluginAdmin(),
41
+ 'user_to_edit_is_admin' => $oWpUsers->isUserAdmin( $oUser ),
42
+ 'strings' => [
43
+ 'title' => __( 'Multi-Factor Authentication', 'wp-simple-firewall' ),
44
+ 'provided_by' => sprintf( __( 'Provided by %s', 'wp-simple-firewall' ), $oMC->getCon()
45
+ ->getHumanName() )
46
+ ],
47
+ 'mfa_rows' => $aRows
48
+ ];
49
+
50
+ echo $oMC->getMod()
51
+ ->renderTemplate(
52
+ '/snippets/user/profile/mfa/mfa_container.twig',
53
+ $aData,
54
+ true
55
+ );
56
+ }
57
+ }
58
+
59
+ /**
60
+ * This MUST only ever be hooked into when the User is looking at their OWN profile,
61
+ * so we can use "current user" functions. Otherwise we need to be careful of mixing up users.
62
+ * @param int $nSavingUserId
63
+ */
64
+ public function handleUserProfileSubmit( $nSavingUserId ) {
65
+ $oUser = Services::WpUsers()->getUserById( $nSavingUserId );
66
+ foreach ( $this->getMfaCon()->getProvidersForUser( $oUser ) as $oProvider ) {
67
+ $oProvider->handleUserProfileSubmit( $oUser );
68
+ }
69
+ }
70
+
71
+ /**
72
+ * ONLY TO BE HOOKED TO USER PROFILE EDIT
73
+ * @param \WP_User $oUser
74
+ */
75
+ public function addOptionsToUserEditProfile( $oUser ) {
76
+ $this->addOptionsToUserProfile( $oUser );
77
+ }
78
+
79
+ /**
80
+ * The only thing we can do is REMOVE Google Authenticator from an account that is not our own
81
+ * But, only admins can do this. If Security Admin feature is enabled, then only they can do it.
82
+ * @param int $nSavingUserId
83
+ */
84
+ public function handleEditOtherUserProfileSubmit( $nSavingUserId ) {
85
+ $oUser = Services::WpUsers()->getUserById( $nSavingUserId );
86
+ foreach ( $this->getMfaCon()->getProvidersForUser( $oUser ) as $oProvider ) {
87
+ $oProvider->handleEditOtherUserProfileSubmit( $oUser );
88
+ }
89
+ }
90
+ }
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/ValidateLoginIntentRequest.php ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor\Provider;
8
+ use FernleafSystems\Wordpress\Services\Services;
9
+
10
+ class ValidateLoginIntentRequest {
11
+
12
+ use MfaControllerConsumer;
13
+
14
+ /**
15
+ * @return bool
16
+ * @throws \Exception
17
+ */
18
+ public function run() {
19
+ $oMfaCon = $this->getMfaCon();
20
+ /** @var LoginGuard\Options $oOpts */
21
+ $oOpts = $oMfaCon->getOptions();
22
+
23
+ $oUser = Services::WpUsers()->getCurrentWpUser();
24
+ if ( !$oUser instanceof \WP_User ) {
25
+ throw new \Exception( 'No user logged-in.' );
26
+ }
27
+ $aProviders = $oMfaCon->getProvidersForUser( $oUser, true );
28
+ if ( empty( $aProviders ) ) {
29
+ throw new \Exception( 'No valid providers' );
30
+ }
31
+
32
+ $aSuccessfulProviders = [];
33
+
34
+ $bValidated = false;
35
+ { // Backup code is special case
36
+ if ( isset( $aProviders[ Provider\Backup::SLUG ] ) ) {
37
+ if ( $aProviders[ Provider\Backup::SLUG ]->validateLoginIntent( $oUser ) ) {
38
+ $bValidated = true;
39
+ $aSuccessfulProviders[] = $aProviders[ Provider\Backup::SLUG ];
40
+ }
41
+ unset( $aProviders[ Provider\Backup::SLUG ] );
42
+ }
43
+ }
44
+
45
+ if ( !$bValidated ) {
46
+ $aStates = [];
47
+ foreach ( $aProviders as $sSlug => $oProvider ) {
48
+ $aStates[ $sSlug ] = $oProvider->validateLoginIntent( $oUser );
49
+ if ( $aStates[ $sSlug ] ) {
50
+ $aSuccessfulProviders[] = $oProvider;
51
+ }
52
+ }
53
+
54
+ $nSuccessful = count( array_filter( $aStates ) );
55
+ $bValidated = $oOpts->isChainedAuth() ? $nSuccessful == count( $aProviders ) : $nSuccessful > 0;
56
+ }
57
+
58
+ if ( $bValidated ) {
59
+ // Some cleanup can only run if login is completely tested and completely valid.
60
+ foreach ( $aSuccessfulProviders as $oProvider ) {
61
+ $oProvider->postSuccessActions( $oUser );
62
+ }
63
+ }
64
+
65
+ return $bValidated;
66
+ }
67
+ }
src/lib/src/Modules/LoginGuard/Options.php CHANGED
@@ -10,6 +10,65 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
10
  */
11
  class Options extends Base\ShieldOptions {
12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  /**
14
  * @return bool
15
  */
@@ -18,9 +77,61 @@ class Options extends Base\ShieldOptions {
18
  }
19
 
20
  /**
21
- * @return int
 
22
  */
23
- public function getCooldownInterval() {
24
- return (int)$this->getOpt( 'login_limit_interval' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  }
26
  }
10
  */
11
  class Options extends Base\ShieldOptions {
12
 
13
+ /**
14
+ * @return int
15
+ */
16
+ public function getCooldownInterval() {
17
+ return (int)$this->getOpt( 'login_limit_interval' );
18
+ }
19
+
20
+ /**
21
+ * @return array
22
+ */
23
+ public function getEmail2FaRoles() {
24
+ /** @var \ICWP_WPSF_FeatureHandler_LoginProtect $oMod */
25
+ $oMod = $this->getMod();
26
+ $aRoles = $this->getOpt( 'two_factor_auth_user_roles', [] );
27
+ if ( empty( $aRoles ) || !is_array( $aRoles ) ) {
28
+ $aRoles = $oMod->getOptEmailTwoFactorRolesDefaults();
29
+ $this->setOpt( 'two_factor_auth_user_roles', $aRoles );
30
+ }
31
+ if ( $this->isPremium() ) {
32
+ $aRoles = apply_filters( 'odp-shield-2fa_email_user_roles', $aRoles );
33
+ }
34
+ return is_array( $aRoles ) ? $aRoles : $oMod->getOptEmailTwoFactorRolesDefaults();
35
+ }
36
+
37
+ /**
38
+ * @return bool
39
+ */
40
+ public function getIfCanSendEmailVerified() {
41
+ return (int)$this->getOpt( 'email_can_send_verified_at' ) > 0;
42
+ }
43
+
44
+ /**
45
+ * @return int - seconds
46
+ */
47
+ public function getMfaSkip() {
48
+ return DAY_IN_SECONDS*( $this->isPremium() ? (int)$this->getOpt( 'mfa_skip', 0 ) : 0 );
49
+ }
50
+
51
+ /**
52
+ * @return string
53
+ */
54
+ public function getYubikeyAppId() {
55
+ return (string)$this->getOpt( 'yubikey_app_id', '' );
56
+ }
57
+
58
+ /**
59
+ * @return bool
60
+ */
61
+ public function isMfaSkip() {
62
+ return $this->getMfaSkip() > 0;
63
+ }
64
+
65
+ /**
66
+ * @return bool
67
+ */
68
+ public function isChainedAuth() {
69
+ return $this->isOpt( 'enable_chained_authentication', 'Y' );
70
+ }
71
+
72
  /**
73
  * @return bool
74
  */
77
  }
78
 
79
  /**
80
+ * Also considers whether email sending ability has been verified
81
+ * @return bool
82
  */
83
+ public function isEmailAuthenticationActive() {
84
+ return $this->getIfCanSendEmailVerified() && $this->isEnabledEmailAuth();
85
+ }
86
+
87
+ /**
88
+ * @return bool
89
+ */
90
+ public function isEnabledEmailAuth() {
91
+ return $this->isOpt( 'enable_email_authentication', 'Y' );
92
+ }
93
+
94
+ /**
95
+ * @return bool
96
+ */
97
+ public function isEnabledEmailAuthAnyUserSet() {
98
+ return $this->isEmailAuthenticationActive() && $this->isOpt( 'email_any_user_set', 'Y' ) && $this->isPremium();
99
+ }
100
+
101
+ /**
102
+ * @return bool
103
+ */
104
+ public function isEnabledBackupCodes() {
105
+ return $this->isPremium() && $this->isOpt( 'allow_backupcodes', 'Y' );
106
+ }
107
+
108
+ /**
109
+ * @return bool
110
+ */
111
+ public function isEnabledGoogleAuthenticator() {
112
+ return $this->isOpt( 'enable_google_authenticator', 'Y' );
113
+ }
114
+
115
+ /**
116
+ * @return bool
117
+ */
118
+ public function isUseLoginIntentPage() {
119
+ return $this->isOpt( 'use_login_intent_page', true );
120
+ }
121
+
122
+ /**
123
+ * @return bool
124
+ */
125
+ public function isEnabledYubikey() {
126
+ return $this->isOpt( 'enable_yubikey', 'Y' ) && $this->isYubikeyConfigReady();
127
+ }
128
+
129
+ /**
130
+ * @return bool
131
+ */
132
+ private function isYubikeyConfigReady() {
133
+ $sAppId = $this->getOpt( 'yubikey_app_id' );
134
+ $sApiKey = $this->getOpt( 'yubikey_api_key' );
135
+ return !empty( $sAppId ) && !empty( $sApiKey );
136
  }
137
  }
src/lib/src/Modules/LoginGuard/Strings.php CHANGED
@@ -206,6 +206,12 @@ class Strings extends Base\Strings {
206
  $sDescription = __( 'All users will be required to verify their login by email-based two-factor authentication.', 'wp-simple-firewall' );
207
  break;
208
 
 
 
 
 
 
 
209
  case 'two_factor_auth_user_roles' :
210
  $sName = sprintf( '%s - %s', __( 'Enforce', 'wp-simple-firewall' ), __( 'Email Authentication', 'wp-simple-firewall' ) );
211
  $sSummary = __( 'All User Roles Subject To Email Authentication', 'wp-simple-firewall' );
206
  $sDescription = __( 'All users will be required to verify their login by email-based two-factor authentication.', 'wp-simple-firewall' );
207
  break;
208
 
209
+ case 'email_any_user_set' :
210
+ $sName = __( 'Allow Any User', 'wp-simple-firewall' );
211
+ $sSummary = __( 'Allow Any User To Turn-On Two-Factor Authentication By Email.', 'wp-simple-firewall' );
212
+ $sDescription = __( 'Any user can turn on two-factor authentication by email from their profile.', 'wp-simple-firewall' );
213
+ break;
214
+
215
  case 'two_factor_auth_user_roles' :
216
  $sName = sprintf( '%s - %s', __( 'Enforce', 'wp-simple-firewall' ), __( 'Email Authentication', 'wp-simple-firewall' ) );
217
  $sSummary = __( 'All User Roles Subject To Email Authentication', 'wp-simple-firewall' );
src/lib/src/Modules/Plugin/AdminNotices.php CHANGED
@@ -287,13 +287,14 @@ class AdminNotices extends Shield\Modules\Base\AdminNotices {
287
  * @return bool
288
  */
289
  protected function isDisplayNeeded( $oNotice ) {
 
290
  /** @var Options $oOpts */
291
  $oOpts = $this->getOptions();
292
 
293
  switch ( $oNotice->id ) {
294
 
295
  case 'override-forceoff':
296
- $bNeeded = $this->getCon()->getIfForceOffActive();
297
  break;
298
 
299
  case 'plugin-disabled':
287
  * @return bool
288
  */
289
  protected function isDisplayNeeded( $oNotice ) {
290
+ $oCon = $this->getCon();
291
  /** @var Options $oOpts */
292
  $oOpts = $this->getOptions();
293
 
294
  switch ( $oNotice->id ) {
295
 
296
  case 'override-forceoff':
297
+ $bNeeded = $oCon->getIfForceOffActive();
298
  break;
299
 
300
  case 'plugin-disabled':
src/lib/src/Modules/Plugin/Lib/WpHashesTokenManager.php CHANGED
@@ -6,6 +6,11 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
  use FernleafSystems\Wordpress\Services\Services;
7
  use FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes\Token;
8
 
 
 
 
 
 
9
  class WpHashesTokenManager {
10
 
11
  use ModConsumer;
@@ -15,12 +20,21 @@ class WpHashesTokenManager {
15
  */
16
  private $bCanRequestOverride = false;
17
 
 
 
 
 
 
 
 
 
 
18
  /**
19
  * @return string
20
  */
21
  public function getToken() {
22
 
23
- if ( $this->getCon()->isPremiumActive() ) {
24
  $aT = $this->loadToken();
25
  if ( $this->isExpired() && $this->canRequestNewToken() ) {
26
  $aT = $this->loadToken();
@@ -60,7 +74,10 @@ class WpHashesTokenManager {
60
  */
61
  private function canRequestNewToken() {
62
  return $this->getCanRequestOverride() ||
63
- Services::Request()->carbon()->subHour()->timestamp > $this->loadToken()[ 'attempt_at' ];
 
 
 
64
  }
65
 
66
  /**
6
  use FernleafSystems\Wordpress\Services\Services;
7
  use FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes\Token;
8
 
9
+ /**
10
+ * Class WpHashesTokenManager
11
+ * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Lib
12
+ * @deprecated 8.6.2
13
+ */
14
  class WpHashesTokenManager {
15
 
16
  use ModConsumer;
20
  */
21
  private $bCanRequestOverride = false;
22
 
23
+ public function run() {
24
+ add_action( $this->getCon()->prefix( 'event' ), function ( $sEventTag ) {
25
+ if ( $sEventTag === 'lic_check_success' ) {
26
+ $this->setCanRequestOverride( true )
27
+ ->getToken();
28
+ }
29
+ } );
30
+ }
31
+
32
  /**
33
  * @return string
34
  */
35
  public function getToken() {
36
 
37
+ if ( $this->getCon()->getModule_License()->getLicenseHandler()->getLicense()->isValid() ) {
38
  $aT = $this->loadToken();
39
  if ( $this->isExpired() && $this->canRequestNewToken() ) {
40
  $aT = $this->loadToken();
74
  */
75
  private function canRequestNewToken() {
76
  return $this->getCanRequestOverride() ||
77
+ (
78
+ Services::Request()->carbon()->subHours( 6 )->timestamp > $this->loadToken()[ 'attempt_at' ]
79
+ && $this->getCon()->getModule_License()->getLicenseHandler()->getLicense()->isValid()
80
+ );
81
  }
82
 
83
  /**
src/lib/src/Modules/Plugin/Options.php CHANGED
@@ -130,21 +130,4 @@ class Options extends Base\ShieldOptions {
130
  return $this->setOpt( 'enable_tracking', $bOnOrOff ? 'Y' : 'N' )
131
  ->setOpt( 'tracking_permission_set_at', Services::Request()->ts() );
132
  }
133
-
134
- /**
135
- * @return array
136
- * @deprecated 8.5.1
137
- */
138
- public function getServerIpDetails() {
139
- return [];
140
- }
141
-
142
- /**
143
- * @param array $aDetails
144
- * @return $this
145
- * @deprecated 8.5.1
146
- */
147
- public function updateServerIpDetails( $aDetails ) {
148
- return $this;
149
- }
150
  }
130
  return $this->setOpt( 'enable_tracking', $bOnOrOff ? 'Y' : 'N' )
131
  ->setOpt( 'tracking_permission_set_at', Services::Request()->ts() );
132
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
  }
src/lib/src/Modules/Plugin/Strings.php CHANGED
@@ -443,5 +443,8 @@ class Strings extends Base\Strings {
443
  __( 'Medium', 'wp-simple-firewall' );
444
  __( 'High', 'wp-simple-firewall' );
445
  __( 'Full', 'wp-simple-firewall' );
 
 
 
446
  }
447
  }
443
  __( 'Medium', 'wp-simple-firewall' );
444
  __( 'High', 'wp-simple-firewall' );
445
  __( 'Full', 'wp-simple-firewall' );
446
+
447
+ __( 'Last Offense', 'wp-simple-firewall' );
448
+ __( 'Automatic license verification failed.', 'wp-simple-firewall' );
449
  }
450
  }
src/lib/src/Modules/SecurityAdmin/Lib/WhiteLabel/ApplyLabels.php ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Lib\WhiteLabel;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin;
7
+ use FernleafSystems\Wordpress\Services\Services;
8
+
9
+ class ApplyLabels {
10
+
11
+ use ModConsumer;
12
+
13
+ /**
14
+ */
15
+ public function run() {
16
+ $oCon = $this->getCon();
17
+ add_action( 'init', [ $this, 'onWpInit' ] );
18
+ add_filter( $oCon->prefix( 'is_relabelled' ), '__return_true' );
19
+ add_filter( $oCon->prefix( 'plugin_labels' ), [ $this, 'applyPluginLabels' ] );
20
+ add_filter( 'plugin_row_meta', [ $this, 'removePluginMetaLinks' ], 200, 2 );
21
+ add_action( 'admin_print_footer_scripts-plugin-editor.php', [ $this, 'hideFromPluginEditor' ] );
22
+ }
23
+
24
+ public function onWpInit() {
25
+ /** @var SecurityAdmin\Options $oOpts */
26
+ $oOpts = $this->getOptions();
27
+ if ( $oOpts->isWlHideUpdates() && $this->isNeedToHideUpdates() && !$this->getCon()->isPluginAdmin() ) {
28
+ $this->hideUpdates();
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Depending on the page, we hide the update data,
34
+ * or we adjust the number of displayed updates counts
35
+ */
36
+ protected function hideUpdates() {
37
+ if ( in_array( Services::WpPost()->getCurrentPage(), [ 'plugins.php', 'update-core.php' ] ) ) {
38
+ add_filter( 'site_transient_update_plugins', [ $this, 'hidePluginUpdatesFromUI' ] );
39
+ }
40
+ else {
41
+ add_filter( 'wp_get_update_data', [ $this, 'adjustUpdateDataCount' ] );
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Adjusts the available updates count so as not to include Shield updates if they're hidden
47
+ * @param array $aUpdateData
48
+ * @return array
49
+ */
50
+ public function adjustUpdateDataCount( $aUpdateData ) {
51
+
52
+ $sFile = $this->getCon()->getPluginBaseFile();
53
+ if ( Services::WpPlugins()->isUpdateAvailable( $sFile ) ) {
54
+ $aUpdateData[ 'counts' ][ 'total' ]--;
55
+ $aUpdateData[ 'counts' ][ 'plugins' ]--;
56
+ }
57
+
58
+ return $aUpdateData;
59
+ }
60
+
61
+ public function hideFromPluginEditor() {
62
+ $oCon = $this->getCon();
63
+ $sJs = Services::Data()->readFileContentsUsingInclude( $oCon->getPath_AssetJs( 'whitelabel.js' ) );
64
+ echo sprintf( '<script type="text/javascript">%s</script>', sprintf( $sJs, $oCon->getPluginBaseFile() ) );
65
+ }
66
+
67
+ /**
68
+ * @param array $aPluginLabels
69
+ * @return array
70
+ */
71
+ public function applyPluginLabels( $aPluginLabels ) {
72
+ /** @var \ICWP_WPSF_FeatureHandler_AdminAccessRestriction $oMod */
73
+ $oMod = $this->getMod();
74
+
75
+ $aWhiteLabels = $oMod->getWhitelabelOptions();
76
+
77
+ // these are the old white labelling keys which will be replaced upon final release of white labelling.
78
+ $sServiceName = $aWhiteLabels[ 'name_main' ];
79
+ $aPluginLabels[ 'Name' ] = $sServiceName;
80
+ $aPluginLabels[ 'Title' ] = $sServiceName;
81
+ $aPluginLabels[ 'Author' ] = $aWhiteLabels[ 'name_company' ];
82
+ $aPluginLabels[ 'AuthorName' ] = $aWhiteLabels[ 'name_company' ];
83
+ $aPluginLabels[ 'MenuTitle' ] = $aWhiteLabels[ 'name_menu' ];
84
+
85
+ $sTagLine = $aWhiteLabels[ 'description' ];
86
+ if ( !empty( $sTagLine ) ) {
87
+ $aPluginLabels[ 'Description' ] = $sTagLine;
88
+ }
89
+
90
+ $sUrl = $aWhiteLabels[ 'url_home' ];
91
+ if ( !empty( $sUrl ) ) {
92
+ $aPluginLabels[ 'PluginURI' ] = $sUrl;
93
+ $aPluginLabels[ 'AuthorURI' ] = $sUrl;
94
+ }
95
+
96
+ $sIconUrl = $aWhiteLabels[ 'url_icon' ];
97
+ if ( !empty( $sIconUrl ) ) {
98
+ $aPluginLabels[ 'icon_url_16x16' ] = $sIconUrl;
99
+ $aPluginLabels[ 'icon_url_32x32' ] = $sIconUrl;
100
+ }
101
+
102
+ $sLogoUrl = $aWhiteLabels[ 'url_dashboardlogourl' ];
103
+ if ( !empty( $sLogoUrl ) ) {
104
+ $aPluginLabels[ 'icon_url_128x128' ] = $sLogoUrl;
105
+ }
106
+
107
+ return array_merge( $aWhiteLabels, $aPluginLabels );
108
+ }
109
+
110
+ /**
111
+ * @filter
112
+ * @param array $aPluginMeta
113
+ * @param string $sPluginBaseFileName
114
+ * @return array
115
+ */
116
+ public function removePluginMetaLinks( $aPluginMeta, $sPluginBaseFileName ) {
117
+ if ( $sPluginBaseFileName == $this->getCon()->getPluginBaseFile() ) {
118
+ unset( $aPluginMeta[ 2 ] ); // View details
119
+ unset( $aPluginMeta[ 3 ] ); // Rate 5*
120
+ }
121
+ return $aPluginMeta;
122
+ }
123
+
124
+ /**
125
+ * Hides the update if the page loaded is the plugins page or the updates page.
126
+ * @param \stdClass $oPlugins
127
+ * @return \stdClass
128
+ */
129
+ public function hidePluginUpdatesFromUI( $oPlugins ) {
130
+ $sFile = $this->getCon()->getPluginBaseFile();
131
+ if ( isset( $oPlugins->response[ $sFile ] ) ) {
132
+ unset( $oPlugins->response[ $sFile ] );
133
+ }
134
+ return $oPlugins;
135
+ }
136
+
137
+ /**
138
+ * @return bool
139
+ */
140
+ private function isNeedToHideUpdates() {
141
+ return is_admin() && !Services::WpGeneral()->isCron();
142
+ }
143
+ }
src/lib/src/Modules/UserManagement/Lib/Registration/EmailValidate.php ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\UserManagement\Lib\Registration;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\UserManagement;
7
+ use FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes\Verify\Email;
8
+
9
+ class EmailValidate {
10
+
11
+ use ModConsumer;
12
+
13
+ private $aTrack;
14
+
15
+ public function run() {
16
+ /** @var UserManagement\Options $oOpts */
17
+ $oOpts = $this->getOptions();
18
+ if ( $oOpts->getValidateEmailOnRegistration() != 'disabled' ) {
19
+ add_filter( 'wp_pre_insert_user_data', [ $this, 'validateNewUserEmail' ] );
20
+ }
21
+ }
22
+
23
+ /**
24
+ * @param array $aUserData
25
+ * @return array
26
+ */
27
+ public function validateNewUserEmail( $aUserData ) {
28
+ $sEmail = $aUserData[ 'user_email' ];
29
+ /** @var UserManagement\Options $oOpts */
30
+
31
+ if ( !is_array( $this->aTrack ) ) {
32
+ $this->aTrack = [];
33
+ }
34
+
35
+ // This hook seems to be called twice on any given registration.
36
+ if ( !in_array( $sEmail, $this->aTrack ) ) {
37
+ $this->aTrack[] = $sEmail;
38
+
39
+ $oOpts = $this->getOptions();
40
+ $sInvalidBecause = null;
41
+ if ( !is_email( $sEmail ) ) {
42
+ $sInvalidBecause = 'syntax';
43
+ }
44
+ else {
45
+ $sApiToken = $this->getCon()
46
+ ->getModule_License()
47
+ ->getWpHashesTokenManager()
48
+ ->getToken();
49
+ if ( !empty( $sApiToken ) ) {
50
+ $aChecks = $oOpts->getEmailValidationChecks();
51
+ foreach ( ( new Email( $sApiToken ) )->getEmailVerification( $sEmail ) as $sValidation => $bIsValid ) {
52
+ if ( !$bIsValid && in_array( $sValidation, $aChecks ) ) {
53
+ $sInvalidBecause = $sValidation;
54
+ break;
55
+ }
56
+ }
57
+ }
58
+ }
59
+
60
+ if ( !empty( $sInvalidBecause ) ) {
61
+ $sOpt = $oOpts->getValidateEmailOnRegistration();
62
+ $this->getCon()->fireEvent(
63
+ 'reg_email_invalid',
64
+ [
65
+ 'audit' => [
66
+ 'email' => sanitize_email( $sEmail ),
67
+ 'reason' => sanitize_key( $sInvalidBecause ),
68
+ ],
69
+ 'offense_count' => $sOpt == 'log' ? 0 : 1,
70
+ 'block' => $sOpt == 'block',
71
+ ]
72
+ );
73
+
74
+ if ( $sOpt == 'block' ) {
75
+ wp_die( 'Attempted user registration with invalid email addressed has been blocked.' );
76
+ }
77
+ }
78
+ }
79
+
80
+ return $aUserData;
81
+ }
82
+ }
src/lib/src/Modules/UserManagement/Options.php CHANGED
@@ -146,4 +146,20 @@ class Options extends Base\ShieldOptions {
146
  public function isSuspendManualEnabled() {
147
  return $this->isOpt( 'manual_suspend', 'Y' );
148
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  }
146
  public function isSuspendManualEnabled() {
147
  return $this->isOpt( 'manual_suspend', 'Y' );
148
  }
149
+
150
+ /**
151
+ * @return string
152
+ */
153
+ public function getValidateEmailOnRegistration() {
154
+ return $this->isPremium() ?
155
+ $this->getOpt( 'reg_email_validate', 'disabled' )
156
+ : 'disabled';
157
+ }
158
+
159
+ /**
160
+ * @return string[]
161
+ */
162
+ public function getEmailValidationChecks() {
163
+ return $this->getOpt( 'email_checks', [] );
164
+ }
165
  }
src/lib/src/Modules/UserManagement/Strings.php CHANGED
@@ -159,6 +159,18 @@ class Strings extends Base\Strings {
159
  .'<br />'.__( "Zero (0) will allow unlimited simultaneous sessions.", 'wp-simple-firewall' );
160
  break;
161
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  case 'enable_password_policies' :
163
  $sName = __( 'Enable Password Policies', 'wp-simple-firewall' );
164
  $sSummary = __( 'Enable The Password Policies Detailed Below', 'wp-simple-firewall' );
@@ -249,6 +261,10 @@ class Strings extends Base\Strings {
249
  */
250
  protected function getAuditMessages() {
251
  return [
 
 
 
 
252
  'pass_expired' => [
253
  __( 'Forcing user to update expired password.', 'wp-simple-firewall' ),
254
  ],
159
  .'<br />'.__( "Zero (0) will allow unlimited simultaneous sessions.", 'wp-simple-firewall' );
160
  break;
161
 
162
+ case 'reg_email_validate' :
163
+ $sName = __( 'Validate Email Addresses', 'wp-simple-firewall' );
164
+ $sSummary = __( 'Validate Email Addresses When User Attempts To Register', 'wp-simple-firewall' );
165
+ $sDesc = __( 'Validate Email Addresses When User Attempts To Register.', 'wp-simple-firewall' );
166
+ break;
167
+
168
+ case 'email_checks' :
169
+ $sName = __( 'Email Validation Checks', 'wp-simple-firewall' );
170
+ $sSummary = __( 'The Email Address Properties That Will Be Tested', 'wp-simple-firewall' );
171
+ $sDesc = __( 'Select the properties that should be tested during email address validation.', 'wp-simple-firewall' );
172
+ break;
173
+
174
  case 'enable_password_policies' :
175
  $sName = __( 'Enable Password Policies', 'wp-simple-firewall' );
176
  $sSummary = __( 'Enable The Password Policies Detailed Below', 'wp-simple-firewall' );
261
  */
262
  protected function getAuditMessages() {
263
  return [
264
+ 'reg_email_invalid' => [
265
+ __( 'Detected user registration with invalid email address (%s).', 'wp-simple-firewall' ),
266
+ __( 'Email verification test that failed: %s' )
267
+ ],
268
  'pass_expired' => [
269
  __( 'Forcing user to update expired password.', 'wp-simple-firewall' ),
270
  ],
src/lib/src/Modules/UserManagement/Suspend/Idle.php CHANGED
@@ -16,10 +16,8 @@ class Idle extends Base {
16
  protected function processUser( $oUser, $oMeta ) {
17
  /** @var UserManagement\Options $oOpts */
18
  $oOpts = $this->getOptions();
19
- /** @var \ICWP_WPSF_FeatureHandler_UserManagement $oMod */
20
- $oMod = $this->getMod();
21
 
22
- $aRoles = array_intersect( $oMod->getSuspendAutoIdleUserRoles(), array_map( 'strtolower', $oUser->roles ) );
23
 
24
  if ( count( $aRoles ) > 0 && $this->isLastVerifiedAtExpired( $oMeta ) ) {
25
  $oUser = new \WP_Error(
@@ -42,8 +40,8 @@ class Idle extends Base {
42
  * @return bool
43
  */
44
  protected function isLastVerifiedAtExpired( $oMeta ) {
45
- /** @var \ICWP_WPSF_FeatureHandler_UserManagement $oMod */
46
- $oMod = $this->getMod();
47
- return ( Services::Request()->ts() - $oMeta->getLastVerifiedAt() > $oMod->getSuspendAutoIdleTime() );
48
  }
49
  }
16
  protected function processUser( $oUser, $oMeta ) {
17
  /** @var UserManagement\Options $oOpts */
18
  $oOpts = $this->getOptions();
 
 
19
 
20
+ $aRoles = array_intersect( $oOpts->getSuspendAutoIdleUserRoles(), array_map( 'strtolower', $oUser->roles ) );
21
 
22
  if ( count( $aRoles ) > 0 && $this->isLastVerifiedAtExpired( $oMeta ) ) {
23
  $oUser = new \WP_Error(
40
  * @return bool
41
  */
42
  protected function isLastVerifiedAtExpired( $oMeta ) {
43
+ /** @var UserManagement\Options $oOpts */
44
+ $oOpts = $this->getOptions();
45
+ return ( Services::Request()->ts() - $oMeta->getLastVerifiedAt() > $oOpts->getSuspendAutoIdleTime() );
46
  }
47
  }
src/lib/src/Modules/UserManagement/Suspend/PasswordExpiry.php CHANGED
@@ -3,6 +3,7 @@
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\UserManagement\Suspend;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Users\ShieldUserMeta;
 
6
  use FernleafSystems\Wordpress\Services\Services;
7
 
8
  /**
@@ -44,12 +45,12 @@ class PasswordExpiry extends Base {
44
  * @return bool
45
  */
46
  private function isPassExpired( $oMeta ) {
47
- /** @var \ICWP_WPSF_FeatureHandler_UserManagement $oMod */
48
- $oMod = $this->getMod();
49
  if ( empty( $oMeta->pass_started_at ) ) {
50
  $oMeta->pass_started_at = $oMeta->first_seen_at;
51
  }
52
- return ( Services::Request()->ts() - $oMeta->pass_started_at > $oMod->getPassExpireTimeout() );
53
  }
54
 
55
  /**
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\UserManagement\Suspend;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Users\ShieldUserMeta;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\UserManagement;
7
  use FernleafSystems\Wordpress\Services\Services;
8
 
9
  /**
45
  * @return bool
46
  */
47
  private function isPassExpired( $oMeta ) {
48
+ /** @var UserManagement\Options $oOpts */
49
+ $oOpts = $this->getOptions();
50
  if ( empty( $oMeta->pass_started_at ) ) {
51
  $oMeta->pass_started_at = $oMeta->first_seen_at;
52
  }
53
+ return ( Services::Request()->ts() - $oMeta->pass_started_at > $oOpts->getPassExpireTimeout() );
54
  }
55
 
56
  /**
src/lib/src/Scans/Mal/Utilities/FalsePositiveQuery.php CHANGED
@@ -46,8 +46,11 @@ class FalsePositiveQuery {
46
  /** @var Modules\HackGuard\Options $oOpts */
47
  $oOpts = $this->getOptions();
48
  if ( $oOpts->isMalUseNetworkIntelligence() ) {
49
-
50
- $aData = ( new Malware\Confidence\Retrieve() )->retrieveForFile( $sFullPath );
 
 
 
51
  if ( isset( $aData[ 'score' ] ) ) {
52
  $nFpConfidence = (int)$aData[ 'score' ];
53
  }
@@ -66,9 +69,12 @@ class FalsePositiveQuery {
66
  /** @var Modules\HackGuard\Options $oOpts */
67
  $oOpts = $this->getOptions();
68
  if ( $oOpts->isMalUseNetworkIntelligence() ) {
69
-
 
 
 
70
  try {
71
- $aData = ( new Malware\Confidence\Retrieve() )->retrieveForFileLine( $sFile, $sLine );
72
  if ( isset( $aData[ 'score' ] ) ) {
73
  $nFpConfidence = (int)$aData[ 'score' ];
74
  }
46
  /** @var Modules\HackGuard\Options $oOpts */
47
  $oOpts = $this->getOptions();
48
  if ( $oOpts->isMalUseNetworkIntelligence() ) {
49
+ $sApiToken = $this->getCon()
50
+ ->getModule_License()
51
+ ->getWpHashesTokenManager()
52
+ ->getToken();
53
+ $aData = ( new Malware\Confidence\Retrieve( $sApiToken ) )->retrieveForFile( $sFullPath );
54
  if ( isset( $aData[ 'score' ] ) ) {
55
  $nFpConfidence = (int)$aData[ 'score' ];
56
  }
69
  /** @var Modules\HackGuard\Options $oOpts */
70
  $oOpts = $this->getOptions();
71
  if ( $oOpts->isMalUseNetworkIntelligence() ) {
72
+ $sApiToken = $this->getCon()
73
+ ->getModule_License()
74
+ ->getWpHashesTokenManager()
75
+ ->getToken();
76
  try {
77
+ $aData = ( new Malware\Confidence\Retrieve( $sApiToken ) )->retrieveForFileLine( $sFile, $sLine );
78
  if ( isset( $aData[ 'score' ] ) ) {
79
  $nFpConfidence = (int)$aData[ 'score' ];
80
  }
src/lib/src/Scans/Mal/Utilities/FalsePositiveReporter.php CHANGED
@@ -63,9 +63,15 @@ class FalsePositiveReporter {
63
  sha1( Services::DataManipulation()->convertLineEndingsDosToLinux( $sFullPath ) ),
64
  $bIsFalsePositive
65
  ] ) );
 
66
  if ( !$oOpts->isMalFalsePositiveReported( $sReportHash ) ) {
67
- $bReported = ( new Malware\Whitelist\ReportFalsePositive() )
68
- ->report( $sFullPath, static::HASH_ALGO, $bIsFalsePositive );
 
 
 
 
 
69
  }
70
  $this->updateReportedCache( $sReportHash );
71
  }
@@ -91,8 +97,12 @@ class FalsePositiveReporter {
91
  $sReportHash = md5( $sFile.$sLine.( $bIsFalsePositive ? 'true' : 'false' ) );
92
  if ( !$oOpts->isMalFalsePositiveReported( $sReportHash ) ) {
93
  try {
94
- if ( !$bIsFalsePositive || count( file( $sFile ) ) > 1 ) {
95
- $bReported = ( new Malware\Signatures\ReportFalsePositive() )
 
 
 
 
96
  ->report( $sFile, $sLine, $bIsFalsePositive );
97
  }
98
  }
63
  sha1( Services::DataManipulation()->convertLineEndingsDosToLinux( $sFullPath ) ),
64
  $bIsFalsePositive
65
  ] ) );
66
+
67
  if ( !$oOpts->isMalFalsePositiveReported( $sReportHash ) ) {
68
+ $sApiToken = $this->getCon()
69
+ ->getModule_License()
70
+ ->getWpHashesTokenManager()
71
+ ->getToken();
72
+ $bReported = !empty( $sApiToken ) &&
73
+ ( new Malware\Whitelist\ReportFalsePositive( $sApiToken ) )
74
+ ->report( $sFullPath, static::HASH_ALGO, $bIsFalsePositive );
75
  }
76
  $this->updateReportedCache( $sReportHash );
77
  }
97
  $sReportHash = md5( $sFile.$sLine.( $bIsFalsePositive ? 'true' : 'false' ) );
98
  if ( !$oOpts->isMalFalsePositiveReported( $sReportHash ) ) {
99
  try {
100
+ $sApiToken = $this->getCon()
101
+ ->getModule_License()
102
+ ->getWpHashesTokenManager()
103
+ ->getToken();
104
+ if ( !empty( $sApiToken ) && !$bIsFalsePositive || count( file( $sFile ) ) > 1 ) {
105
+ $bReported = ( new Malware\Signatures\ReportFalsePositive( $sApiToken ) )
106
  ->report( $sFile, $sLine, $bIsFalsePositive );
107
  }
108
  }
src/lib/src/Scans/Mal/Utilities/Patterns.php CHANGED
@@ -32,9 +32,12 @@ class Patterns {
32
  }
33
 
34
  if ( empty( $oCacheDef->data ) ) {
35
-
 
 
 
36
  // First attempt to download from WP Hashes API.
37
- $aPatts = ( new Malware\Patterns\Retrieve() )->getPatterns();
38
 
39
  // Fallback to original method
40
  if ( !is_array( $aPatts ) || empty( $aPatts[ 'simple' ] ) || empty( $aPatts[ 'regex' ] ) ) {
32
  }
33
 
34
  if ( empty( $oCacheDef->data ) ) {
35
+ $sApiToken = $this->getCon()
36
+ ->getModule_License()
37
+ ->getWpHashesTokenManager()
38
+ ->getToken();
39
  // First attempt to download from WP Hashes API.
40
+ $aPatts = ( new Malware\Patterns\Retrieve( $sApiToken ) )->getPatterns();
41
 
42
  // Fallback to original method
43
  if ( !is_array( $aPatts ) || empty( $aPatts[ 'simple' ] ) || empty( $aPatts[ 'regex' ] ) ) {
src/lib/src/Scans/Ptg/ScannerBase.php DELETED
@@ -1,53 +0,0 @@
1
- <?php
2
-
3
- namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Ptg;
4
-
5
- use FernleafSystems\Wordpress\Plugin\Shield\Scans;
6
-
7
- /**
8
- * Class ScannerBase
9
- * @package FernleafSystems\Wordpress\Plugin\Shield\Scans\Ptg
10
- * @deprecated 8.5
11
- */
12
- abstract class ScannerBase {
13
-
14
- const CONTEXT = '';
15
-
16
- /**
17
- * @param array[] $aPreExistingHashes - key is the slug/base-file name and value is the file hashes
18
- * @return ResultsSet
19
- */
20
- public function run( $aPreExistingHashes ) {
21
- return new ResultsSet();
22
- }
23
-
24
- /**
25
- * @param string $sAssetSlug
26
- * @return string[]
27
- */
28
- public function hashAssetFiles( $sAssetSlug ) {
29
- return [];
30
- }
31
-
32
- /**
33
- * @param string $sSlug
34
- * @return string
35
- */
36
- abstract protected function getDirFromItemSlug( $sSlug );
37
-
38
- /**
39
- * @param int $nDepth
40
- * @return $this
41
- */
42
- public function setDepth( $nDepth ) {
43
- return $this;
44
- }
45
-
46
- /**
47
- * @param string[] $aExts
48
- * @return $this
49
- */
50
- public function setFileExts( $aExts ) {
51
- return $this;
52
- }
53
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/src/Scans/Ptg/ScannerPlugins.php DELETED
@@ -1,23 +0,0 @@
1
- <?php
2
-
3
- namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Ptg;
4
-
5
- use FernleafSystems\Wordpress\Services\Services;
6
-
7
- /**
8
- * Class ScannerPlugins
9
- * @package FernleafSystems\Wordpress\Plugin\Shield\Scans\Ptg
10
- * @deprecated 8.5
11
- */
12
- class ScannerPlugins extends ScannerBase {
13
-
14
- const CONTEXT = 'plugins';
15
-
16
- /**
17
- * @param string $sSlug
18
- * @return string
19
- */
20
- protected function getDirFromItemSlug( $sSlug ) {
21
- return Services::WpPlugins()->getInstallationDir( $sSlug );
22
- }
23
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/src/Scans/Wpv/Scan.php CHANGED
@@ -38,6 +38,11 @@ class Scan extends Shield\Scans\Base\BaseScan {
38
  protected function scanItem( $sContext, $sFile ) {
39
  $oResultsSet = new ResultsSet();
40
 
 
 
 
 
 
41
  if ( $sContext == 'plugins' ) {
42
  $oWpPlugins = Services::WpPlugins();
43
  $sSlug = $oWpPlugins->getSlug( $sFile );
@@ -45,12 +50,12 @@ class Scan extends Shield\Scans\Base\BaseScan {
45
  $sSlug = dirname( $sFile );
46
  }
47
  $sVersion = $oWpPlugins->getPluginAsVo( $sFile )->Version;
48
- $oLookup = new Vulnerabilities\Plugin();
49
  }
50
  else {
51
  $sSlug = $sFile;
52
  $sVersion = Services::WpThemes()->getTheme( $sSlug )->get( 'Version' );
53
- $oLookup = new Vulnerabilities\Theme();
54
  }
55
 
56
  $aVulns = $oLookup->getVulnerabilities( $sSlug, $sVersion );
38
  protected function scanItem( $sContext, $sFile ) {
39
  $oResultsSet = new ResultsSet();
40
 
41
+ $sApiToken = $this->getCon()
42
+ ->getModule_License()
43
+ ->getWpHashesTokenManager()
44
+ ->getToken();
45
+
46
  if ( $sContext == 'plugins' ) {
47
  $oWpPlugins = Services::WpPlugins();
48
  $sSlug = $oWpPlugins->getSlug( $sFile );
50
  $sSlug = dirname( $sFile );
51
  }
52
  $sVersion = $oWpPlugins->getPluginAsVo( $sFile )->Version;
53
+ $oLookup = new Vulnerabilities\Plugin( $sApiToken );
54
  }
55
  else {
56
  $sSlug = $sFile;
57
  $sVersion = Services::WpThemes()->getTheme( $sSlug )->get( 'Version' );
58
+ $oLookup = new Vulnerabilities\Theme( $sApiToken );
59
  }
60
 
61
  $aVulns = $oLookup->getVulnerabilities( $sSlug, $sVersion );
src/lib/src/Tables/Build/Ip.php CHANGED
@@ -26,6 +26,8 @@ class Ip extends BaseBuild {
26
  $oSelector->filterByIp( $aParams[ 'fIp' ] );
27
  }
28
 
 
 
29
  return $this;
30
  }
31
 
26
  $oSelector->filterByIp( $aParams[ 'fIp' ] );
27
  }
28
 
29
+ $oSelector->setOrderBy( 'last_access_at', 'DESC', true );
30
+
31
  return $this;
32
  }
33
 
src/lib/src/Tables/Render/IpBlack.php CHANGED
@@ -9,10 +9,17 @@ class IpBlack extends IpBase {
9
  * @return string
10
  */
11
  public function column_details( $aItem ) {
 
12
  return implode( '<br/>', [
13
  sprintf( '%s: %s', __( 'Blocked', 'wp-simple-firewall' ), $aItem[ 'blocked' ] ),
14
- sprintf( '%s: %s', __( 'Offenses', 'wp-simple-firewall' ), $aItem[ 'transgressions' ] ),
15
- sprintf( '%s: %s', __( 'Last Offense', 'wp-simple-firewall' ), $aItem[ 'last_trans_at' ] ),
 
 
 
 
 
 
16
  ] );
17
  }
18
 
9
  * @return string
10
  */
11
  public function column_details( $aItem ) {
12
+ $bAutoBlock = $aItem[ 'list' ] === \ICWP_WPSF_FeatureHandler_Ips::LIST_AUTO_BLACK;
13
  return implode( '<br/>', [
14
  sprintf( '%s: %s', __( 'Blocked', 'wp-simple-firewall' ), $aItem[ 'blocked' ] ),
15
+ sprintf( '%s / %s',
16
+ $aItem[ 'is_range' ] ? __( 'IP Range', 'wp-simple-firewall' ) : __( 'Single IP', 'wp-simple-firewall' ),
17
+ $bAutoBlock ? __( 'Automatic', 'wp-simple-firewall' ) : __( 'Manual', 'wp-simple-firewall' )
18
+ ),
19
+ sprintf( '%s - %s',
20
+ sprintf( _n( '%s Offense', '%s Offenses', $aItem[ 'transgressions' ], 'wp-simple-firewall' ), $aItem[ 'transgressions' ] ),
21
+ sprintf( '%s: %s', __( 'Last Access', 'wp-simple-firewall' ), $aItem[ 'last_trans_at' ] )
22
+ ),
23
  ] );
24
  }
25
 
src/lib/src/Users/ShieldUserMeta.php CHANGED
@@ -29,6 +29,23 @@ use FernleafSystems\Wordpress\Services\Services;
29
  */
30
  class ShieldUserMeta extends \FernleafSystems\Wordpress\Services\Utilities\PluginUserMeta {
31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  /**
33
  * @return int
34
  */
29
  */
30
  class ShieldUserMeta extends \FernleafSystems\Wordpress\Services\Utilities\PluginUserMeta {
31
 
32
+ /**
33
+ * @param string $sAgent
34
+ * @param int|null $nMaxExpires - allows us to clean out old entries
35
+ */
36
+ public function addMfaSkipAgent( $sAgent, $nMaxExpires = null ) {
37
+ $aHashes = is_array( $this->hash_loginmfa ) ? $this->hash_loginmfa : [];
38
+ $aHashes[ md5( $sAgent ) ] = Services::Request()->ts();
39
+ if ( !empty( $nMaxExpires ) ) {
40
+ $aHashes = array_filter( $aHashes,
41
+ function ( $nTS ) use ( $nMaxExpires ) {
42
+ return Services::Request()->ts() - $nTS < $nMaxExpires;
43
+ }
44
+ );
45
+ }
46
+ $this->hash_loginmfa = $aHashes;
47
+ }
48
+
49
  /**
50
  * @return int
51
  */
src/lib/src/Utilities/AdminNotices/Controller.php CHANGED
@@ -84,7 +84,7 @@ class Controller {
84
  /**
85
  * @return NoticeVO|null
86
  */
87
- private function getFlashNotice() {
88
  $oNotice = null;
89
  $aM = $this->retrieveFlashMessage();
90
  if ( is_array( $aM ) ) {
84
  /**
85
  * @return NoticeVO|null
86
  */
87
+ public function getFlashNotice() {
88
  $oNotice = null;
89
  $aM = $this->retrieveFlashMessage();
90
  if ( is_array( $aM ) ) {
src/lib/vendor/composer/autoload_classmap.php CHANGED
@@ -51,6 +51,9 @@ return array(
51
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Snapshot\\Collate' => $baseDir . '/src/ChangeTrack/Snapshot/Collate.php',
52
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Snapshot\\SnapshotsConsumer' => $baseDir . '/src/ChangeTrack/Snapshot/SnapshotsConsumer.php',
53
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Controller' => $baseDir . '/src/Controller/Controller.php',
 
 
 
54
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Crons\\StandardCron' => $baseDir . '/src/Crons/StandardCron.php',
55
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\AdminNotes\\Delete' => $baseDir . '/src/Databases/AdminNotes/Delete.php',
56
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\AdminNotes\\EntryVO' => $baseDir . '/src/Databases/AdminNotes/EntryVO.php',
@@ -195,7 +198,6 @@ return array(
195
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\BaseAction' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/BaseAction.php',
196
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\BaseBulk' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/BaseBulk.php',
197
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\Build' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/Build.php',
198
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\BuildAll' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/BuildAll.php',
199
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\CleanAll' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/CleanAll.php',
200
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\CreateNew' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/CreateNew.php',
201
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\Delete' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/Delete.php',
@@ -253,6 +255,9 @@ return array(
253
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Components\\QueryIpBlock' => $baseDir . '/src/Modules/IPs/Components/QueryIpBlock.php',
254
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Components\\QueryRemainingOffenses' => $baseDir . '/src/Modules/IPs/Components/QueryRemainingOffenses.php',
255
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Components\\UnblockIpByFlag' => $baseDir . '/src/Modules/IPs/Components/UnblockIpByFlag.php',
 
 
 
256
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\OffenseTracker' => $baseDir . '/src/Modules/IPs/Lib/OffenseTracker.php',
257
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Ops\\AddIp' => $baseDir . '/src/Modules/IPs/Lib/Ops/AddIp.php',
258
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Ops\\DeleteIp' => $baseDir . '/src/Modules/IPs/Lib/Ops/DeleteIp.php',
@@ -262,7 +267,13 @@ return array(
262
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Strings' => $baseDir . '/src/Modules/IPs/Strings.php',
263
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Options' => $baseDir . '/src/Modules/Insights/Options.php',
264
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Strings' => $baseDir . '/src/Modules/Insights/Strings.php',
 
265
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\AjaxHandler' => $baseDir . '/src/Modules/License/AjaxHandler.php',
 
 
 
 
 
266
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Options' => $baseDir . '/src/Modules/License/Options.php',
267
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Strings' => $baseDir . '/src/Modules/License/Strings.php',
268
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Lockdown\\Options' => $baseDir . '/src/Modules/Lockdown/Options.php',
@@ -271,6 +282,16 @@ return array(
271
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\AjaxHandler' => $baseDir . '/src/Modules/LoginGuard/AjaxHandler.php',
272
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\CooldownFlagFile' => $baseDir . '/src/Modules/LoginGuard/Lib/CooldownFlagFile.php',
273
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\CooldownRedirect' => $baseDir . '/src/Modules/LoginGuard/Lib/CooldownRedirect.php',
 
 
 
 
 
 
 
 
 
 
274
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Options' => $baseDir . '/src/Modules/LoginGuard/Options.php',
275
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Strings' => $baseDir . '/src/Modules/LoginGuard/Strings.php',
276
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\ModConsumer' => $baseDir . '/src/Modules/ModConsumer.php',
@@ -288,6 +309,7 @@ return array(
288
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\AdminNotices' => $baseDir . '/src/Modules/SecurityAdmin/AdminNotices.php',
289
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\AjaxHandler' => $baseDir . '/src/Modules/SecurityAdmin/AjaxHandler.php',
290
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\Actions\\RemoveSecAdmin' => $baseDir . '/src/Modules/SecurityAdmin/Lib/Actions/RemoveSecAdmin.php',
 
291
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Options' => $baseDir . '/src/Modules/SecurityAdmin/Options.php',
292
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Strings' => $baseDir . '/src/Modules/SecurityAdmin/Strings.php',
293
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Sessions\\Lib\\Ops\\Terminate' => $baseDir . '/src/Modules/Sessions/Lib/Ops/Terminate.php',
@@ -302,6 +324,7 @@ return array(
302
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Strings' => $baseDir . '/src/Modules/Traffic/Strings.php',
303
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\AjaxHandler' => $baseDir . '/src/Modules/UserManagement/AjaxHandler.php',
304
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Lib\\CleanExpired' => $baseDir . '/src/Modules/UserManagement/Lib/CleanExpired.php',
 
305
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Lib\\RetrieveActive' => $baseDir . '/src/Modules/UserManagement/Lib/RetrieveActive.php',
306
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Options' => $baseDir . '/src/Modules/UserManagement/Options.php',
307
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Strings' => $baseDir . '/src/Modules/UserManagement/Strings.php',
@@ -365,8 +388,6 @@ return array(
365
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\Scan' => $baseDir . '/src/Scans/Ptg/Scan.php',
366
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\ScanActionVO' => $baseDir . '/src/Scans/Ptg/ScanActionVO.php',
367
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\ScanFromFileMap' => $baseDir . '/src/Scans/Ptg/ScanFromFileMap.php',
368
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\ScannerBase' => $baseDir . '/src/Scans/Ptg/ScannerBase.php',
369
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\ScannerPlugins' => $baseDir . '/src/Scans/Ptg/ScannerPlugins.php',
370
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\Table\\EntryFormatter' => $baseDir . '/src/Scans/Ptg/Table/EntryFormatter.php',
371
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\Utilities\\ItemActionHandler' => $baseDir . '/src/Scans/Ptg/Utilities/ItemActionHandler.php',
372
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\Utilities\\Repair' => $baseDir . '/src/Scans/Ptg/Utilities/Repair.php',
@@ -461,6 +482,7 @@ return array(
461
  'FernleafSystems\\Wordpress\\Services\\Core\\Respond' => $vendorDir . '/fernleafsystems/wordpress-services/src/Core/Respond.php',
462
  'FernleafSystems\\Wordpress\\Services\\Core\\Response' => $vendorDir . '/fernleafsystems/wordpress-services/src/Core/Response.php',
463
  'FernleafSystems\\Wordpress\\Services\\Core\\Rest' => $vendorDir . '/fernleafsystems/wordpress-services/src/Core/Rest.php',
 
464
  'FernleafSystems\\Wordpress\\Services\\Core\\Themes' => $vendorDir . '/fernleafsystems/wordpress-services/src/Core/Themes.php',
465
  'FernleafSystems\\Wordpress\\Services\\Core\\Track' => $vendorDir . '/fernleafsystems/wordpress-services/src/Core/Track.php',
466
  'FernleafSystems\\Wordpress\\Services\\Core\\Upgrades\\BulkPluginUpgraderSkin' => $vendorDir . '/fernleafsystems/wordpress-services/src/Core/Upgrades/BulkPluginUpgraderSkin.php',
@@ -546,9 +568,14 @@ return array(
546
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Iterators\\WpUserIterator' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Iterators/WpUserIterator.php',
547
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\EddActions' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/EddActions.php',
548
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\EddLicenseVO' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/EddLicenseVO.php',
 
 
 
549
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Lookup' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Lookup.php',
550
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\VisitorIpDetection' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Net/VisitorIpDetection.php',
551
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Obfuscate' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Obfuscate.php',
 
 
552
  'FernleafSystems\\Wordpress\\Services\\Utilities\\PluginUserMeta' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/PluginUserMeta.php',
553
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Render' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Render.php',
554
  'FernleafSystems\\Wordpress\\Services\\Utilities\\ServiceProviders' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/ServiceProviders.php',
@@ -604,7 +631,6 @@ return array(
604
  'ICWP_WPSF_FeatureHandler_Sessions' => $baseDir . '/../features/sessions.php',
605
  'ICWP_WPSF_FeatureHandler_Traffic' => $baseDir . '/../features/traffic.php',
606
  'ICWP_WPSF_FeatureHandler_UserManagement' => $baseDir . '/../features/user_management.php',
607
- 'ICWP_WPSF_Foundation' => $baseDir . '/../common/icwp-foundation.php',
608
  'ICWP_WPSF_Processor_AdminAccessRestriction' => $baseDir . '/../processors/admin_access_restriction.php',
609
  'ICWP_WPSF_Processor_AdminAccess_Whitelabel' => $baseDir . '/../processors/adminaccess_whitelabel.php',
610
  'ICWP_WPSF_Processor_AuditTrail' => $baseDir . '/../processors/audit_trail.php',
@@ -623,7 +649,6 @@ return array(
623
  'ICWP_WPSF_Processor_HackProtect_Mal' => $baseDir . '/../processors/hackprotect_scan_mal.php',
624
  'ICWP_WPSF_Processor_HackProtect_Ptg' => $baseDir . '/../processors/hackprotect_scan_ptg.php',
625
  'ICWP_WPSF_Processor_HackProtect_Realtime' => $baseDir . '/../processors/hackprotect_realtime.php',
626
- 'ICWP_WPSF_Processor_HackProtect_ScanAssetsBase' => $baseDir . '/../processors/hackprotect_scan_assets_base.php',
627
  'ICWP_WPSF_Processor_HackProtect_Scanner' => $baseDir . '/../processors/hackprotect_scanner.php',
628
  'ICWP_WPSF_Processor_HackProtect_Ufc' => $baseDir . '/../processors/hackprotect_scan_ufc.php',
629
  'ICWP_WPSF_Processor_HackProtect_Wcf' => $baseDir . '/../processors/hackprotect_scan_wcf.php',
@@ -659,12 +684,10 @@ return array(
659
  'ICWP_WPSF_Processor_UserManagement_Passwords' => $baseDir . '/../processors/usermanagement_passwords.php',
660
  'ICWP_WPSF_Processor_UserManagement_Sessions' => $baseDir . '/../processors/usermanagement_sessions.php',
661
  'ICWP_WPSF_Processor_UserManagement_Suspend' => $baseDir . '/../processors/usermanagement_suspend.php',
662
- 'ICWP_WPSF_ServiceProviders' => $baseDir . '/../common/icwp-serviceproviders.php',
663
  'ICWP_WPSF_Wizard_Base' => $baseDir . '/../wizards/base.php',
664
  'ICWP_WPSF_Wizard_BaseWpsf' => $baseDir . '/../wizards/base_wpsf.php',
665
  'ICWP_WPSF_Wizard_LoginProtect' => $baseDir . '/../wizards/login_protect.php',
666
  'ICWP_WPSF_Wizard_Plugin' => $baseDir . '/../wizards/plugin.php',
667
- 'ICWP_WPSF_WpCron' => $baseDir . '/../common/icwp-wpcron.php',
668
  'JsonSerializable' => $vendorDir . '/nesbot/carbon/src/JsonSerializable.php',
669
  'LZCompressor\\LZContext' => $vendorDir . '/nullpunkt/lz-string-php/src/LZCompressor/LZContext.php',
670
  'LZCompressor\\LZData' => $vendorDir . '/nullpunkt/lz-string-php/src/LZCompressor/LZData.php',
51
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Snapshot\\Collate' => $baseDir . '/src/ChangeTrack/Snapshot/Collate.php',
52
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Snapshot\\SnapshotsConsumer' => $baseDir . '/src/ChangeTrack/Snapshot/SnapshotsConsumer.php',
53
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Controller' => $baseDir . '/src/Controller/Controller.php',
54
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Crons\\BaseCron' => $baseDir . '/src/Crons/BaseCron.php',
55
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Crons\\DailyCron' => $baseDir . '/src/Crons/DailyCron.php',
56
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Crons\\HourlyCron' => $baseDir . '/src/Crons/HourlyCron.php',
57
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Crons\\StandardCron' => $baseDir . '/src/Crons/StandardCron.php',
58
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\AdminNotes\\Delete' => $baseDir . '/src/Databases/AdminNotes/Delete.php',
59
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\AdminNotes\\EntryVO' => $baseDir . '/src/Databases/AdminNotes/EntryVO.php',
198
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\BaseAction' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/BaseAction.php',
199
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\BaseBulk' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/BaseBulk.php',
200
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\Build' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/Build.php',
 
201
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\CleanAll' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/CleanAll.php',
202
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\CreateNew' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/CreateNew.php',
203
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\Delete' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/Delete.php',
255
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Components\\QueryIpBlock' => $baseDir . '/src/Modules/IPs/Components/QueryIpBlock.php',
256
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Components\\QueryRemainingOffenses' => $baseDir . '/src/Modules/IPs/Components/QueryRemainingOffenses.php',
257
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Components\\UnblockIpByFlag' => $baseDir . '/src/Modules/IPs/Components/UnblockIpByFlag.php',
258
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\BlacklistHandler' => $baseDir . '/src/Modules/IPs/Lib/BlacklistHandler.php',
259
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\BlackmarkRequest' => $baseDir . '/src/Modules/IPs/Lib/BlackmarkRequest.php',
260
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\BlockRequest' => $baseDir . '/src/Modules/IPs/Lib/BlockRequest.php',
261
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\OffenseTracker' => $baseDir . '/src/Modules/IPs/Lib/OffenseTracker.php',
262
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Ops\\AddIp' => $baseDir . '/src/Modules/IPs/Lib/Ops/AddIp.php',
263
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Ops\\DeleteIp' => $baseDir . '/src/Modules/IPs/Lib/Ops/DeleteIp.php',
267
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Strings' => $baseDir . '/src/Modules/IPs/Strings.php',
268
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Options' => $baseDir . '/src/Modules/Insights/Options.php',
269
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Strings' => $baseDir . '/src/Modules/Insights/Strings.php',
270
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\AdminNotices' => $baseDir . '/src/Modules/License/AdminNotices.php',
271
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\AjaxHandler' => $baseDir . '/src/Modules/License/AjaxHandler.php',
272
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Lib\\LicenseEmails' => $baseDir . '/src/Modules/License/Lib/LicenseEmails.php',
273
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Lib\\LicenseHandler' => $baseDir . '/src/Modules/License/Lib/LicenseHandler.php',
274
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Lib\\LookupRequest' => $baseDir . '/src/Modules/License/Lib/LookupRequest.php',
275
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Lib\\Verify' => $baseDir . '/src/Modules/License/Lib/Verify.php',
276
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Lib\\WpHashes\\ApiTokenManager' => $baseDir . '/src/Modules/License/Lib/WpHashes/ApiTokenManager.php',
277
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Options' => $baseDir . '/src/Modules/License/Options.php',
278
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Strings' => $baseDir . '/src/Modules/License/Strings.php',
279
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Lockdown\\Options' => $baseDir . '/src/Modules/Lockdown/Options.php',
282
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\AjaxHandler' => $baseDir . '/src/Modules/LoginGuard/AjaxHandler.php',
283
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\CooldownFlagFile' => $baseDir . '/src/Modules/LoginGuard/Lib/CooldownFlagFile.php',
284
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\CooldownRedirect' => $baseDir . '/src/Modules/LoginGuard/Lib/CooldownRedirect.php',
285
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\LoginIntentPage' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/LoginIntentPage.php',
286
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\MfaController' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/MfaController.php',
287
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\MfaControllerConsumer' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/MfaControllerConsumer.php',
288
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\Backup' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Backup.php',
289
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\BaseProvider' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/BaseProvider.php',
290
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\Email' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Email.php',
291
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\GoogleAuth' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/GoogleAuth.php',
292
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\Yubikey' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Yubikey.php',
293
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\UserProfile' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/UserProfile.php',
294
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\ValidateLoginIntentRequest' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/ValidateLoginIntentRequest.php',
295
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Options' => $baseDir . '/src/Modules/LoginGuard/Options.php',
296
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Strings' => $baseDir . '/src/Modules/LoginGuard/Strings.php',
297
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\ModConsumer' => $baseDir . '/src/Modules/ModConsumer.php',
309
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\AdminNotices' => $baseDir . '/src/Modules/SecurityAdmin/AdminNotices.php',
310
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\AjaxHandler' => $baseDir . '/src/Modules/SecurityAdmin/AjaxHandler.php',
311
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\Actions\\RemoveSecAdmin' => $baseDir . '/src/Modules/SecurityAdmin/Lib/Actions/RemoveSecAdmin.php',
312
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\WhiteLabel\\ApplyLabels' => $baseDir . '/src/Modules/SecurityAdmin/Lib/WhiteLabel/ApplyLabels.php',
313
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Options' => $baseDir . '/src/Modules/SecurityAdmin/Options.php',
314
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Strings' => $baseDir . '/src/Modules/SecurityAdmin/Strings.php',
315
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Sessions\\Lib\\Ops\\Terminate' => $baseDir . '/src/Modules/Sessions/Lib/Ops/Terminate.php',
324
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Strings' => $baseDir . '/src/Modules/Traffic/Strings.php',
325
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\AjaxHandler' => $baseDir . '/src/Modules/UserManagement/AjaxHandler.php',
326
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Lib\\CleanExpired' => $baseDir . '/src/Modules/UserManagement/Lib/CleanExpired.php',
327
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Lib\\Registration\\EmailValidate' => $baseDir . '/src/Modules/UserManagement/Lib/Registration/EmailValidate.php',
328
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Lib\\RetrieveActive' => $baseDir . '/src/Modules/UserManagement/Lib/RetrieveActive.php',
329
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Options' => $baseDir . '/src/Modules/UserManagement/Options.php',
330
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Strings' => $baseDir . '/src/Modules/UserManagement/Strings.php',
388
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\Scan' => $baseDir . '/src/Scans/Ptg/Scan.php',
389
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\ScanActionVO' => $baseDir . '/src/Scans/Ptg/ScanActionVO.php',
390
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\ScanFromFileMap' => $baseDir . '/src/Scans/Ptg/ScanFromFileMap.php',
 
 
391
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\Table\\EntryFormatter' => $baseDir . '/src/Scans/Ptg/Table/EntryFormatter.php',
392
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\Utilities\\ItemActionHandler' => $baseDir . '/src/Scans/Ptg/Utilities/ItemActionHandler.php',
393
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\Utilities\\Repair' => $baseDir . '/src/Scans/Ptg/Utilities/Repair.php',
482
  'FernleafSystems\\Wordpress\\Services\\Core\\Respond' => $vendorDir . '/fernleafsystems/wordpress-services/src/Core/Respond.php',
483
  'FernleafSystems\\Wordpress\\Services\\Core\\Response' => $vendorDir . '/fernleafsystems/wordpress-services/src/Core/Response.php',
484
  'FernleafSystems\\Wordpress\\Services\\Core\\Rest' => $vendorDir . '/fernleafsystems/wordpress-services/src/Core/Rest.php',
485
+ 'FernleafSystems\\Wordpress\\Services\\Core\\System' => $vendorDir . '/fernleafsystems/wordpress-services/src/Core/System.php',
486
  'FernleafSystems\\Wordpress\\Services\\Core\\Themes' => $vendorDir . '/fernleafsystems/wordpress-services/src/Core/Themes.php',
487
  'FernleafSystems\\Wordpress\\Services\\Core\\Track' => $vendorDir . '/fernleafsystems/wordpress-services/src/Core/Track.php',
488
  'FernleafSystems\\Wordpress\\Services\\Core\\Upgrades\\BulkPluginUpgraderSkin' => $vendorDir . '/fernleafsystems/wordpress-services/src/Core/Upgrades/BulkPluginUpgraderSkin.php',
568
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Iterators\\WpUserIterator' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Iterators/WpUserIterator.php',
569
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\EddActions' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/EddActions.php',
570
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\EddLicenseVO' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/EddLicenseVO.php',
571
+ 'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Keyless\\Base' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Base.php',
572
+ 'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Keyless\\Lookup' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Lookup.php',
573
+ 'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Keyless\\Ping' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Ping.php',
574
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Lookup' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Lookup.php',
575
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\VisitorIpDetection' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Net/VisitorIpDetection.php',
576
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Obfuscate' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Obfuscate.php',
577
+ 'FernleafSystems\\Wordpress\\Services\\Utilities\\Options\\TestCanUseTransients' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Options/TestCanUseTransients.php',
578
+ 'FernleafSystems\\Wordpress\\Services\\Utilities\\Options\\Transient' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Options/Transient.php',
579
  'FernleafSystems\\Wordpress\\Services\\Utilities\\PluginUserMeta' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/PluginUserMeta.php',
580
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Render' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Render.php',
581
  'FernleafSystems\\Wordpress\\Services\\Utilities\\ServiceProviders' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/ServiceProviders.php',
631
  'ICWP_WPSF_FeatureHandler_Sessions' => $baseDir . '/../features/sessions.php',
632
  'ICWP_WPSF_FeatureHandler_Traffic' => $baseDir . '/../features/traffic.php',
633
  'ICWP_WPSF_FeatureHandler_UserManagement' => $baseDir . '/../features/user_management.php',
 
634
  'ICWP_WPSF_Processor_AdminAccessRestriction' => $baseDir . '/../processors/admin_access_restriction.php',
635
  'ICWP_WPSF_Processor_AdminAccess_Whitelabel' => $baseDir . '/../processors/adminaccess_whitelabel.php',
636
  'ICWP_WPSF_Processor_AuditTrail' => $baseDir . '/../processors/audit_trail.php',
649
  'ICWP_WPSF_Processor_HackProtect_Mal' => $baseDir . '/../processors/hackprotect_scan_mal.php',
650
  'ICWP_WPSF_Processor_HackProtect_Ptg' => $baseDir . '/../processors/hackprotect_scan_ptg.php',
651
  'ICWP_WPSF_Processor_HackProtect_Realtime' => $baseDir . '/../processors/hackprotect_realtime.php',
 
652
  'ICWP_WPSF_Processor_HackProtect_Scanner' => $baseDir . '/../processors/hackprotect_scanner.php',
653
  'ICWP_WPSF_Processor_HackProtect_Ufc' => $baseDir . '/../processors/hackprotect_scan_ufc.php',
654
  'ICWP_WPSF_Processor_HackProtect_Wcf' => $baseDir . '/../processors/hackprotect_scan_wcf.php',
684
  'ICWP_WPSF_Processor_UserManagement_Passwords' => $baseDir . '/../processors/usermanagement_passwords.php',
685
  'ICWP_WPSF_Processor_UserManagement_Sessions' => $baseDir . '/../processors/usermanagement_sessions.php',
686
  'ICWP_WPSF_Processor_UserManagement_Suspend' => $baseDir . '/../processors/usermanagement_suspend.php',
 
687
  'ICWP_WPSF_Wizard_Base' => $baseDir . '/../wizards/base.php',
688
  'ICWP_WPSF_Wizard_BaseWpsf' => $baseDir . '/../wizards/base_wpsf.php',
689
  'ICWP_WPSF_Wizard_LoginProtect' => $baseDir . '/../wizards/login_protect.php',
690
  'ICWP_WPSF_Wizard_Plugin' => $baseDir . '/../wizards/plugin.php',
 
691
  'JsonSerializable' => $vendorDir . '/nesbot/carbon/src/JsonSerializable.php',
692
  'LZCompressor\\LZContext' => $vendorDir . '/nullpunkt/lz-string-php/src/LZCompressor/LZContext.php',
693
  'LZCompressor\\LZData' => $vendorDir . '/nullpunkt/lz-string-php/src/LZCompressor/LZData.php',
src/lib/vendor/composer/autoload_static.php CHANGED
@@ -200,6 +200,9 @@ class ComposerStaticInitfcf2fe1888f1f5fc092770cdc8ef3cf4
200
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Snapshot\\Collate' => __DIR__ . '/../..' . '/src/ChangeTrack/Snapshot/Collate.php',
201
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Snapshot\\SnapshotsConsumer' => __DIR__ . '/../..' . '/src/ChangeTrack/Snapshot/SnapshotsConsumer.php',
202
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Controller' => __DIR__ . '/../..' . '/src/Controller/Controller.php',
 
 
 
203
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Crons\\StandardCron' => __DIR__ . '/../..' . '/src/Crons/StandardCron.php',
204
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\AdminNotes\\Delete' => __DIR__ . '/../..' . '/src/Databases/AdminNotes/Delete.php',
205
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\AdminNotes\\EntryVO' => __DIR__ . '/../..' . '/src/Databases/AdminNotes/EntryVO.php',
@@ -344,7 +347,6 @@ class ComposerStaticInitfcf2fe1888f1f5fc092770cdc8ef3cf4
344
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\BaseAction' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/BaseAction.php',
345
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\BaseBulk' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/BaseBulk.php',
346
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\Build' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/Build.php',
347
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\BuildAll' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/BuildAll.php',
348
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\CleanAll' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/CleanAll.php',
349
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\CreateNew' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/CreateNew.php',
350
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\Delete' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/Delete.php',
@@ -402,6 +404,9 @@ class ComposerStaticInitfcf2fe1888f1f5fc092770cdc8ef3cf4
402
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Components\\QueryIpBlock' => __DIR__ . '/../..' . '/src/Modules/IPs/Components/QueryIpBlock.php',
403
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Components\\QueryRemainingOffenses' => __DIR__ . '/../..' . '/src/Modules/IPs/Components/QueryRemainingOffenses.php',
404
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Components\\UnblockIpByFlag' => __DIR__ . '/../..' . '/src/Modules/IPs/Components/UnblockIpByFlag.php',
 
 
 
405
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\OffenseTracker' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/OffenseTracker.php',
406
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Ops\\AddIp' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/Ops/AddIp.php',
407
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Ops\\DeleteIp' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/Ops/DeleteIp.php',
@@ -411,7 +416,13 @@ class ComposerStaticInitfcf2fe1888f1f5fc092770cdc8ef3cf4
411
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Strings' => __DIR__ . '/../..' . '/src/Modules/IPs/Strings.php',
412
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Options' => __DIR__ . '/../..' . '/src/Modules/Insights/Options.php',
413
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Strings' => __DIR__ . '/../..' . '/src/Modules/Insights/Strings.php',
 
414
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\AjaxHandler' => __DIR__ . '/../..' . '/src/Modules/License/AjaxHandler.php',
 
 
 
 
 
415
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Options' => __DIR__ . '/../..' . '/src/Modules/License/Options.php',
416
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Strings' => __DIR__ . '/../..' . '/src/Modules/License/Strings.php',
417
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Lockdown\\Options' => __DIR__ . '/../..' . '/src/Modules/Lockdown/Options.php',
@@ -420,6 +431,16 @@ class ComposerStaticInitfcf2fe1888f1f5fc092770cdc8ef3cf4
420
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\AjaxHandler' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/AjaxHandler.php',
421
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\CooldownFlagFile' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/CooldownFlagFile.php',
422
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\CooldownRedirect' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/CooldownRedirect.php',
 
 
 
 
 
 
 
 
 
 
423
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Options' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Options.php',
424
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Strings' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Strings.php',
425
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\ModConsumer' => __DIR__ . '/../..' . '/src/Modules/ModConsumer.php',
@@ -437,6 +458,7 @@ class ComposerStaticInitfcf2fe1888f1f5fc092770cdc8ef3cf4
437
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\AdminNotices' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/AdminNotices.php',
438
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\AjaxHandler' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/AjaxHandler.php',
439
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\Actions\\RemoveSecAdmin' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/Actions/RemoveSecAdmin.php',
 
440
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Options' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Options.php',
441
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Strings' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Strings.php',
442
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Sessions\\Lib\\Ops\\Terminate' => __DIR__ . '/../..' . '/src/Modules/Sessions/Lib/Ops/Terminate.php',
@@ -451,6 +473,7 @@ class ComposerStaticInitfcf2fe1888f1f5fc092770cdc8ef3cf4
451
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Strings' => __DIR__ . '/../..' . '/src/Modules/Traffic/Strings.php',
452
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\AjaxHandler' => __DIR__ . '/../..' . '/src/Modules/UserManagement/AjaxHandler.php',
453
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Lib\\CleanExpired' => __DIR__ . '/../..' . '/src/Modules/UserManagement/Lib/CleanExpired.php',
 
454
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Lib\\RetrieveActive' => __DIR__ . '/../..' . '/src/Modules/UserManagement/Lib/RetrieveActive.php',
455
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Options' => __DIR__ . '/../..' . '/src/Modules/UserManagement/Options.php',
456
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Strings' => __DIR__ . '/../..' . '/src/Modules/UserManagement/Strings.php',
@@ -514,8 +537,6 @@ class ComposerStaticInitfcf2fe1888f1f5fc092770cdc8ef3cf4
514
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\Scan' => __DIR__ . '/../..' . '/src/Scans/Ptg/Scan.php',
515
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\ScanActionVO' => __DIR__ . '/../..' . '/src/Scans/Ptg/ScanActionVO.php',
516
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\ScanFromFileMap' => __DIR__ . '/../..' . '/src/Scans/Ptg/ScanFromFileMap.php',
517
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\ScannerBase' => __DIR__ . '/../..' . '/src/Scans/Ptg/ScannerBase.php',
518
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\ScannerPlugins' => __DIR__ . '/../..' . '/src/Scans/Ptg/ScannerPlugins.php',
519
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\Table\\EntryFormatter' => __DIR__ . '/../..' . '/src/Scans/Ptg/Table/EntryFormatter.php',
520
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\Utilities\\ItemActionHandler' => __DIR__ . '/../..' . '/src/Scans/Ptg/Utilities/ItemActionHandler.php',
521
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\Utilities\\Repair' => __DIR__ . '/../..' . '/src/Scans/Ptg/Utilities/Repair.php',
@@ -610,6 +631,7 @@ class ComposerStaticInitfcf2fe1888f1f5fc092770cdc8ef3cf4
610
  'FernleafSystems\\Wordpress\\Services\\Core\\Respond' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Core/Respond.php',
611
  'FernleafSystems\\Wordpress\\Services\\Core\\Response' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Core/Response.php',
612
  'FernleafSystems\\Wordpress\\Services\\Core\\Rest' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Core/Rest.php',
 
613
  'FernleafSystems\\Wordpress\\Services\\Core\\Themes' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Core/Themes.php',
614
  'FernleafSystems\\Wordpress\\Services\\Core\\Track' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Core/Track.php',
615
  'FernleafSystems\\Wordpress\\Services\\Core\\Upgrades\\BulkPluginUpgraderSkin' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Core/Upgrades/BulkPluginUpgraderSkin.php',
@@ -695,9 +717,14 @@ class ComposerStaticInitfcf2fe1888f1f5fc092770cdc8ef3cf4
695
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Iterators\\WpUserIterator' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Iterators/WpUserIterator.php',
696
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\EddActions' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/EddActions.php',
697
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\EddLicenseVO' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/EddLicenseVO.php',
 
 
 
698
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Lookup' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Lookup.php',
699
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\VisitorIpDetection' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Net/VisitorIpDetection.php',
700
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Obfuscate' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Obfuscate.php',
 
 
701
  'FernleafSystems\\Wordpress\\Services\\Utilities\\PluginUserMeta' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/PluginUserMeta.php',
702
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Render' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Render.php',
703
  'FernleafSystems\\Wordpress\\Services\\Utilities\\ServiceProviders' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/ServiceProviders.php',
@@ -753,7 +780,6 @@ class ComposerStaticInitfcf2fe1888f1f5fc092770cdc8ef3cf4
753
  'ICWP_WPSF_FeatureHandler_Sessions' => __DIR__ . '/../..' . '/../features/sessions.php',
754
  'ICWP_WPSF_FeatureHandler_Traffic' => __DIR__ . '/../..' . '/../features/traffic.php',
755
  'ICWP_WPSF_FeatureHandler_UserManagement' => __DIR__ . '/../..' . '/../features/user_management.php',
756
- 'ICWP_WPSF_Foundation' => __DIR__ . '/../..' . '/../common/icwp-foundation.php',
757
  'ICWP_WPSF_Processor_AdminAccessRestriction' => __DIR__ . '/../..' . '/../processors/admin_access_restriction.php',
758
  'ICWP_WPSF_Processor_AdminAccess_Whitelabel' => __DIR__ . '/../..' . '/../processors/adminaccess_whitelabel.php',
759
  'ICWP_WPSF_Processor_AuditTrail' => __DIR__ . '/../..' . '/../processors/audit_trail.php',
@@ -772,7 +798,6 @@ class ComposerStaticInitfcf2fe1888f1f5fc092770cdc8ef3cf4
772
  'ICWP_WPSF_Processor_HackProtect_Mal' => __DIR__ . '/../..' . '/../processors/hackprotect_scan_mal.php',
773
  'ICWP_WPSF_Processor_HackProtect_Ptg' => __DIR__ . '/../..' . '/../processors/hackprotect_scan_ptg.php',
774
  'ICWP_WPSF_Processor_HackProtect_Realtime' => __DIR__ . '/../..' . '/../processors/hackprotect_realtime.php',
775
- 'ICWP_WPSF_Processor_HackProtect_ScanAssetsBase' => __DIR__ . '/../..' . '/../processors/hackprotect_scan_assets_base.php',
776
  'ICWP_WPSF_Processor_HackProtect_Scanner' => __DIR__ . '/../..' . '/../processors/hackprotect_scanner.php',
777
  'ICWP_WPSF_Processor_HackProtect_Ufc' => __DIR__ . '/../..' . '/../processors/hackprotect_scan_ufc.php',
778
  'ICWP_WPSF_Processor_HackProtect_Wcf' => __DIR__ . '/../..' . '/../processors/hackprotect_scan_wcf.php',
@@ -808,12 +833,10 @@ class ComposerStaticInitfcf2fe1888f1f5fc092770cdc8ef3cf4
808
  'ICWP_WPSF_Processor_UserManagement_Passwords' => __DIR__ . '/../..' . '/../processors/usermanagement_passwords.php',
809
  'ICWP_WPSF_Processor_UserManagement_Sessions' => __DIR__ . '/../..' . '/../processors/usermanagement_sessions.php',
810
  'ICWP_WPSF_Processor_UserManagement_Suspend' => __DIR__ . '/../..' . '/../processors/usermanagement_suspend.php',
811
- 'ICWP_WPSF_ServiceProviders' => __DIR__ . '/../..' . '/../common/icwp-serviceproviders.php',
812
  'ICWP_WPSF_Wizard_Base' => __DIR__ . '/../..' . '/../wizards/base.php',
813
  'ICWP_WPSF_Wizard_BaseWpsf' => __DIR__ . '/../..' . '/../wizards/base_wpsf.php',
814
  'ICWP_WPSF_Wizard_LoginProtect' => __DIR__ . '/../..' . '/../wizards/login_protect.php',
815
  'ICWP_WPSF_Wizard_Plugin' => __DIR__ . '/../..' . '/../wizards/plugin.php',
816
- 'ICWP_WPSF_WpCron' => __DIR__ . '/../..' . '/../common/icwp-wpcron.php',
817
  'JsonSerializable' => __DIR__ . '/..' . '/nesbot/carbon/src/JsonSerializable.php',
818
  'LZCompressor\\LZContext' => __DIR__ . '/..' . '/nullpunkt/lz-string-php/src/LZCompressor/LZContext.php',
819
  'LZCompressor\\LZData' => __DIR__ . '/..' . '/nullpunkt/lz-string-php/src/LZCompressor/LZData.php',
200
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Snapshot\\Collate' => __DIR__ . '/../..' . '/src/ChangeTrack/Snapshot/Collate.php',
201
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Snapshot\\SnapshotsConsumer' => __DIR__ . '/../..' . '/src/ChangeTrack/Snapshot/SnapshotsConsumer.php',
202
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Controller' => __DIR__ . '/../..' . '/src/Controller/Controller.php',
203
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Crons\\BaseCron' => __DIR__ . '/../..' . '/src/Crons/BaseCron.php',
204
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Crons\\DailyCron' => __DIR__ . '/../..' . '/src/Crons/DailyCron.php',
205
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Crons\\HourlyCron' => __DIR__ . '/../..' . '/src/Crons/HourlyCron.php',
206
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Crons\\StandardCron' => __DIR__ . '/../..' . '/src/Crons/StandardCron.php',
207
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\AdminNotes\\Delete' => __DIR__ . '/../..' . '/src/Databases/AdminNotes/Delete.php',
208
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\AdminNotes\\EntryVO' => __DIR__ . '/../..' . '/src/Databases/AdminNotes/EntryVO.php',
347
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\BaseAction' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/BaseAction.php',
348
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\BaseBulk' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/BaseBulk.php',
349
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\Build' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/Build.php',
 
350
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\CleanAll' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/CleanAll.php',
351
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\CreateNew' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/CreateNew.php',
352
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\Delete' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/Delete.php',
404
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Components\\QueryIpBlock' => __DIR__ . '/../..' . '/src/Modules/IPs/Components/QueryIpBlock.php',
405
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Components\\QueryRemainingOffenses' => __DIR__ . '/../..' . '/src/Modules/IPs/Components/QueryRemainingOffenses.php',
406
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Components\\UnblockIpByFlag' => __DIR__ . '/../..' . '/src/Modules/IPs/Components/UnblockIpByFlag.php',
407
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\BlacklistHandler' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/BlacklistHandler.php',
408
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\BlackmarkRequest' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/BlackmarkRequest.php',
409
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\BlockRequest' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/BlockRequest.php',
410
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\OffenseTracker' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/OffenseTracker.php',
411
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Ops\\AddIp' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/Ops/AddIp.php',
412
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Ops\\DeleteIp' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/Ops/DeleteIp.php',
416
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Strings' => __DIR__ . '/../..' . '/src/Modules/IPs/Strings.php',
417
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Options' => __DIR__ . '/../..' . '/src/Modules/Insights/Options.php',
418
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Strings' => __DIR__ . '/../..' . '/src/Modules/Insights/Strings.php',
419
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\AdminNotices' => __DIR__ . '/../..' . '/src/Modules/License/AdminNotices.php',
420
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\AjaxHandler' => __DIR__ . '/../..' . '/src/Modules/License/AjaxHandler.php',
421
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Lib\\LicenseEmails' => __DIR__ . '/../..' . '/src/Modules/License/Lib/LicenseEmails.php',
422
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Lib\\LicenseHandler' => __DIR__ . '/../..' . '/src/Modules/License/Lib/LicenseHandler.php',
423
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Lib\\LookupRequest' => __DIR__ . '/../..' . '/src/Modules/License/Lib/LookupRequest.php',
424
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Lib\\Verify' => __DIR__ . '/../..' . '/src/Modules/License/Lib/Verify.php',
425
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Lib\\WpHashes\\ApiTokenManager' => __DIR__ . '/../..' . '/src/Modules/License/Lib/WpHashes/ApiTokenManager.php',
426
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Options' => __DIR__ . '/../..' . '/src/Modules/License/Options.php',
427
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Strings' => __DIR__ . '/../..' . '/src/Modules/License/Strings.php',
428
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Lockdown\\Options' => __DIR__ . '/../..' . '/src/Modules/Lockdown/Options.php',
431
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\AjaxHandler' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/AjaxHandler.php',
432
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\CooldownFlagFile' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/CooldownFlagFile.php',
433
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\CooldownRedirect' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/CooldownRedirect.php',
434
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\LoginIntentPage' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/LoginIntentPage.php',
435
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\MfaController' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/MfaController.php',
436
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\MfaControllerConsumer' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/MfaControllerConsumer.php',
437
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\Backup' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Backup.php',
438
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\BaseProvider' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/BaseProvider.php',
439
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\Email' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Email.php',
440
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\GoogleAuth' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/GoogleAuth.php',
441
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\Yubikey' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Yubikey.php',
442
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\UserProfile' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/UserProfile.php',
443
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\ValidateLoginIntentRequest' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/ValidateLoginIntentRequest.php',
444
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Options' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Options.php',
445
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Strings' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Strings.php',
446
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\ModConsumer' => __DIR__ . '/../..' . '/src/Modules/ModConsumer.php',
458
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\AdminNotices' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/AdminNotices.php',
459
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\AjaxHandler' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/AjaxHandler.php',
460
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\Actions\\RemoveSecAdmin' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/Actions/RemoveSecAdmin.php',
461
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\WhiteLabel\\ApplyLabels' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/WhiteLabel/ApplyLabels.php',
462
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Options' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Options.php',
463
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Strings' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Strings.php',
464
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Sessions\\Lib\\Ops\\Terminate' => __DIR__ . '/../..' . '/src/Modules/Sessions/Lib/Ops/Terminate.php',
473
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Strings' => __DIR__ . '/../..' . '/src/Modules/Traffic/Strings.php',
474
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\AjaxHandler' => __DIR__ . '/../..' . '/src/Modules/UserManagement/AjaxHandler.php',
475
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Lib\\CleanExpired' => __DIR__ . '/../..' . '/src/Modules/UserManagement/Lib/CleanExpired.php',
476
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Lib\\Registration\\EmailValidate' => __DIR__ . '/../..' . '/src/Modules/UserManagement/Lib/Registration/EmailValidate.php',
477
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Lib\\RetrieveActive' => __DIR__ . '/../..' . '/src/Modules/UserManagement/Lib/RetrieveActive.php',
478
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Options' => __DIR__ . '/../..' . '/src/Modules/UserManagement/Options.php',
479
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Strings' => __DIR__ . '/../..' . '/src/Modules/UserManagement/Strings.php',
537
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\Scan' => __DIR__ . '/../..' . '/src/Scans/Ptg/Scan.php',
538
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\ScanActionVO' => __DIR__ . '/../..' . '/src/Scans/Ptg/ScanActionVO.php',
539
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\ScanFromFileMap' => __DIR__ . '/../..' . '/src/Scans/Ptg/ScanFromFileMap.php',
 
 
540
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\Table\\EntryFormatter' => __DIR__ . '/../..' . '/src/Scans/Ptg/Table/EntryFormatter.php',
541
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\Utilities\\ItemActionHandler' => __DIR__ . '/../..' . '/src/Scans/Ptg/Utilities/ItemActionHandler.php',
542
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Scans\\Ptg\\Utilities\\Repair' => __DIR__ . '/../..' . '/src/Scans/Ptg/Utilities/Repair.php',
631
  'FernleafSystems\\Wordpress\\Services\\Core\\Respond' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Core/Respond.php',
632
  'FernleafSystems\\Wordpress\\Services\\Core\\Response' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Core/Response.php',
633
  'FernleafSystems\\Wordpress\\Services\\Core\\Rest' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Core/Rest.php',
634
+ 'FernleafSystems\\Wordpress\\Services\\Core\\System' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Core/System.php',
635
  'FernleafSystems\\Wordpress\\Services\\Core\\Themes' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Core/Themes.php',
636
  'FernleafSystems\\Wordpress\\Services\\Core\\Track' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Core/Track.php',
637
  'FernleafSystems\\Wordpress\\Services\\Core\\Upgrades\\BulkPluginUpgraderSkin' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Core/Upgrades/BulkPluginUpgraderSkin.php',
717
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Iterators\\WpUserIterator' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Iterators/WpUserIterator.php',
718
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\EddActions' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/EddActions.php',
719
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\EddLicenseVO' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/EddLicenseVO.php',
720
+ 'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Keyless\\Base' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Base.php',
721
+ 'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Keyless\\Lookup' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Lookup.php',
722
+ 'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Keyless\\Ping' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Ping.php',
723
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Lookup' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Lookup.php',
724
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\VisitorIpDetection' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Net/VisitorIpDetection.php',
725
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Obfuscate' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Obfuscate.php',
726
+ 'FernleafSystems\\Wordpress\\Services\\Utilities\\Options\\TestCanUseTransients' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Options/TestCanUseTransients.php',
727
+ 'FernleafSystems\\Wordpress\\Services\\Utilities\\Options\\Transient' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Options/Transient.php',
728
  'FernleafSystems\\Wordpress\\Services\\Utilities\\PluginUserMeta' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/PluginUserMeta.php',
729
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Render' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Render.php',
730
  'FernleafSystems\\Wordpress\\Services\\Utilities\\ServiceProviders' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/ServiceProviders.php',
780
  'ICWP_WPSF_FeatureHandler_Sessions' => __DIR__ . '/../..' . '/../features/sessions.php',
781
  'ICWP_WPSF_FeatureHandler_Traffic' => __DIR__ . '/../..' . '/../features/traffic.php',
782
  'ICWP_WPSF_FeatureHandler_UserManagement' => __DIR__ . '/../..' . '/../features/user_management.php',
 
783
  'ICWP_WPSF_Processor_AdminAccessRestriction' => __DIR__ . '/../..' . '/../processors/admin_access_restriction.php',
784
  'ICWP_WPSF_Processor_AdminAccess_Whitelabel' => __DIR__ . '/../..' . '/../processors/adminaccess_whitelabel.php',
785
  'ICWP_WPSF_Processor_AuditTrail' => __DIR__ . '/../..' . '/../processors/audit_trail.php',
798
  'ICWP_WPSF_Processor_HackProtect_Mal' => __DIR__ . '/../..' . '/../processors/hackprotect_scan_mal.php',
799
  'ICWP_WPSF_Processor_HackProtect_Ptg' => __DIR__ . '/../..' . '/../processors/hackprotect_scan_ptg.php',
800
  'ICWP_WPSF_Processor_HackProtect_Realtime' => __DIR__ . '/../..' . '/../processors/hackprotect_realtime.php',
 
801
  'ICWP_WPSF_Processor_HackProtect_Scanner' => __DIR__ . '/../..' . '/../processors/hackprotect_scanner.php',
802
  'ICWP_WPSF_Processor_HackProtect_Ufc' => __DIR__ . '/../..' . '/../processors/hackprotect_scan_ufc.php',
803
  'ICWP_WPSF_Processor_HackProtect_Wcf' => __DIR__ . '/../..' . '/../processors/hackprotect_scan_wcf.php',
833
  'ICWP_WPSF_Processor_UserManagement_Passwords' => __DIR__ . '/../..' . '/../processors/usermanagement_passwords.php',
834
  'ICWP_WPSF_Processor_UserManagement_Sessions' => __DIR__ . '/../..' . '/../processors/usermanagement_sessions.php',
835
  'ICWP_WPSF_Processor_UserManagement_Suspend' => __DIR__ . '/../..' . '/../processors/usermanagement_suspend.php',
 
836
  'ICWP_WPSF_Wizard_Base' => __DIR__ . '/../..' . '/../wizards/base.php',
837
  'ICWP_WPSF_Wizard_BaseWpsf' => __DIR__ . '/../..' . '/../wizards/base_wpsf.php',
838
  'ICWP_WPSF_Wizard_LoginProtect' => __DIR__ . '/../..' . '/../wizards/login_protect.php',
839
  'ICWP_WPSF_Wizard_Plugin' => __DIR__ . '/../..' . '/../wizards/plugin.php',
 
840
  'JsonSerializable' => __DIR__ . '/..' . '/nesbot/carbon/src/JsonSerializable.php',
841
  'LZCompressor\\LZContext' => __DIR__ . '/..' . '/nullpunkt/lz-string-php/src/LZCompressor/LZContext.php',
842
  'LZCompressor\\LZData' => __DIR__ . '/..' . '/nullpunkt/lz-string-php/src/LZCompressor/LZData.php',
src/lib/vendor/fernleafsystems/wordpress-services/src/Core/General.php CHANGED
@@ -4,6 +4,7 @@ namespace FernleafSystems\Wordpress\Services\Core;
4
 
5
  use FernleafSystems\Wordpress\Services\Services;
6
  use FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes\Hashes;
 
7
 
8
  class General {
9
 
@@ -12,6 +13,13 @@ class General {
12
  */
13
  protected $sWpVersion;
14
 
 
 
 
 
 
 
 
15
  /**
16
  * @return null|string
17
  */
@@ -579,27 +587,30 @@ class General {
579
  /**
580
  * @param string $sKey
581
  * @param $sValue
 
582
  * @return bool
583
  */
584
- public function updateOption( $sKey, $sValue ) {
585
- return $this->isMultisite() ? update_site_option( $sKey, $sValue ) : update_option( $sKey, $sValue );
586
  }
587
 
588
  /**
589
  * @param string $sKey
590
  * @param mixed $mDefault
 
591
  * @return mixed
592
  */
593
- public function getOption( $sKey, $mDefault = false ) {
594
- return $this->isMultisite() ? get_site_option( $sKey, $mDefault ) : get_option( $sKey, $mDefault );
595
  }
596
 
597
  /**
598
  * @param string $sKey
599
- * @return mixed
 
600
  */
601
- public function deleteOption( $sKey ) {
602
- return $this->isMultisite() ? delete_site_option( $sKey ) : delete_option( $sKey );
603
  }
604
 
605
  /**
4
 
5
  use FernleafSystems\Wordpress\Services\Services;
6
  use FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes\Hashes;
7
+ use FernleafSystems\Wordpress\Services\Utilities\Options\TestCanUseTransients;
8
 
9
  class General {
10
 
13
  */
14
  protected $sWpVersion;
15
 
16
+ /**
17
+ * @return bool
18
+ */
19
+ public function canUseTransients() {
20
+ return ( new TestCanUseTransients() )->run();
21
+ }
22
+
23
  /**
24
  * @return null|string
25
  */
587
  /**
588
  * @param string $sKey
589
  * @param $sValue
590
+ * @param bool $bIgnoreWPMS
591
  * @return bool
592
  */
593
+ public function updateOption( $sKey, $sValue, $bIgnoreWPMS = false ) {
594
+ return ( $this->isMultisite() && !$bIgnoreWPMS ) ? update_site_option( $sKey, $sValue ) : update_option( $sKey, $sValue );
595
  }
596
 
597
  /**
598
  * @param string $sKey
599
  * @param mixed $mDefault
600
+ * @param bool $bIgnoreWPMS
601
  * @return mixed
602
  */
603
+ public function getOption( $sKey, $mDefault = false, $bIgnoreWPMS = false ) {
604
+ return ( $this->isMultisite() && !$bIgnoreWPMS ) ? get_site_option( $sKey, $mDefault ) : get_option( $sKey, $mDefault );
605
  }
606
 
607
  /**
608
  * @param string $sKey
609
+ * @param bool $bIgnoreWPMS
610
+ * @return bool
611
  */
612
+ public function deleteOption( $sKey, $bIgnoreWPMS = false ) {
613
+ return ( $this->isMultisite() && !$bIgnoreWPMS ) ? delete_site_option( $sKey ) : delete_option( $sKey );
614
  }
615
 
616
  /**
src/lib/vendor/fernleafsystems/wordpress-services/src/Core/System.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Services\Core;
4
+
5
+ class System {
6
+
7
+ const PREFIX = 'aptoweb_';
8
+ }
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Data.php CHANGED
@@ -464,6 +464,7 @@ class Data {
464
  'PATH',
465
  'DOCUMENT_ROOT',
466
  'SERVER_ADDR',
 
467
  ] )
468
  ) )
469
  ) );
464
  'PATH',
465
  'DOCUMENT_ROOT',
466
  'SERVER_ADDR',
467
+ 'SERVER_NAME',
468
  ] )
469
  ) )
470
  ) );
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/ApiBase.php CHANGED
@@ -16,6 +16,8 @@ abstract class ApiBase {
16
  const REQUEST_TYPE = 'GET';
17
  const RESPONSE_DATA_KEY = '';
18
 
 
 
19
  /**
20
  * @var RequestVO
21
  */
@@ -31,18 +33,26 @@ abstract class ApiBase {
31
  */
32
  private static $aQueryCache = [];
33
 
 
 
 
 
 
 
 
 
34
  /**
35
  * @return string
36
  */
37
  protected function getApiUrl() {
38
- return trailingslashit( static::API_URL.static::API_ENDPOINT );
39
  }
40
 
41
  /**
42
  * @return array
43
  */
44
  protected function getQueryData() {
45
- return [];
46
  }
47
 
48
  /**
@@ -104,7 +114,7 @@ abstract class ApiBase {
104
  protected function fireRequest_GET() {
105
  $sResponse = null;
106
 
107
- $sUrl = add_query_arg( array_map( 'strtolower', $this->getQueryData() ), $this->getApiUrl() );
108
  $sSig = md5( $sUrl );
109
 
110
  if ( $this->isUseQueryCache() && isset( self::$aQueryCache[ $sSig ] ) ) {
@@ -128,7 +138,7 @@ abstract class ApiBase {
128
  $oHttp = new HttpRequest();
129
  $oHttp
130
  ->post(
131
- add_query_arg( array_map( 'strtolower', $this->getQueryData() ), $this->getApiUrl() ),
132
  [ 'body' => $this->getRequestVO()->getRawDataAsArray() ]
133
  );
134
  return $oHttp->isSuccess() ? $oHttp->lastResponse->body : null;
@@ -141,6 +151,17 @@ abstract class ApiBase {
141
  return (bool)$this->bUseQueryCache;
142
  }
143
 
 
 
 
 
 
 
 
 
 
 
 
144
  /**
145
  * @param bool $bUseQueryCache
146
  * @return $this
16
  const REQUEST_TYPE = 'GET';
17
  const RESPONSE_DATA_KEY = '';
18
 
19
+ protected static $API_TOKEN;
20
+
21
  /**
22
  * @var RequestVO
23
  */
33
  */
34
  private static $aQueryCache = [];
35
 
36
+ /**
37
+ * ApiBase constructor.
38
+ * @param string $sApiToken
39
+ */
40
+ public function __construct( $sApiToken = null ) {
41
+ $this->setApiToken( $sApiToken );
42
+ }
43
+
44
  /**
45
  * @return string
46
  */
47
  protected function getApiUrl() {
48
+ return static::API_URL.static::API_ENDPOINT;
49
  }
50
 
51
  /**
52
  * @return array
53
  */
54
  protected function getQueryData() {
55
+ return empty( static::$API_TOKEN ) ? [] : [ 'token' => static::$API_TOKEN ];
56
  }
57
 
58
  /**
114
  protected function fireRequest_GET() {
115
  $sResponse = null;
116
 
117
+ $sUrl = add_query_arg( $this->getQueryData(), $this->getApiUrl() );
118
  $sSig = md5( $sUrl );
119
 
120
  if ( $this->isUseQueryCache() && isset( self::$aQueryCache[ $sSig ] ) ) {
138
  $oHttp = new HttpRequest();
139
  $oHttp
140
  ->post(
141
+ add_query_arg( $this->getQueryData(), $this->getApiUrl() ),
142
  [ 'body' => $this->getRequestVO()->getRawDataAsArray() ]
143
  );
144
  return $oHttp->isSuccess() ? $oHttp->lastResponse->body : null;
151
  return (bool)$this->bUseQueryCache;
152
  }
153
 
154
+ /**
155
+ * @param string $sToken
156
+ * @return $this
157
+ */
158
+ public function setApiToken( $sToken ) {
159
+ if ( is_string( $sToken ) && preg_match( '#^[a-z0-9]{32,}$#', $sToken ) ) {
160
+ static::$API_TOKEN = $sToken;
161
+ }
162
+ return $this;
163
+ }
164
+
165
  /**
166
  * @param bool $bUseQueryCache
167
  * @return $this
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Hashes/ApiInfo.php CHANGED
@@ -21,6 +21,6 @@ class ApiInfo extends Base {
21
  * @return string
22
  */
23
  protected function getApiUrl() {
24
- return parent::getApiUrl().'info';
25
  }
26
  }
21
  * @return string
22
  */
23
  protected function getApiUrl() {
24
+ return parent::getApiUrl().'/info';
25
  }
26
  }
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Hashes/AssetHashesBase.php CHANGED
@@ -2,8 +2,6 @@
2
 
3
  namespace FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes\Hashes;
4
 
5
- use FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes;
6
-
7
  abstract class AssetHashesBase extends Base {
8
 
9
  const DEFAULT_HASH_ALGO = 'md5';
@@ -14,7 +12,7 @@ abstract class AssetHashesBase extends Base {
14
  * @return string
15
  */
16
  protected function getApiUrl() {
17
- $aData = array_filter( array_merge(
18
  [
19
  'type' => false,
20
  'slug' => false,
@@ -23,8 +21,8 @@ abstract class AssetHashesBase extends Base {
23
  'hash' => false,
24
  ],
25
  $this->getRequestVO()->getRawDataAsArray()
26
- ) );
27
- return sprintf( '%s%s', parent::getApiUrl(), implode( '/', $aData ) );
28
  }
29
 
30
  /**
2
 
3
  namespace FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes\Hashes;
4
 
 
 
5
  abstract class AssetHashesBase extends Base {
6
 
7
  const DEFAULT_HASH_ALGO = 'md5';
12
  * @return string
13
  */
14
  protected function getApiUrl() {
15
+ $aData = array_map( 'strtolower', array_filter( array_merge(
16
  [
17
  'type' => false,
18
  'slug' => false,
21
  'hash' => false,
22
  ],
23
  $this->getRequestVO()->getRawDataAsArray()
24
+ ) ) );
25
+ return sprintf( '%s/%s', parent::getApiUrl(), implode( '/', $aData ) );
26
  }
27
 
28
  /**
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Hashes/Base.php CHANGED
@@ -6,5 +6,5 @@ use FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes;
6
 
7
  abstract class Base extends WpHashes\ApiBase {
8
 
9
- const API_ENDPOINT = 'hashes/';
10
  }
6
 
7
  abstract class Base extends WpHashes\ApiBase {
8
 
9
+ const API_ENDPOINT = 'hashes';
10
  }
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Hashes/PluginThemeBase.php CHANGED
@@ -17,9 +17,9 @@ abstract class PluginThemeBase extends AssetHashesBase {
17
  public function getHashes( $sSlug, $sVersion, $sHashAlgo = null ) {
18
  /** @var RequestVO $oReq */
19
  $oReq = $this->getRequestVO();
 
20
  $oReq->version = $sVersion;
21
  $oReq->hash = $sHashAlgo;
22
- $oReq->slug = $sSlug;
23
  return $this->query();
24
  }
25
  }
17
  public function getHashes( $sSlug, $sVersion, $sHashAlgo = null ) {
18
  /** @var RequestVO $oReq */
19
  $oReq = $this->getRequestVO();
20
+ $oReq->slug = $sSlug;
21
  $oReq->version = $sVersion;
22
  $oReq->hash = $sHashAlgo;
 
23
  return $this->query();
24
  }
25
  }
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Malware/Confidence/Base.php CHANGED
@@ -6,7 +6,7 @@ use FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes;
6
 
7
  abstract class Base extends WpHashes\ApiBase {
8
 
9
- const API_ENDPOINT = 'malware/fpconfidence/';
10
 
11
  /**
12
  * @return RequestVO
6
 
7
  abstract class Base extends WpHashes\ApiBase {
8
 
9
+ const API_ENDPOINT = 'malware/fpconfidence';
10
 
11
  /**
12
  * @return RequestVO
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Malware/Confidence/Retrieve.php CHANGED
@@ -25,7 +25,7 @@ class Retrieve extends Base {
25
  ],
26
  $this->getRequestVO()->getRawDataAsArray()
27
  ) );
28
- return sprintf( '%s%s', parent::getApiUrl(), implode( '/', $aData ) );
29
  }
30
 
31
  /**
25
  ],
26
  $this->getRequestVO()->getRawDataAsArray()
27
  ) );
28
+ return sprintf( '%s/%s', parent::getApiUrl(), implode( '/', $aData ) );
29
  }
30
 
31
  /**
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Services/Base.php CHANGED
@@ -6,7 +6,7 @@ use FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes;
6
 
7
  abstract class Base extends WpHashes\ApiBase {
8
 
9
- const API_ENDPOINT = 'services/';
10
 
11
  /**
12
  * @return RequestVO
6
 
7
  abstract class Base extends WpHashes\ApiBase {
8
 
9
+ const API_ENDPOINT = 'services';
10
 
11
  /**
12
  * @return RequestVO
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Services/IPs.php CHANGED
@@ -21,6 +21,6 @@ class IPs extends Base {
21
  * @return string
22
  */
23
  protected function getApiUrl() {
24
- return parent::getApiUrl().'ips';
25
  }
26
  }
21
  * @return string
22
  */
23
  protected function getApiUrl() {
24
+ return parent::getApiUrl().'/ips';
25
  }
26
  }
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Token/Base.php CHANGED
@@ -6,7 +6,7 @@ use FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes;
6
 
7
  abstract class Base extends WpHashes\ApiBase {
8
 
9
- const API_ENDPOINT = 'token/';
10
  const RESPONSE_DATA_KEY = 'token';
11
 
12
  /**
6
 
7
  abstract class Base extends WpHashes\ApiBase {
8
 
9
+ const API_ENDPOINT = 'token';
10
  const RESPONSE_DATA_KEY = 'token';
11
 
12
  /**
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Token/Solicit.php CHANGED
@@ -2,8 +2,6 @@
2
 
3
  namespace FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes\Token;
4
 
5
- use FernleafSystems\Wordpress\Services\Utilities\Licenses\EddActions;
6
-
7
  /**
8
  * Class Solicit
9
  * @package FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes\Token
@@ -20,22 +18,27 @@ class Solicit extends Base {
20
  $oReq = $this->getRequestVO();
21
  $oReq->action = 'solicit';
22
  $oReq->install_id = $sInstallId;
23
- $oReq->url = untrailingslashit( EddActions::CleanUrl( $sUrl ) );
24
  return $this->query();
25
  }
26
 
27
  /**
28
- * @return string
29
  */
30
  protected function getApiUrl() {
31
- $aData = array_filter( array_merge(
32
- [
33
- 'action' => false,
34
- 'install_id' => false,
35
- 'url' => false,
36
- ],
37
- $this->getRequestVO()->getRawDataAsArray()
38
- ) );
39
- return sprintf( '%s%s', parent::getApiUrl(), implode( '/', $aData ) );
 
 
 
 
 
40
  }
41
  }
2
 
3
  namespace FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes\Token;
4
 
 
 
5
  /**
6
  * Class Solicit
7
  * @package FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes\Token
18
  $oReq = $this->getRequestVO();
19
  $oReq->action = 'solicit';
20
  $oReq->install_id = $sInstallId;
21
+ $oReq->url = strpos( $sUrl, '?' ) ? explode( '?', $sUrl, 2 )[ 0 ] : $sUrl;
22
  return $this->query();
23
  }
24
 
25
  /**
26
+ * @inheritDoc
27
  */
28
  protected function getApiUrl() {
29
+ /** @var RequestVO $oReq */
30
+ $oReq = $this->getRequestVO();
31
+ return sprintf( '%s/%s/%s', parent::getApiUrl(), $oReq->action, $oReq->install_id );
32
+ }
33
+
34
+ /**
35
+ * @inheritDoc
36
+ */
37
+ protected function getQueryData() {
38
+ /** @var RequestVO $oReq */
39
+ $oReq = $this->getRequestVO();
40
+ $aData = parent::getQueryData();
41
+ $aData[ 'url' ] = $oReq->url;
42
+ return $aData;
43
  }
44
  }
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Verify/Base.php CHANGED
@@ -6,7 +6,7 @@ use FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes;
6
 
7
  abstract class Base extends WpHashes\ApiBase {
8
 
9
- const API_ENDPOINT = 'verify/';
10
  const RESPONSE_DATA_KEY = 'verification';
11
 
12
  /**
6
 
7
  abstract class Base extends WpHashes\ApiBase {
8
 
9
+ const API_ENDPOINT = 'verify';
10
  const RESPONSE_DATA_KEY = 'verification';
11
 
12
  /**
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Verify/Email.php CHANGED
@@ -30,6 +30,6 @@ class Email extends Base {
30
  ],
31
  $this->getRequestVO()->getRawDataAsArray()
32
  ) ) );
33
- return sprintf( '%s%s', parent::getApiUrl(), implode( '/', $aData ) );
34
  }
35
  }
30
  ],
31
  $this->getRequestVO()->getRawDataAsArray()
32
  ) ) );
33
+ return sprintf( '%s/%s', parent::getApiUrl(), implode( '/', $aData ) );
34
  }
35
  }
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Vulnerabilities/Base.php CHANGED
@@ -6,7 +6,7 @@ use FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes;
6
 
7
  abstract class Base extends WpHashes\ApiBase {
8
 
9
- const API_ENDPOINT = 'vulnerabilities/';
10
  const ASSET_TYPE = '';
11
  const RESPONSE_DATA_KEY = 'vulnerabilities';
12
 
@@ -21,7 +21,7 @@ abstract class Base extends WpHashes\ApiBase {
21
  * @return string
22
  */
23
  protected function getApiUrl() {
24
- return parent::getApiUrl().$this->getRequestVO()->type.'/';
25
  }
26
 
27
  /**
6
 
7
  abstract class Base extends WpHashes\ApiBase {
8
 
9
+ const API_ENDPOINT = 'vulnerabilities';
10
  const ASSET_TYPE = '';
11
  const RESPONSE_DATA_KEY = 'vulnerabilities';
12
 
21
  * @return string
22
  */
23
  protected function getApiUrl() {
24
+ return parent::getApiUrl().'/'.$this->getRequestVO()->type;
25
  }
26
 
27
  /**
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Vulnerabilities/BasePluginTheme.php CHANGED
@@ -15,7 +15,7 @@ abstract class BasePluginTheme extends Base {
15
  */
16
  public function getVulnerabilities( $sSlug, $sVersion ) {
17
  $oReq = $this->getRequestVO();
18
- $oReq->slug = $sSlug;
19
  $oReq->version = $sVersion;
20
  return $this->query();
21
  }
@@ -25,6 +25,6 @@ abstract class BasePluginTheme extends Base {
25
  */
26
  protected function getApiUrl() {
27
  $oReq = $this->getRequestVO();
28
- return sprintf( '%s%s/%s', parent::getApiUrl(), $oReq->slug, $oReq->version );
29
  }
30
  }
15
  */
16
  public function getVulnerabilities( $sSlug, $sVersion ) {
17
  $oReq = $this->getRequestVO();
18
+ $oReq->slug = strtolower( $sSlug );
19
  $oReq->version = $sVersion;
20
  return $this->query();
21
  }
25
  */
26
  protected function getApiUrl() {
27
  $oReq = $this->getRequestVO();
28
+ return sprintf( '%s/%s/%s', parent::getApiUrl(), $oReq->slug, $oReq->version );
29
  }
30
  }
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/IpUtils.php CHANGED
@@ -379,164 +379,4 @@ class IpUtils {
379
  $this->sIp = $sIp;
380
  return $this;
381
  }
382
-
383
- /**
384
- * @param string $sIp
385
- * @return bool
386
- * @throws \Exception
387
- * @deprecated 0.1.43
388
- */
389
- public function isCloudFlareIp( $sIp ) {
390
- return Services::ServiceProviders()->isIp_Cloudflare( $sIp );
391
- }
392
-
393
- /**
394
- * Checks:
395
- * - valid public remote IP
396
- * - Not CloudFlare
397
- * - Not the IP of the currently running server if this is provided
398
- * @param string $sIp
399
- * @param string $sHostIp
400
- * @return bool
401
- * @deprecated 0.1.43
402
- */
403
- public function isViablePublicVisitorIp( $sIp, $sHostIp = '' ) {
404
- return !empty( $sIp ) && $this->isValidIp_PublicRemote( $sIp )
405
- && !Services::ServiceProviders()->isIp_Cloudflare( $sIp )
406
- && ( empty( $sHostIp ) || !$this->checkIp( $sIp, $sHostIp ) );
407
- }
408
-
409
- /**
410
- * @return string
411
- * @deprecated 0.1.43
412
- */
413
- public function discoverViableRequestIpSource() {
414
- return $this->findViableVisitorIp()[ 'source' ];
415
- }
416
-
417
- /**
418
- * @param bool $bRemoteVerify
419
- * @return string[]
420
- * @deprecated 0.1.43
421
- */
422
- protected function findViableVisitorIp( $bRemoteVerify = false ) {
423
- return [
424
- 'source' => $this->getIpDetector()->getLastSuccessfulSource(),
425
- 'ip' => $this->getRequestIp()
426
- ];
427
- }
428
-
429
- /**
430
- * @return string[]
431
- * @deprecated 0.1.43
432
- */
433
- protected function getCloudFlareIpsV4() {
434
- return Services::ServiceProviders()->getIps_iControlWP()[ 4 ];
435
- }
436
-
437
- /**
438
- * @return string[]
439
- * @deprecated 0.1.43
440
- */
441
- protected function getCloudFlareIpsV6() {
442
- return Services::ServiceProviders()->getIps_iControlWP()[ 6 ];
443
- }
444
-
445
- /**
446
- * @param int $sIpVersion
447
- * @return string[]
448
- * @deprecated 0.1.43
449
- */
450
- public function getServiceIps_Pingdom( $sIpVersion = 4 ) {
451
- return Services::ServiceProviders()->getIps_Pingdom( true );
452
- }
453
-
454
- /**
455
- * @return string[]
456
- * @deprecated 0.1.43
457
- */
458
- public function getServiceIps_StatusCake() {
459
- return Services::ServiceProviders()->getIps_Statuscake( true );
460
- }
461
-
462
- /**
463
- * @param int $sIpVersion
464
- * @return string[]
465
- * @deprecated 0.1.43
466
- */
467
- public function getServiceIps_UptimeRobot( $sIpVersion = 4 ) {
468
- return Services::ServiceProviders()->getIps_UptimeRobot( true );
469
- }
470
-
471
- /**
472
- * @param string $sIp
473
- * @param string $sUserAgent
474
- * @return bool
475
- * @deprecated 0.1.43
476
- */
477
- public function isIpBingBot( $sIp, $sUserAgent = '' ) {
478
- return Services::ServiceProviders()->isIp_BingBot( $sIp, $sUserAgent );
479
- }
480
-
481
- /**
482
- * https://duckduckgo.com/duckduckbot
483
- * @param string $sIp
484
- * @param string $sUserAgent
485
- * @return bool
486
- * @deprecated 0.1.43
487
- */
488
- public function isIpDuckDuckGoBot( $sIp, $sUserAgent = '' ) {
489
- return Services::ServiceProviders()->isIp_DuckDuckGoBot( $sIp, $sUserAgent );
490
- }
491
-
492
- /**
493
- * @param string $sIp
494
- * @param string $sUserAgent
495
- * @return bool
496
- * @deprecated 0.1.43
497
- */
498
- public function isIpGoogleBot( $sIp, $sUserAgent = '' ) {
499
- return Services::ServiceProviders()->isIp_GoogleBot( $sIp, $sUserAgent );
500
- }
501
-
502
- /**
503
- * @param string $sIp
504
- * @param string $sUserAgent
505
- * @return bool
506
- * @deprecated 0.1.43
507
- */
508
- public function isIpYandexBot( $sIp, $sUserAgent = '' ) {
509
- return Services::ServiceProviders()->isIp_YandexBot( $sIp, $sUserAgent );
510
- }
511
-
512
- /**
513
- * https://support.apple.com/en-gb/HT204683
514
- * https://discussions.apple.com/thread/7090135
515
- * Apple IPs start with '17.'
516
- * @param string $sIp
517
- * @param string $sUserAgent
518
- * @return bool
519
- * @deprecated 0.1.43
520
- */
521
- public function isIpAppleBot( $sIp, $sUserAgent = '' ) {
522
- return Services::ServiceProviders()->isIp_AppleBot( $sIp, $sUserAgent );
523
- }
524
-
525
- /**
526
- * @return string|null
527
- * @deprecated 0.1.39
528
- */
529
- public function whatIsMyIp() {
530
- $aIPs = $this->getServerPublicIPs();
531
- return array_shift( $aIPs );
532
- }
533
-
534
- /**
535
- * @param string $sIp
536
- * @return $this
537
- * @deprecated 0.1.39
538
- */
539
- public function setServerIpAddress( $sIp ) {
540
- return $this;
541
- }
542
  }
379
  $this->sIp = $sIp;
380
  return $this;
381
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
382
  }
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Licenses/EddActions.php CHANGED
@@ -9,8 +9,10 @@ class EddActions {
9
  * @return string
10
  */
11
  public static function CleanUrl( $sUrl ) {
12
- return sanitize_text_field( trailingslashit(
13
- preg_replace( '#^(https?:/{1,2})?(www\.)?#', '', mb_strtolower( trim( $sUrl ) ) )
14
- ) );
 
 
15
  }
16
  }
9
  * @return string
10
  */
11
  public static function CleanUrl( $sUrl ) {
12
+ $sUrl = preg_replace( '#^(https?:/{1,2})?(www\.)?#', '', mb_strtolower( trim( $sUrl ) ) );
13
+ if ( strpos( $sUrl, '?' ) ) {
14
+ $sUrl = explode( '?', $sUrl, 2 )[ 0 ];
15
+ }
16
+ return sanitize_text_field( trailingslashit( $sUrl ) );
17
  }
18
  }
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Licenses/EddLicenseVO.php CHANGED
@@ -12,6 +12,8 @@ use FernleafSystems\Wordpress\Services\Services;
12
  * @property string $checksum
13
  * @property string $customer_name
14
  * @property string $item_name
 
 
15
  * @property int $last_request_at
16
  * @property int $last_verified_at
17
  * @property int $license_limit
@@ -29,8 +31,7 @@ class EddLicenseVO {
29
  * @return int
30
  */
31
  public function getExpiresAt() {
32
- $sTime = $this->getParam( 'expires' );
33
- return ( $sTime == 'lifetime' ) ? PHP_INT_MAX : strtotime( $sTime );
34
  }
35
 
36
  /**
@@ -73,7 +74,8 @@ class EddLicenseVO {
73
  * @return $this
74
  */
75
  public function updateLastVerifiedAt( $bAddRandom = false ) {
76
- $nRandom = $bAddRandom ? rand( -6, 18 )*HOUR_IN_SECONDS : 0;
77
- return $this->setParam( 'last_verified_at', $this->last_request_at + $nRandom );
 
78
  }
79
  }
12
  * @property string $checksum
13
  * @property string $customer_name
14
  * @property string $item_name
15
+ * @property string $expires - date string or "lifetime"
16
+ * @property int $expires_at - unix timestamp
17
  * @property int $last_request_at
18
  * @property int $last_verified_at
19
  * @property int $license_limit
31
  * @return int
32
  */
33
  public function getExpiresAt() {
34
+ return ( $this->expires == 'lifetime' ) ? PHP_INT_MAX : strtotime( $this->expires );
 
35
  }
36
 
37
  /**
74
  * @return $this
75
  */
76
  public function updateLastVerifiedAt( $bAddRandom = false ) {
77
+ $this->last_verified_at = (int)$this->last_request_at +
78
+ ( $bAddRandom ? rand( -6, 18 )*HOUR_IN_SECONDS : 0 );
79
+ return $this;
80
  }
81
  }
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Base.php ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Services\Utilities\Licenses\Keyless;
4
+
5
+ use FernleafSystems\Utilities\Data\Adapter\StdClassAdapter;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
+ use FernleafSystems\Wordpress\Services\Utilities\HttpRequest;
8
+
9
+ /**
10
+ * Class Lookup
11
+ * @package FernleafSystems\Wordpress\Services\Utilities\Licenses\Keyless
12
+ * @property string $lookup_url_stub
13
+ * @property string $request_method
14
+ * @property int $timeout
15
+ * @property HttpRequest $last_http_req
16
+ */
17
+ abstract class Base {
18
+
19
+ use StdClassAdapter {
20
+ __get as __adapterGet;
21
+ }
22
+ const DEFAULT_URL_STUB = 'https://www.shieldsecurity.io/wp-json/odp-eddkeyless/v1';
23
+ const API_ACTION = '';
24
+
25
+ /**
26
+ * @return array|null
27
+ */
28
+ protected function sendReq() {
29
+ $oHttpReq = Services::HttpRequest();
30
+
31
+ $aParams = [
32
+ 'timeout' => $this->timeout,
33
+ 'body' => array_intersect_key(
34
+ $this->getRawDataAsArray(),
35
+ array_flip( $this->getRequestBodyParamKeys() )
36
+ )
37
+ ];
38
+
39
+ switch ( $this->request_method ) {
40
+ case 'post':
41
+ $bReqSuccess = $oHttpReq->post( $this->getApiRequestUrl(), $aParams );
42
+ break;
43
+ case 'get':
44
+ default:
45
+ $bReqSuccess = $oHttpReq->get( $this->getApiRequestUrl(), $aParams );
46
+ break;
47
+ }
48
+
49
+ if ( $bReqSuccess ) {
50
+ $aResponse = empty( $oHttpReq->lastResponse->body ) ? [] : @json_decode( $oHttpReq->lastResponse->body, true );
51
+ }
52
+ else {
53
+ $aResponse = null;
54
+ }
55
+
56
+ $this->last_http_req = $oHttpReq;
57
+ return $aResponse;
58
+ }
59
+
60
+ /**
61
+ * @return string
62
+ */
63
+ protected function getApiRequestUrl() {
64
+ return sprintf( '%s/%s', $this->lookup_url_stub, static::API_ACTION );
65
+ }
66
+
67
+ /**
68
+ * @return string[]
69
+ */
70
+ protected function getRequestBodyParamKeys() {
71
+ return [];
72
+ }
73
+
74
+ /**
75
+ * @param string $sProperty
76
+ * @return mixed
77
+ */
78
+ public function __get( $sProperty ) {
79
+
80
+ $mValue = $this->__adapterGet( $sProperty );
81
+
82
+ switch ( $sProperty ) {
83
+
84
+ case 'request_method':
85
+ if ( empty( $mValue ) ) {
86
+ $mValue = 'get';
87
+ }
88
+ $mValue = strtolower( $mValue );
89
+ break;
90
+
91
+ case 'lookup_url_stub':
92
+ if ( empty( $mValue ) ) {
93
+ $mValue = static::DEFAULT_URL_STUB;
94
+ }
95
+ $mValue = rtrim( $mValue, '/' );
96
+ break;
97
+
98
+ case 'timeout':
99
+ if ( empty( $mValue ) || !is_numeric( $mValue ) ) {
100
+ $mValue = 60;
101
+ }
102
+ break;
103
+
104
+ default:
105
+ break;
106
+ }
107
+
108
+ return $mValue;
109
+ }
110
+ }
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Lookup.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Services\Utilities\Licenses\Keyless;
4
+
5
+ use FernleafSystems\Wordpress\Services\Services;
6
+ use FernleafSystems\Wordpress\Services\Utilities\Licenses\EddLicenseVO;
7
+
8
+ /**
9
+ * Class Lookup
10
+ * @package FernleafSystems\Wordpress\Services\Utilities\Licenses\Keyless
11
+ * @property int $item_id
12
+ * @property string $install_id
13
+ * @property string $url
14
+ * @property string $nonce
15
+ * @property array $meta
16
+ */
17
+ class Lookup extends Base {
18
+
19
+ const API_ACTION = 'lookup';
20
+
21
+ /**
22
+ * @return EddLicenseVO
23
+ */
24
+ public function lookup() {
25
+ if ( empty( $this->url ) ) {
26
+ $this->url = Services::WpGeneral()->getHomeUrl( '', true );
27
+ }
28
+
29
+ $aRaw = $this->sendReq();
30
+ if ( is_array( $aRaw ) && !empty( $aRaw[ 'keyless' ] ) && !empty( $aRaw[ 'keyless' ][ 'license' ] ) ) {
31
+ $aLicenseInfo = $aRaw[ 'keyless' ][ 'license' ];
32
+ }
33
+ else {
34
+ $aLicenseInfo = [];
35
+ }
36
+
37
+ $oLic = ( new EddLicenseVO() )->applyFromArray( $aLicenseInfo );
38
+ $oLic->last_request_at = Services::Request()->ts();
39
+ return $oLic;
40
+ }
41
+
42
+ /**
43
+ * @return string
44
+ */
45
+ protected function getApiRequestUrl() {
46
+ return sprintf( '%s/%s/%s', parent::getApiRequestUrl(), $this->item_id, $this->install_id );
47
+ }
48
+
49
+ /**
50
+ * @return string[]
51
+ */
52
+ protected function getRequestBodyParamKeys() {
53
+ return [
54
+ 'url',
55
+ 'nonce',
56
+ 'meta',
57
+ ];
58
+ }
59
+ }
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Ping.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Services\Utilities\Licenses\Keyless;
4
+
5
+ /**
6
+ * Class Ping
7
+ * @package FernleafSystems\Wordpress\Services\Utilities\Licenses\Keyless
8
+ */
9
+ class Ping extends Base {
10
+
11
+ const API_ACTION = 'ping';
12
+
13
+ /**
14
+ * @return bool
15
+ */
16
+ public function ping() {
17
+ $sPong = '';
18
+
19
+ $aRaw = $this->sendReq();
20
+ if ( is_array( $aRaw ) && !empty( $aRaw[ 'keyless' ] ) && !empty( $aRaw[ 'keyless' ][ self::API_ACTION ] ) ) {
21
+ $sPong = $aRaw[ 'keyless' ][ self::API_ACTION ];
22
+ }
23
+
24
+ return $sPong === 'pong';
25
+ }
26
+ }
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Licenses/Lookup.php CHANGED
@@ -4,6 +4,11 @@ namespace FernleafSystems\Wordpress\Services\Utilities\Licenses;
4
 
5
  use FernleafSystems\Wordpress\Services\Services;
6
 
 
 
 
 
 
7
  class Lookup {
8
 
9
  /**
@@ -94,7 +99,6 @@ class Lookup {
94
  'license' => $sKey,
95
  'item_id' => $sItemId,
96
  'url' => $oWp->getHomeUrl( '', true ),
97
- 'alt_url' => $oWp->getWpUrl()
98
  ],
99
  $this->getRequestParams()
100
  )
4
 
5
  use FernleafSystems\Wordpress\Services\Services;
6
 
7
+ /**
8
+ * Class Lookup
9
+ * @package FernleafSystems\Wordpress\Services\Utilities\Licenses
10
+ * @deprecated 0.1.60
11
+ */
12
  class Lookup {
13
 
14
  /**
99
  'license' => $sKey,
100
  'item_id' => $sItemId,
101
  'url' => $oWp->getHomeUrl( '', true ),
 
102
  ],
103
  $this->getRequestParams()
104
  )
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Options/TestCanUseTransients.php ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Services\Utilities\Options;
4
+
5
+ use FernleafSystems\Wordpress\Services\Core\System;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
+
8
+ /**
9
+ * Remarkably, it seems that some WordPress sites can't actually store WordPress Transients
10
+ * so we run a quick test to see.
11
+ *
12
+ * Class Transient
13
+ * @package FernleafSystems\Wordpress\Services\Utilities\Options
14
+ */
15
+ class TestCanUseTransients {
16
+
17
+ /**
18
+ * @var bool
19
+ */
20
+ private static $bCan;
21
+
22
+ /**
23
+ * @return bool
24
+ */
25
+ public function run() {
26
+ if ( isset( self::$bCan ) ) {
27
+ return self::$bCan;
28
+ }
29
+
30
+ $oWP = Services::WpGeneral();
31
+ $sOptPrefix = System::PREFIX.'can_trans_';
32
+ $mCan = $oWP->getOption( $sOptPrefix.'confirmed', false, true );
33
+
34
+ if ( !in_array( $mCan, [ 'Y', 'N' ] ) ) {
35
+ $nStartedAt = $oWP->getOption( $sOptPrefix.'started', false, true );
36
+ if ( is_numeric( $nStartedAt ) && $nStartedAt > 0 ) {
37
+ $sTransResult = $oWP->getTransient( $sOptPrefix.'test' );
38
+ if ( $sTransResult === System::PREFIX.'test_value' ) {
39
+ $mCan = 'Y';
40
+ }
41
+ else {
42
+ $mCan = 'N';
43
+ }
44
+ $oWP->deleteOption( $sOptPrefix.'started', true );
45
+ $oWP->updateOption( $sOptPrefix.'confirmed', $mCan, true );
46
+ }
47
+ else {
48
+ $mCan = 'Y'; // We temporarily state that we can use transients
49
+ $oWP->setTransient( $sOptPrefix.'test', System::PREFIX.'test_value', 3600 );
50
+ $oWP->updateOption( $sOptPrefix.'started', Services::Request()->ts(), true );
51
+ }
52
+ }
53
+
54
+ self::$bCan = ( $mCan === 'Y' );
55
+ return self::$bCan;
56
+ }
57
+ }
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Options/Transient.php ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace FernleafSystems\Wordpress\Services\Utilities\Options;
4
+
5
+ use FernleafSystems\Wordpress\Services\Core\System;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
+
8
+ /**
9
+ * Remarkably, it seems that some WordPress sites can't actually store WordPress Transients.
10
+ * Class Transient
11
+ * @package FernleafSystems\Wordpress\Services\Utilities\Options
12
+ */
13
+ class Transient {
14
+
15
+ /**
16
+ * @param string $sKey
17
+ * @param bool $bIgnoreWPMS
18
+ * @return bool
19
+ */
20
+ public static function Delete( $sKey, $bIgnoreWPMS = true ) {
21
+ $oWP = Services::WpGeneral();
22
+ return $oWP->canUseTransients() ?
23
+ $oWP->deleteTransient( $sKey )
24
+ : Services::WpGeneral()->deleteOption( System::PREFIX.'trans_'.$sKey, $bIgnoreWPMS );
25
+ }
26
+
27
+ /**
28
+ * @param string $sKey
29
+ * @param null $mDefault
30
+ * @param bool $bIgnoreWPMS
31
+ * @return mixed|null
32
+ */
33
+ public static function Get( $sKey, $mDefault = null, $bIgnoreWPMS = true ) {
34
+ $mVal = null;
35
+
36
+ $oWP = Services::WpGeneral();
37
+
38
+ if ( $oWP->canUseTransients() ) {
39
+ $mVal = $oWP->getTransient( $sKey );
40
+ }
41
+ else {
42
+ $aData = $oWP->getOption( System::PREFIX.'trans_'.$sKey, null, $bIgnoreWPMS );
43
+ if ( !empty( $aData ) && is_array( $aData ) && isset( $aData[ 'data' ] )
44
+ && isset( $aData[ 'expires_at' ] ) ) {
45
+ if ( $aData[ 'expires_at' ] === 0 || Services::Request()->ts() < $aData[ 'expires_at' ] ) {
46
+ $mVal = $aData[ 'data' ];
47
+ }
48
+ }
49
+ }
50
+
51
+ return is_null( $mVal ) ? $mDefault : $mVal;
52
+ }
53
+
54
+ /**
55
+ * @param string $sKey
56
+ * @param mixed $mData
57
+ * @param int $nLifeTime
58
+ * @param bool $bIgnoreWPMS
59
+ * @return bool
60
+ */
61
+ public static function Set( $sKey, $mData, $nLifeTime = 0, $bIgnoreWPMS = true ) {
62
+ if ( is_null( $mData ) ) {
63
+ self::Delete( $sKey );
64
+ }
65
+
66
+ $oWP = Services::WpGeneral();
67
+
68
+ if ( $oWP->canUseTransients() ) {
69
+ return $oWP->setTransient( $sKey, $mData, $nLifeTime );
70
+ }
71
+ else {
72
+ return $oWP->updateOption(
73
+ System::PREFIX.'trans_'.$sKey,
74
+ [
75
+ 'data' => $mData,
76
+ 'expires_at' => empty( $nLifeTime ) ? 0 : Services::Request()->ts() + max( 0, $nLifeTime ),
77
+ ],
78
+ $bIgnoreWPMS
79
+ );
80
+ }
81
+ }
82
+ }
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/ServiceProviders.php CHANGED
@@ -4,6 +4,7 @@ namespace FernleafSystems\Wordpress\Services\Utilities;
4
 
5
  use FernleafSystems\Wordpress\Services\Services;
6
  use FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes\Services\IPs;
 
7
 
8
  /**
9
  * Class ServiceProviders
@@ -32,12 +33,10 @@ class ServiceProviders {
32
  * @return string[][][]|null
33
  */
34
  protected function getAllServiceIPs() {
35
- $oWp = Services::WpGeneral();
36
- $sStoreKey = $this->getPrefixedStoreKey( 'serviceips_wphashes_all' );
37
- $aIps = $oWp->getTransient( $sStoreKey );
38
  if ( empty( $aIps ) ) {
39
  $aIps = ( new IPs() )->getIPs();
40
- $oWp->setTransient( $sStoreKey, $aIps, WEEK_IN_SECONDS );
41
  }
42
  return $aIps;
43
  }
4
 
5
  use FernleafSystems\Wordpress\Services\Services;
6
  use FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes\Services\IPs;
7
+ use FernleafSystems\Wordpress\Services\Utilities\Options\Transient;
8
 
9
  /**
10
  * Class ServiceProviders
33
  * @return string[][][]|null
34
  */
35
  protected function getAllServiceIPs() {
36
+ $aIps = Transient::Get( 'serviceips_all' );
 
 
37
  if ( empty( $aIps ) ) {
38
  $aIps = ( new IPs() )->getIPs();
39
+ $aIps = Transient::Set( 'serviceips_all',$aIps, WEEK_IN_SECONDS );
40
  }
41
  return $aIps;
42
  }
src/lib/vendor/symfony/polyfill-mbstring/Mbstring.php CHANGED
@@ -545,7 +545,14 @@ final class Mbstring
545
  }
546
 
547
  if ('UTF-8' === $encoding = self::getEncoding($encoding)) {
548
- return preg_split("/(.{{$split_length}})/u", $string, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
 
 
 
 
 
 
 
549
  }
550
 
551
  $result = array();
545
  }
546
 
547
  if ('UTF-8' === $encoding = self::getEncoding($encoding)) {
548
+ $rx = '/(';
549
+ while (65535 < $split_length) {
550
+ $rx .= '.{65535}';
551
+ $split_length -= 65535;
552
+ }
553
+ $rx .= '.{'.$split_length.'})/us';
554
+
555
+ return preg_split($rx, $string, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
556
  }
557
 
558
  $result = array();
src/processors/admin_access_restriction.php CHANGED
@@ -18,7 +18,9 @@ class ICWP_WPSF_Processor_AdminAccessRestriction extends Modules\BaseShield\Shie
18
  add_filter( $this->getCon()->prefix( 'is_plugin_admin' ), [ $this, 'adjustUserAdminPermissions' ] );
19
 
20
  if ( $oOpts->isEnabledWhitelabel() ) {
21
- $this->getSubProWhitelabel()->execute();
 
 
22
  }
23
  }
24
 
@@ -74,22 +76,6 @@ class ICWP_WPSF_Processor_AdminAccessRestriction extends Modules\BaseShield\Shie
74
  }
75
  }
76
 
77
- /**
78
- * @return \ICWP_WPSF_Processor_AdminAccess_Whitelabel|mixed
79
- */
80
- protected function getSubProWhitelabel() {
81
- return $this->getSubPro( 'wl' );
82
- }
83
-
84
- /**
85
- * @return array
86
- */
87
- protected function getSubProMap() {
88
- return [
89
- 'wl' => 'ICWP_WPSF_Processor_AdminAccess_Whitelabel',
90
- ];
91
- }
92
-
93
  /**
94
  * Override the original collection to then add plugin statistics to the mix
95
  * @param $aData
18
  add_filter( $this->getCon()->prefix( 'is_plugin_admin' ), [ $this, 'adjustUserAdminPermissions' ] );
19
 
20
  if ( $oOpts->isEnabledWhitelabel() ) {
21
+ ( new SecurityAdmin\Lib\WhiteLabel\ApplyLabels() )
22
+ ->setMod( $this->getMod() )
23
+ ->run();
24
  }
25
  }
26
 
76
  }
77
  }
78
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  /**
80
  * Override the original collection to then add plugin statistics to the mix
81
  * @param $aData
src/processors/adminaccess_whitelabel.php CHANGED
@@ -3,15 +3,18 @@
3
  use FernleafSystems\Wordpress\Plugin\Shield\Modules;
4
  use FernleafSystems\Wordpress\Services\Services;
5
 
 
 
 
 
6
  class ICWP_WPSF_Processor_AdminAccess_Whitelabel extends Modules\BaseShield\ShieldProcessor {
7
 
8
  /**
9
  */
10
  public function run() {
11
- /** @var \ICWP_WPSF_FeatureHandler_AdminAccessRestriction $oMod */
12
- $oMod = $this->getMod();
13
- add_filter( $oMod->prefix( 'is_relabelled' ), '__return_true' );
14
- add_filter( $oMod->prefix( 'plugin_labels' ), [ $this, 'doRelabelPlugin' ] );
15
  add_filter( 'plugin_row_meta', [ $this, 'fRemoveDetailsMetaLink' ], 200, 2 );
16
  add_action( 'admin_print_footer_scripts-plugin-editor.php', [ $this, 'hideFromPluginEditor' ] );
17
  }
3
  use FernleafSystems\Wordpress\Plugin\Shield\Modules;
4
  use FernleafSystems\Wordpress\Services\Services;
5
 
6
+ /**
7
+ * Class ICWP_WPSF_Processor_AdminAccess_Whitelabel
8
+ * @deprecated 8.6.2
9
+ */
10
  class ICWP_WPSF_Processor_AdminAccess_Whitelabel extends Modules\BaseShield\ShieldProcessor {
11
 
12
  /**
13
  */
14
  public function run() {
15
+ $oCon = $this->getCon();
16
+ add_filter( $oCon->prefix( 'is_relabelled' ), '__return_true' );
17
+ add_filter( $oCon->prefix( 'plugin_labels' ), [ $this, 'doRelabelPlugin' ] );
 
18
  add_filter( 'plugin_row_meta', [ $this, 'fRemoveDetailsMetaLink' ], 200, 2 );
19
  add_action( 'admin_print_footer_scripts-plugin-editor.php', [ $this, 'hideFromPluginEditor' ] );
20
  }
src/processors/autoupdates.php CHANGED
@@ -5,30 +5,11 @@ use FernleafSystems\Wordpress\Services\Services;
5
 
6
  class ICWP_WPSF_Processor_Autoupdates extends Modules\BaseShield\ShieldProcessor {
7
 
8
- /**
9
- * @var bool
10
- */
11
- protected $bDoForceRunAutoupdates = false;
12
-
13
  /**
14
  * @var array
15
  */
16
  private $aAssetsVersions = [];
17
 
18
- /**
19
- * @param bool $bDoForceRun
20
- */
21
- public function setForceRunAutoupdates( $bDoForceRun ) {
22
- $this->bDoForceRunAutoupdates = $bDoForceRun;
23
- }
24
-
25
- /**
26
- * @return bool
27
- */
28
- public function getIfForceRunAutoupdates() {
29
- return apply_filters( $this->getMod()->prefix( 'force_autoupdate' ), $this->bDoForceRunAutoupdates );
30
- }
31
-
32
  /**
33
  * The allow_* core filters are run first in a "should_update" query. Then comes the "auto_update_core"
34
  * filter. What this filter decides will ultimately determine the fate of any core upgrade.
@@ -47,15 +28,10 @@ class ICWP_WPSF_Processor_Autoupdates extends Modules\BaseShield\ShieldProcessor
47
  add_filter( 'allow_major_auto_core_updates', [ $this, 'autoupdate_core_major' ], $nPriority );
48
  }
49
 
50
- add_filter( 'auto_update_translation', [ $this, 'autoupdate_translations' ], $nPriority, 1 );
51
  add_filter( 'auto_update_plugin', [ $this, 'autoupdate_plugins' ], $nPriority, 2 );
52
  add_filter( 'auto_update_theme', [ $this, 'autoupdate_themes' ], $nPriority, 2 );
53
  add_filter( 'auto_update_core', [ $this, 'autoupdate_core' ], $nPriority, 2 );
54
 
55
- if ( $oOpts->isOpt( 'enable_autoupdate_ignore_vcs', 'Y' ) ) {
56
- add_filter( 'automatic_updates_is_vcs_checkout', '__return_false', $nPriority );
57
- }
58
-
59
  if ( !$oOpts->isDisableAllAutoUpdates() ) {
60
  //more parameter options here for later
61
  add_filter( 'auto_core_update_send_email', [ $this, 'autoupdate_send_email' ], $nPriority, 1 );
@@ -83,9 +59,6 @@ class ICWP_WPSF_Processor_Autoupdates extends Modules\BaseShield\ShieldProcessor
83
  if ( $oOpts->isDisableAllAutoUpdates() ) {
84
  $this->disableAllAutoUpdates();
85
  }
86
- else {
87
- $this->forceRunAutoUpdates();
88
- }
89
  }
90
 
91
  private function disableAllAutoUpdates() {
@@ -193,15 +166,6 @@ class ICWP_WPSF_Processor_Autoupdates extends Modules\BaseShield\ShieldProcessor
193
  }
194
  }
195
 
196
- /**
197
- * Will force-run the WordPress automatic updates process and then redirect to the updates screen.
198
- */
199
- private function forceRunAutoUpdates() {
200
- if ( $this->getIfForceRunAutoupdates() ) {
201
- Services::WpGeneral()->doForceRunAutomaticUpdates();
202
- }
203
- }
204
-
205
  /**
206
  * This is a filter method designed to say whether a major core WordPress upgrade should be permitted,
207
  * based on the plugin settings.
@@ -241,16 +205,6 @@ class ICWP_WPSF_Processor_Autoupdates extends Modules\BaseShield\ShieldProcessor
241
  return $bUpdate;
242
  }
243
 
244
- /**
245
- * This is a filter method designed to say whether a WordPress translations upgrades should be permitted,
246
- * based on the plugin settings.
247
- * @param bool $bUpdate
248
- * @return bool
249
- */
250
- public function autoupdate_translations( $bUpdate ) {
251
- return $this->getOptions()->isOpt( 'enable_autoupdate_translations', 'Y' );
252
- }
253
-
254
  /**
255
  * @param bool $bDoAutoUpdate
256
  * @param \stdClass $oCoreUpdate
@@ -399,7 +353,7 @@ class ICWP_WPSF_Processor_Autoupdates extends Modules\BaseShield\ShieldProcessor
399
  * @return array
400
  */
401
  public function autoupdate_email_override( $aEmailParams ) {
402
- $sOverride = $this->getOption( 'override_email_address', '' );
403
  if ( Services::Data()->validEmail( $sOverride ) ) {
404
  $aEmailParams[ 'to' ] = $sOverride;
405
  }
@@ -470,7 +424,7 @@ class ICWP_WPSF_Processor_Autoupdates extends Modules\BaseShield\ShieldProcessor
470
  // Are there really updates?
471
  $bReallyUpdates = false;
472
 
473
- $aEmailContent = [
474
  sprintf(
475
  __( 'This is a quick notification from the %s that WordPress Automatic Updates just completed on your site with the following results.', 'wp-simple-firewall' ),
476
  $this->getCon()->getHumanName()
@@ -501,7 +455,7 @@ class ICWP_WPSF_Processor_Autoupdates extends Modules\BaseShield\ShieldProcessor
501
 
502
  if ( $bHasPluginUpdates ) {
503
  $bReallyUpdates = true;
504
- $aEmailContent = array_merge( $aEmailContent, $aTempContent );
505
  }
506
  }
507
 
@@ -526,7 +480,7 @@ class ICWP_WPSF_Processor_Autoupdates extends Modules\BaseShield\ShieldProcessor
526
 
527
  if ( $bHasThemesUpdates ) {
528
  $bReallyUpdates = true;
529
- $aEmailContent = array_merge( $aEmailContent, $aTempContent );
530
  }
531
  }
532
 
@@ -543,7 +497,7 @@ class ICWP_WPSF_Processor_Autoupdates extends Modules\BaseShield\ShieldProcessor
543
 
544
  if ( $bHasCoreUpdates ) {
545
  $bReallyUpdates = true;
546
- $aEmailContent = array_merge( $aEmailContent, $aTempContent );
547
  }
548
  }
549
 
@@ -551,11 +505,11 @@ class ICWP_WPSF_Processor_Autoupdates extends Modules\BaseShield\ShieldProcessor
551
  return;
552
  }
553
 
554
- $aEmailContent[] = __( 'Thank you.', 'wp-simple-firewall' );
555
 
556
  $sTitle = sprintf( __( "Notice: %s", 'wp-simple-firewall' ), __( "Automatic Updates Completed", 'wp-simple-firewall' ) );
557
  $this->getEmailProcessor()
558
- ->sendEmailWithWrap( $this->getOption( 'override_email_address' ), $sTitle, $aEmailContent );
559
  die();
560
  }
561
 
@@ -604,4 +558,21 @@ class ICWP_WPSF_Processor_Autoupdates extends Modules\BaseShield\ShieldProcessor
604
  protected function getHookPriority() {
605
  return $this->getOptions()->getDef( 'action_hook_priority' );
606
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
607
  }
5
 
6
  class ICWP_WPSF_Processor_Autoupdates extends Modules\BaseShield\ShieldProcessor {
7
 
 
 
 
 
 
8
  /**
9
  * @var array
10
  */
11
  private $aAssetsVersions = [];
12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  /**
14
  * The allow_* core filters are run first in a "should_update" query. Then comes the "auto_update_core"
15
  * filter. What this filter decides will ultimately determine the fate of any core upgrade.
28
  add_filter( 'allow_major_auto_core_updates', [ $this, 'autoupdate_core_major' ], $nPriority );
29
  }
30
 
 
31
  add_filter( 'auto_update_plugin', [ $this, 'autoupdate_plugins' ], $nPriority, 2 );
32
  add_filter( 'auto_update_theme', [ $this, 'autoupdate_themes' ], $nPriority, 2 );
33
  add_filter( 'auto_update_core', [ $this, 'autoupdate_core' ], $nPriority, 2 );
34
 
 
 
 
 
35
  if ( !$oOpts->isDisableAllAutoUpdates() ) {
36
  //more parameter options here for later
37
  add_filter( 'auto_core_update_send_email', [ $this, 'autoupdate_send_email' ], $nPriority, 1 );
59
  if ( $oOpts->isDisableAllAutoUpdates() ) {
60
  $this->disableAllAutoUpdates();
61
  }
 
 
 
62
  }
63
 
64
  private function disableAllAutoUpdates() {
166
  }
167
  }
168
 
 
 
 
 
 
 
 
 
 
169
  /**
170
  * This is a filter method designed to say whether a major core WordPress upgrade should be permitted,
171
  * based on the plugin settings.
205
  return $bUpdate;
206
  }
207
 
 
 
 
 
 
 
 
 
 
 
208
  /**
209
  * @param bool $bDoAutoUpdate
210
  * @param \stdClass $oCoreUpdate
353
  * @return array
354
  */
355
  public function autoupdate_email_override( $aEmailParams ) {
356
+ $sOverride = $this->getOptions()->getOpt( 'override_email_address', '' );
357
  if ( Services::Data()->validEmail( $sOverride ) ) {
358
  $aEmailParams[ 'to' ] = $sOverride;
359
  }
424
  // Are there really updates?
425
  $bReallyUpdates = false;
426
 
427
+ $aBody = [
428
  sprintf(
429
  __( 'This is a quick notification from the %s that WordPress Automatic Updates just completed on your site with the following results.', 'wp-simple-firewall' ),
430
  $this->getCon()->getHumanName()
455
 
456
  if ( $bHasPluginUpdates ) {
457
  $bReallyUpdates = true;
458
+ $aBody = array_merge( $aBody, $aTempContent );
459
  }
460
  }
461
 
480
 
481
  if ( $bHasThemesUpdates ) {
482
  $bReallyUpdates = true;
483
+ $aBody = array_merge( $aBody, $aTempContent );
484
  }
485
  }
486
 
497
 
498
  if ( $bHasCoreUpdates ) {
499
  $bReallyUpdates = true;
500
+ $aBody = array_merge( $aBody, $aTempContent );
501
  }
502
  }
503
 
505
  return;
506
  }
507
 
508
+ $aBody[] = __( 'Thank you.', 'wp-simple-firewall' );
509
 
510
  $sTitle = sprintf( __( "Notice: %s", 'wp-simple-firewall' ), __( "Automatic Updates Completed", 'wp-simple-firewall' ) );
511
  $this->getEmailProcessor()
512
+ ->sendEmailWithWrap( $this->getOptions()->getOpt( 'override_email_address' ), $sTitle, $aBody );
513
  die();
514
  }
515
 
558
  protected function getHookPriority() {
559
  return $this->getOptions()->getDef( 'action_hook_priority' );
560
  }
561
+
562
+ /**
563
+ * This is a filter method designed to say whether a WordPress translations upgrades should be permitted,
564
+ * based on the plugin settings.
565
+ * @param bool $bUpdate
566
+ * @return bool
567
+ * @deprecated 8.6.2
568
+ */
569
+ public function autoupdate_translations( $bUpdate ) {
570
+ return $bUpdate;
571
+ }
572
+
573
+ /**
574
+ * @deprecated 8.6.2
575
+ */
576
+ private function forceRunAutoUpdates() {
577
+ }
578
  }
src/processors/comments_filter.php CHANGED
@@ -26,7 +26,7 @@ class ICWP_WPSF_Processor_CommentsFilter extends Modules\BaseShield\ShieldProces
26
  if ( $bLoadComProc ) {
27
 
28
  if ( $oMod->isGoogleRecaptchaEnabled() ) {
29
- $this->getSubProRecaptcha()->execute();
30
  }
31
 
32
  if ( Services::Request()->isPost() ) {
@@ -36,7 +36,7 @@ class ICWP_WPSF_Processor_CommentsFilter extends Modules\BaseShield\ShieldProces
36
  add_filter( 'comment_notification_recipients', [ $this, 'clearCommentNotificationEmail' ], 100, 1 );
37
  }
38
  elseif ( $oMod->isEnabledGaspCheck() ) {
39
- $this->getSubProGasp()->execute();
40
  }
41
  }
42
  }
@@ -59,20 +59,6 @@ class ICWP_WPSF_Processor_CommentsFilter extends Modules\BaseShield\ShieldProces
59
  ];
60
  }
61
 
62
- /**
63
- * @return \ICWP_WPSF_Processor_CommentsFilter_BotSpam
64
- */
65
- private function getSubProGasp() {
66
- return $this->getSubPro( 'bot' );
67
- }
68
-
69
- /**
70
- * @return \ICWP_WPSF_Processor_CommentsFilter_GoogleRecaptcha
71
- */
72
- private function getSubProRecaptcha() {
73
- return $this->getSubPro( 'recaptcha' );
74
- }
75
-
76
  /**
77
  * When you set a new comment as anything but 'spam' a notification email is sent to the post author.
78
  * We suppress this for when we mark as trash by emptying the email notifications list.
26
  if ( $bLoadComProc ) {
27
 
28
  if ( $oMod->isGoogleRecaptchaEnabled() ) {
29
+ $this->getSubPro( 'recaptcha' )->execute();
30
  }
31
 
32
  if ( Services::Request()->isPost() ) {
36
  add_filter( 'comment_notification_recipients', [ $this, 'clearCommentNotificationEmail' ], 100, 1 );
37
  }
38
  elseif ( $oMod->isEnabledGaspCheck() ) {
39
+ $this->getSubPro( 'bot' )->execute();
40
  }
41
  }
42
  }
59
  ];
60
  }
61
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  /**
63
  * When you set a new comment as anything but 'spam' a notification email is sent to the post author.
64
  * We suppress this for when we mark as trash by emptying the email notifications list.
src/processors/commentsfilter_botspam.php CHANGED
@@ -1,6 +1,7 @@
1
  <?php
2
 
3
  use FernleafSystems\Wordpress\Plugin\Shield\Modules;
 
4
  use FernleafSystems\Wordpress\Services\Services;
5
 
6
  class ICWP_WPSF_Processor_CommentsFilter_BotSpam extends Modules\BaseShield\ShieldProcessor {
@@ -28,10 +29,12 @@ class ICWP_WPSF_Processor_CommentsFilter_BotSpam extends Modules\BaseShield\Shie
28
  public function onWpEnqueueJs() {
29
  /** @var \ICWP_WPSF_FeatureHandler_CommentsFilter $oMod */
30
  $oMod = $this->getMod();
 
 
31
  $oConn = $this->getCon();
32
 
33
  $sAsset = 'shield-comments';
34
- $sUnique = $oMod->prefix( 'shield-comments' );
35
  wp_register_script(
36
  $sUnique,
37
  $oConn->getPluginUrl_Js( $sAsset ),
@@ -58,8 +61,8 @@ class ICWP_WPSF_Processor_CommentsFilter_BotSpam extends Modules\BaseShield\Shie
58
  'botts' => $nTs,
59
  'token' => 'not created',
60
  'uniq' => $this->getUniqueFormId(),
61
- 'cooldown' => $oMod->getTokenCooldown(),
62
- 'expires' => $oMod->getTokenExpireInterval(),
63
  ],
64
  'strings' => [
65
  'label' => $oMod->getTextOpt( 'custom_message_checkbox' ),
1
  <?php
2
 
3
  use FernleafSystems\Wordpress\Plugin\Shield\Modules;
4
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter\Options;
5
  use FernleafSystems\Wordpress\Services\Services;
6
 
7
  class ICWP_WPSF_Processor_CommentsFilter_BotSpam extends Modules\BaseShield\ShieldProcessor {
29
  public function onWpEnqueueJs() {
30
  /** @var \ICWP_WPSF_FeatureHandler_CommentsFilter $oMod */
31
  $oMod = $this->getMod();
32
+ /** @var Options $oOpts */
33
+ $oOpts = $this->getOptions();
34
  $oConn = $this->getCon();
35
 
36
  $sAsset = 'shield-comments';
37
+ $sUnique = $oConn->prefix( 'shield-comments' );
38
  wp_register_script(
39
  $sUnique,
40
  $oConn->getPluginUrl_Js( $sAsset ),
61
  'botts' => $nTs,
62
  'token' => 'not created',
63
  'uniq' => $this->getUniqueFormId(),
64
+ 'cooldown' => $oOpts->getTokenCooldown(),
65
+ 'expires' => $oOpts->getTokenExpireInterval(),
66
  ],
67
  'strings' => [
68
  'label' => $oMod->getTextOpt( 'custom_message_checkbox' ),
src/processors/email.php CHANGED
@@ -9,42 +9,40 @@ class ICWP_WPSF_Processor_Email extends Modules\BaseShield\ShieldProcessor {
9
 
10
  /**
11
  * @var string
 
12
  */
13
  protected static $sModeFile_EmailThrottled;
14
 
15
  /**
16
  * @var int
 
17
  */
18
  protected static $nThrottleInterval = 1;
19
 
20
  /**
21
  * @var int
 
22
  */
23
  protected $nEmailThrottleLimit;
24
 
25
  /**
26
  * @var int
 
27
  */
28
  protected $nEmailThrottleTime;
29
 
30
  /**
31
  * @var int
 
32
  */
33
  protected $nEmailThrottleCount;
34
 
35
  /**
36
  * @var bool
 
37
  */
38
  protected $bEmailIsThrottled;
39
 
40
- public function init() {
41
- parent::init();
42
- self::$sModeFile_EmailThrottled = path_join( __DIR__, '/../mode.email_throttled' );
43
- }
44
-
45
- public function run() {
46
- }
47
-
48
  /**
49
  * @return array
50
  */
@@ -97,10 +95,6 @@ class ICWP_WPSF_Processor_Email extends Modules\BaseShield\ShieldProcessor {
97
  * @uses wp_mail
98
  */
99
  public function send( $sAddress = '', $sSubject = '', $sMessageBody = '' ) {
100
- $this->updateEmailThrottle();
101
- if ( $this->bEmailIsThrottled ) {
102
- return true;
103
- }
104
 
105
  $this->emailFilters( true );
106
  $bSuccess = wp_mail(
@@ -193,59 +187,17 @@ class ICWP_WPSF_Processor_Email extends Modules\BaseShield\ShieldProcessor {
193
  * system object telling us we're throttled.
194
  * The file system object takes precedence.
195
  * @return bool
 
196
  */
197
  protected function updateEmailThrottle() {
198
- $nNow = Services::Request()->ts();
199
-
200
- // Throttling Is Effectively Off
201
- if ( $this->getThrottleLimit() <= 0 ) {
202
- $this->setThrottledFile( false );
203
- return $this->bEmailIsThrottled;
204
- }
205
-
206
- // Check that there is an email throttle file. If it exists and its modified time is greater than the
207
- // current $this->m_nEmailThrottleTime it suggests another process has touched the file and updated it
208
- // concurrently. So, we update our $this->m_nEmailThrottleTime accordingly.
209
- if ( is_file( self::$sModeFile_EmailThrottled ) ) {
210
- $nModifiedTime = filemtime( self::$sModeFile_EmailThrottled );
211
- if ( $nModifiedTime > $this->nEmailThrottleTime ) {
212
- $this->nEmailThrottleTime = $nModifiedTime;
213
- }
214
- }
215
-
216
- if ( !isset( $this->nEmailThrottleTime ) || $this->nEmailThrottleTime > $nNow ) {
217
- $this->nEmailThrottleTime = $nNow;
218
- }
219
- if ( !isset( $this->nEmailThrottleCount ) ) {
220
- $this->nEmailThrottleCount = 0;
221
- }
222
-
223
- // If $nNow is greater than throttle interval (1s) we turn off the file throttle and reset the count
224
- $nDiff = $nNow - $this->nEmailThrottleTime;
225
- if ( $nDiff > self::$nThrottleInterval ) {
226
- $this->nEmailThrottleTime = $nNow;
227
- $this->nEmailThrottleCount = 1; //we set to 1 assuming that this was called because we're about to send, or have just sent, an email.
228
- $this->setThrottledFile( false );
229
- }
230
- elseif ( is_file( self::$sModeFile_EmailThrottled ) || ( $this->nEmailThrottleCount >= $this->getThrottleLimit() ) ) {
231
- $this->setThrottledFile( true );
232
- }
233
- else {
234
- $this->nEmailThrottleCount++;
235
- }
236
  return true;
237
  }
238
 
 
 
 
 
239
  public function setThrottledFile( $infOn = false ) {
240
-
241
- $this->bEmailIsThrottled = $infOn;
242
-
243
- if ( $infOn && !is_file( self::$sModeFile_EmailThrottled ) && function_exists( 'touch' ) ) {
244
- @touch( self::$sModeFile_EmailThrottled );
245
- }
246
- elseif ( !$infOn && is_file( self::$sModeFile_EmailThrottled ) ) {
247
- @unlink( self::$sModeFile_EmailThrottled );
248
- }
249
  }
250
 
251
  /**
@@ -256,10 +208,11 @@ class ICWP_WPSF_Processor_Email extends Modules\BaseShield\ShieldProcessor {
256
  return Services::Data()->validEmail( $sEmail ) ? $sEmail : Services::WpGeneral()->getSiteAdminEmail();
257
  }
258
 
 
 
 
 
259
  public function getThrottleLimit() {
260
- if ( empty( $this->nEmailThrottleLimit ) ) {
261
- $this->nEmailThrottleLimit = $this->getOption( 'send_email_throttle_limit' );
262
- }
263
- return $this->nEmailThrottleLimit;
264
  }
265
  }
9
 
10
  /**
11
  * @var string
12
+ * @deprecated 8.6.2
13
  */
14
  protected static $sModeFile_EmailThrottled;
15
 
16
  /**
17
  * @var int
18
+ * @deprecated 8.6.2
19
  */
20
  protected static $nThrottleInterval = 1;
21
 
22
  /**
23
  * @var int
24
+ * @deprecated 8.6.2
25
  */
26
  protected $nEmailThrottleLimit;
27
 
28
  /**
29
  * @var int
30
+ * @deprecated 8.6.2
31
  */
32
  protected $nEmailThrottleTime;
33
 
34
  /**
35
  * @var int
36
+ * @deprecated 8.6.2
37
  */
38
  protected $nEmailThrottleCount;
39
 
40
  /**
41
  * @var bool
42
+ * @deprecated 8.6.2
43
  */
44
  protected $bEmailIsThrottled;
45
 
 
 
 
 
 
 
 
 
46
  /**
47
  * @return array
48
  */
95
  * @uses wp_mail
96
  */
97
  public function send( $sAddress = '', $sSubject = '', $sMessageBody = '' ) {
 
 
 
 
98
 
99
  $this->emailFilters( true );
100
  $bSuccess = wp_mail(
187
  * system object telling us we're throttled.
188
  * The file system object takes precedence.
189
  * @return bool
190
+ * @deprecated 8.6.2
191
  */
192
  protected function updateEmailThrottle() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  return true;
194
  }
195
 
196
+ /**
197
+ * @param bool $infOn
198
+ * @deprecated 8.6.2
199
+ */
200
  public function setThrottledFile( $infOn = false ) {
 
 
 
 
 
 
 
 
 
201
  }
202
 
203
  /**
208
  return Services::Data()->validEmail( $sEmail ) ? $sEmail : Services::WpGeneral()->getSiteAdminEmail();
209
  }
210
 
211
+
212
+ /**
213
+ * @deprecated 8.6.2
214
+ */
215
  public function getThrottleLimit() {
216
+ return 0;
 
 
 
217
  }
218
  }
src/processors/events.php CHANGED
@@ -29,8 +29,6 @@ class ICWP_WPSF_Processor_Events extends Shield\Modules\BaseShield\ShieldProcess
29
  return $this->oStatsWriter;
30
  }
31
 
32
- /**
33
- */
34
  public function statsWidget() {
35
  /** @var Databases\Events\Select $oSelEvents */
36
  $oSelEvents = $this->getCon()
@@ -100,12 +98,6 @@ class ICWP_WPSF_Processor_Events extends Shield\Modules\BaseShield\ShieldProcess
100
  return $aData;
101
  }
102
 
103
- /**
104
- * @deprecated 8.5
105
- */
106
- private function commitEvents() {
107
- }
108
-
109
  public function runDailyCron() {
110
  ( new Events\Consolidate\ConsolidateAllEvents() )
111
  ->setMod( $this->getMod() )
29
  return $this->oStatsWriter;
30
  }
31
 
 
 
32
  public function statsWidget() {
33
  /** @var Databases\Events\Select $oSelEvents */
34
  $oSelEvents = $this->getCon()
98
  return $aData;
99
  }
100
 
 
 
 
 
 
 
101
  public function runDailyCron() {
102
  ( new Events\Consolidate\ConsolidateAllEvents() )
103
  ->setMod( $this->getMod() )
src/processors/hackprotect_integrity.php CHANGED
@@ -24,7 +24,8 @@ class ICWP_WPSF_Processor_HackProtect_Integrity extends ShieldProcessor {
24
  * @return array[] - associative arrays where keys are $this->getStandardUserFields()
25
  */
26
  public function getSnapshotUsers() {
27
- return is_array( $this->getOption( 'snapshot_users' ) ) ? $this->getOption( 'snapshot_users' ) : [];
 
28
  }
29
 
30
  /**
24
  * @return array[] - associative arrays where keys are $this->getStandardUserFields()
25
  */
26
  public function getSnapshotUsers() {
27
+ $aUs = $this->getOptions()->getOpt( 'snapshot_users' );
28
+ return is_array( $aUs ) ? $aUs : [];
29
  }
30
 
31
  /**
src/processors/hackprotect_scan_assets_base.php DELETED
@@ -1,29 +0,0 @@
1
- <?php
2
-
3
- use FernleafSystems\Wordpress\Plugin\Shield;
4
- use FernleafSystems\Wordpress\Services;
5
-
6
- /**
7
- * Class ICWP_WPSF_Processor_HackProtect_ScanAssetsBase
8
- * @deprecated 8.5
9
- */
10
- abstract class ICWP_WPSF_Processor_HackProtect_ScanAssetsBase extends ICWP_WPSF_Processor_ScanBase {
11
-
12
- const CONTEXT_PLUGINS = 'plugins';
13
- const CONTEXT_THEMES = 'themes';
14
-
15
- /**
16
- * @param string $sSlug
17
- * @return Services\Core\VOs\WpPluginVo|Services\Core\VOs\WpThemeVo|null
18
- * @deprecated 8.5
19
- */
20
- protected function getAssetFromSlug( $sSlug ) {
21
- if ( Services\Services::WpPlugins()->isInstalled( $sSlug ) ) {
22
- $oAsset = Services\Services::WpPlugins()->getPluginAsVo( $sSlug );
23
- }
24
- elseif ( Services\Services::WpThemes()->isInstalled( $sSlug ) ) {
25
- $oAsset = Services\Services::WpThemes()->getThemeAsVo( $sSlug );
26
- }
27
- return $oAsset;
28
- }
29
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/processors/hackprotect_scan_base.php CHANGED
@@ -89,61 +89,4 @@ abstract class ICWP_WPSF_Processor_ScanBase extends Shield\Modules\BaseShield\Sh
89
  $oMod = $this->getMod();
90
  return $oMod->getScanCon( static::SCAN_SLUG );
91
  }
92
-
93
- /**
94
- * @param \ICWP_WPSF_Processor_HackProtect_Scanner $oScanner
95
- * @return $this
96
- * @deprecated 8.5
97
- */
98
- public function setScannerDb( $oScanner ) {
99
- return $this;
100
- }
101
-
102
- /**
103
- * @return bool
104
- * @deprecated 8.5
105
- */
106
- public function isRestricted() {
107
- return false;
108
- }
109
-
110
- /**
111
- * @return bool
112
- * @deprecated 8.5
113
- */
114
- public function isAvailable() {
115
- return $this->getThisScanCon()->isScanningAvailable();
116
- }
117
-
118
- /**
119
- * @return bool
120
- * @deprecated 8.5
121
- */
122
- protected function isCronAutoRepair() {
123
- return $this->getThisScanCon()->isCronAutoRepair();
124
- }
125
-
126
- /**
127
- * @return bool
128
- * @deprecated 8.5
129
- */
130
- public function isEnabled() {
131
- return $this->getThisScanCon()->isEnabled();
132
- }
133
-
134
- /**
135
- * Override this to provide the correct VO
136
- * @return Shield\Scans\Base\BaseScanActionVO|mixed
137
- * @deprecated 8.5
138
- */
139
- protected function getNewActionVO() {
140
- return $this->getThisScanCon()->getScanActionVO();
141
- }
142
-
143
- /**
144
- * @param Shield\Scans\Base\BaseResultsSet $oRes
145
- * @deprecated 8.5
146
- */
147
- protected function runCronAutoRepair( $oRes ) {
148
- }
149
  }
89
  $oMod = $this->getMod();
90
  return $oMod->getScanCon( static::SCAN_SLUG );
91
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  }
src/processors/hackprotect_scan_ptg.php CHANGED
@@ -183,121 +183,4 @@ class ICWP_WPSF_Processor_HackProtect_Ptg extends ICWP_WPSF_Processor_ScanBase {
183
  ]
184
  );
185
  }
186
-
187
- /**
188
- * @param string $sBaseName
189
- * @deprecated 8.5
190
- */
191
- public function onActivatePlugin( $sBaseName ) {
192
- }
193
-
194
- /**
195
- * @deprecated 8.5
196
- */
197
- public function onActivateTheme() {
198
- }
199
-
200
- /**
201
- * @param string $sBaseName
202
- * @deprecated 8.5
203
- */
204
- public function onDeactivatePlugin( $sBaseName ) {
205
- }
206
-
207
- /**
208
- * Only snaps active.
209
- *
210
- * @param string $sSlug - the basename for plugin, or stylesheet for theme.
211
- * @param string $sContext
212
- * @return $this
213
- * @deprecated 8.5
214
- */
215
- public function updateItemInSnapshot( $sSlug, $sContext = null ) {
216
- return $this;
217
- }
218
-
219
- /**
220
- * @param string $sSlug
221
- * @deprecated 8.5
222
- */
223
- public function updateThemeSnapshot( $sSlug ) {
224
- }
225
-
226
- /**
227
- * @return bool
228
- * @deprecated 8.5
229
- */
230
- private function snapshotThemes() {
231
- return true;
232
- }
233
-
234
- /**
235
- * Will also remove a plugin if it's found to be in-active
236
- * Careful: Cannot use this for the activate and deactivate hooks as the WP option
237
- * wont be updated
238
- *
239
- * @param string $sBaseName
240
- * @deprecated 8.5
241
- */
242
- public function updatePluginSnapshot( $sBaseName ) {
243
- }
244
-
245
- /**
246
- * @param string $sSlug
247
- * @return $this
248
- * @deprecated 8.5
249
- */
250
- protected function removeItemSnapshot( $sSlug ) {
251
- return $this;
252
- }
253
-
254
- /**
255
- * @param WP_Upgrader $oUpgrader
256
- * @param array $aInfo Upgrade/Install Information
257
- * @deprecated 8.5
258
- */
259
- public function updateSnapshotAfterUpgrade( $oUpgrader, $aInfo ) {
260
- }
261
-
262
- /**
263
- * @return $this
264
- * @deprecated 8.5
265
- */
266
- private function snapshotPlugins() {
267
- return $this;
268
- }
269
-
270
- /**
271
- * @param string $sBaseFile
272
- * @return array
273
- * @deprecated 8.5
274
- */
275
- private function buildSnapshotPlugin( $sBaseFile ) {
276
- return [];
277
- }
278
-
279
- /**
280
- * @param string $sSlug
281
- * @return array
282
- * @deprecated 8.5
283
- */
284
- private function buildSnapshotTheme( $sSlug ) {
285
- return [];
286
- }
287
-
288
- /**
289
- * @return null
290
- * @deprecated 8.5
291
- */
292
- private function getStore_Plugins() {
293
- return null;
294
- }
295
-
296
- /**
297
- * @return null
298
- * @deprecated 8.5
299
- */
300
- private function getStore_Themes() {
301
- return null;
302
- }
303
  }
183
  ]
184
  );
185
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
  }
src/processors/hackprotect_scan_ufc.php CHANGED
@@ -12,9 +12,9 @@ class ICWP_WPSF_Processor_HackProtect_Ufc extends ICWP_WPSF_Processor_ScanBase {
12
  * @return bool - true if user notified
13
  */
14
  protected function runCronUserNotify( $oRes ) {
15
- /** @var \ICWP_WPSF_FeatureHandler_HackProtect $oFO */
16
- $oFO = $this->getMod();
17
- $bSend = $oFO->isUfcSendReport();
18
  if ( $bSend ) {
19
  $this->emailResults( $oRes );
20
  }
12
  * @return bool - true if user notified
13
  */
14
  protected function runCronUserNotify( $oRes ) {
15
+ /** @var Shield\Modules\HackGuard\Options $oOpts */
16
+ $oOpts = $this->getOptions();
17
+ $bSend = $oOpts->isUfcSendReport();
18
  if ( $bSend ) {
19
  $this->emailResults( $oRes );
20
  }
src/processors/hackprotect_scan_wcf.php CHANGED
@@ -50,6 +50,8 @@ class ICWP_WPSF_Processor_HackProtect_Wcf extends ICWP_WPSF_Processor_ScanBase {
50
  private function buildEmailBodyFromFiles( $oResults ) {
51
  /** @var \ICWP_WPSF_FeatureHandler_HackProtect $oMod */
52
  $oMod = $this->getMod();
 
 
53
  $sName = $this->getCon()->getHumanName();
54
  $sHomeUrl = Services::WpGeneral()->getHomeUrl();
55
 
@@ -58,11 +60,11 @@ class ICWP_WPSF_Processor_HackProtect_Wcf extends ICWP_WPSF_Processor_ScanBase {
58
  sprintf( '%s: %s', __( 'Site URL', 'wp-simple-firewall' ), sprintf( '<a href="%s" target="_blank">%s</a>', $sHomeUrl, $sHomeUrl ) ),
59
  ];
60
 
61
- if ( $oMod->isWcfScanAutoRepair() || $oMod->isIncludeFileLists() ) {
62
  $aContent = array_merge( $aContent, $this->buildListOfFilesForEmail( $oResults ) );
63
  $aContent[] = '';
64
 
65
- if ( $oMod->isWcfScanAutoRepair() ) {
66
  $aContent[] = '<strong>'.sprintf( __( "%s has already attempted to repair the files.", 'wp-simple-firewall' ), $sName ).'</strong>'
67
  .' '.__( 'But, you should always check these files to ensure everything is as you expect.', 'wp-simple-firewall' );
68
  }
50
  private function buildEmailBodyFromFiles( $oResults ) {
51
  /** @var \ICWP_WPSF_FeatureHandler_HackProtect $oMod */
52
  $oMod = $this->getMod();
53
+ /** @var Shield\Modules\HackGuard\Options $oOpts */
54
+ $oOpts = $this->getOptions();
55
  $sName = $this->getCon()->getHumanName();
56
  $sHomeUrl = Services::WpGeneral()->getHomeUrl();
57
 
60
  sprintf( '%s: %s', __( 'Site URL', 'wp-simple-firewall' ), sprintf( '<a href="%s" target="_blank">%s</a>', $sHomeUrl, $sHomeUrl ) ),
61
  ];
62
 
63
+ if ( $oOpts->isWcfScanAutoRepair() || $oMod->isIncludeFileLists() ) {
64
  $aContent = array_merge( $aContent, $this->buildListOfFilesForEmail( $oResults ) );
65
  $aContent[] = '';
66
 
67
+ if ( $oOpts->isWcfScanAutoRepair() ) {
68
  $aContent[] = '<strong>'.sprintf( __( "%s has already attempted to repair the files.", 'wp-simple-firewall' ), $sName ).'</strong>'
69
  .' '.__( 'But, you should always check these files to ensure everything is as you expect.', 'wp-simple-firewall' );
70
  }
src/processors/hackprotect_scanner.php CHANGED
@@ -160,13 +160,4 @@ class ICWP_WPSF_Processor_HackProtect_Scanner extends ShieldProcessor {
160
  protected function getCronName() {
161
  return $this->getCon()->prefix( $this->getOptions()->getDef( 'cron_all_scans' ) );
162
  }
163
-
164
- /**
165
- * @param string $sSlug
166
- * @return \ICWP_WPSF_Processor_ScanBase|null
167
- * @deprecated 8.5
168
- */
169
- public function getScannerFromSlug( $sSlug ) {
170
- return $this->getSubPro( $sSlug );
171
- }
172
  }
160
  protected function getCronName() {
161
  return $this->getCon()->prefix( $this->getOptions()->getDef( 'cron_all_scans' ) );
162
  }
 
 
 
 
 
 
 
 
 
163
  }
src/processors/headers.php CHANGED
@@ -97,7 +97,7 @@ class ICWP_WPSF_Processor_Headers extends Modules\BaseShield\ShieldProcessor {
97
  * @return array|null
98
  */
99
  private function getXFrameHeader() {
100
- switch ( $this->getOption( 'x_frame' ) ) {
101
  case 'on_sameorigin':
102
  $sXFrameOption = 'SAMEORIGIN';
103
  break;
97
  * @return array|null
98
  */
99
  private function getXFrameHeader() {
100
+ switch ( $this->getOptions()->getOpt( 'x_frame' ) ) {
101
  case 'on_sameorigin':
102
  $sXFrameOption = 'SAMEORIGIN';
103
  break;
src/processors/ips.php CHANGED
@@ -1,429 +1,21 @@
1
  <?php
2
 
3
  use FernleafSystems\Wordpress\Plugin\Shield;
4
- use FernleafSystems\Wordpress\Plugin\Shield\Databases;
5
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield\ShieldProcessor;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
7
- use FernleafSystems\Wordpress\Services\Services;
8
 
9
- class ICWP_WPSF_Processor_Ips extends ShieldProcessor {
10
 
11
  /**
12
  */
13
  public function run() {
14
-
15
- /** @var \ICWP_WPSF_FeatureHandler_Ips $oMod */
16
- $oMod = $this->getMod();
17
- /** @var IPs\Options $oOpts */
18
- $oOpts = $this->getOptions();
19
- if ( $oOpts->isEnabledAutoBlackList() ) {
20
-
21
- ( new IPs\Components\UnblockIpByFlag() )
22
- ->setMod( $oMod )
23
- ->run();
24
-
25
- if ( !$oMod->isVisitorWhitelisted() && !$this->isRequestWhitelisted() ) {
26
- $oMod->loadOffenseTracker()->setIfCommit( true );
27
-
28
- $this->processBlacklist();
29
- $oCon = $this->getCon();
30
- add_filter( $oCon->prefix( 'firewall_die_message' ), [ $this, 'fAugmentFirewallDieMessage' ] );
31
- add_action( $oCon->prefix( 'pre_plugin_shutdown' ), function () {
32
- $this->doBlackMarkCurrentVisitor();
33
- } );
34
- add_action( 'shield_security_offense', [ $this, 'processCustomShieldOffense' ], 10, 3 );
35
- }
36
- }
37
- }
38
-
39
- /**
40
- * @return bool
41
- */
42
- private function isRequestWhitelisted() {
43
- /** @var IPs\Options $oOpts */
44
- $oOpts = $this->getOptions();
45
- $bWhitelisted = false;
46
- $aWhitelist = $oOpts->getRequestWhitelistAsRegex();
47
- if ( !empty( $aWhitelist ) ) {
48
- $sPath = strtolower( '/'.ltrim( (string)Services::Request()->getPath(), '/' ) );
49
- foreach ( $aWhitelist as $sRule ) {
50
- if ( preg_match( $sRule, $sPath ) ) {
51
- $bWhitelisted = true;
52
- break;
53
- }
54
- }
55
- }
56
- return $bWhitelisted;
57
- }
58
-
59
- public function onWpInit() {
60
- /** @var \ICWP_WPSF_FeatureHandler_Ips $oMod */
61
- $oMod = $this->getMod();
62
- /** @var IPs\Options $oOpts */
63
- $oOpts = $oMod->getOptions();
64
-
65
- if ( $oOpts->isEnabledAutoBlackList() && !Services::WpUsers()->isUserLoggedIn() ) {
66
-
67
- if ( !$oMod->isVerifiedBot() ) {
68
- if ( $oOpts->isEnabledTrackXmlRpc() ) {
69
- ( new IPs\BotTrack\TrackXmlRpc() )
70
- ->setMod( $oMod )
71
- ->run();
72
- }
73
- if ( $oOpts->isEnabledTrack404() ) {
74
- ( new IPs\BotTrack\Track404() )
75
- ->setMod( $oMod )
76
- ->run();
77
- }
78
- if ( $oOpts->isEnabledTrackLoginFailed() ) {
79
- ( new IPs\BotTrack\TrackLoginFailed() )
80
- ->setMod( $oMod )
81
- ->run();
82
- }
83
- if ( $oOpts->isEnabledTrackLoginInvalid() ) {
84
- ( new IPs\BotTrack\TrackLoginInvalid() )
85
- ->setMod( $oMod )
86
- ->run();
87
- }
88
- if ( $oOpts->isEnabledTrackFakeWebCrawler() ) {
89
- ( new IPs\BotTrack\TrackFakeWebCrawler() )
90
- ->setMod( $oMod )
91
- ->run();
92
- }
93
- }
94
-
95
- /** Always run link cheese regardless of the verified bot or not */
96
- if ( $oOpts->isEnabledTrackLinkCheese() ) {
97
- ( new IPs\BotTrack\TrackLinkCheese() )
98
- ->setMod( $oMod )
99
- ->run();
100
- }
101
- }
102
- }
103
-
104
- /**
105
- * Allows 3rd parties to trigger Shield offenses
106
- * @param string $sMessage
107
- * @param int $nOffenseCount
108
- * @param bool $bIncludeLoggedIn
109
- */
110
- public function processCustomShieldOffense( $sMessage, $nOffenseCount = 1, $bIncludeLoggedIn = true ) {
111
- if ( $this->getCon()->isPremiumActive() ) {
112
- if ( empty( $sMessage ) ) {
113
- $sMessage = __( 'No custom message provided.', 'wp-simple-firewall' );
114
- }
115
-
116
- if ( $bIncludeLoggedIn || !did_action( 'init' ) || !Services::WpUsers()->isUserLoggedIn() ) {
117
- $this->getCon()
118
- ->fireEvent(
119
- 'custom_offense',
120
- [
121
- 'audit' => [ 'message' => $sMessage ],
122
- 'offense_count' => $nOffenseCount
123
- ]
124
- );
125
- }
126
- }
127
- }
128
-
129
- /**
130
- * @param array $aMessages
131
- * @return array
132
- */
133
- public function fAugmentFirewallDieMessage( $aMessages ) {
134
- if ( !is_array( $aMessages ) ) {
135
- $aMessages = [];
136
- }
137
-
138
- $aMessages[] = sprintf( '<p>%s</p>', sprintf(
139
- $this->getMod()->getTextOpt( 'text_remainingtrans' ),
140
- ( new IPs\Components\QueryRemainingOffenses() )
141
- ->setMod( $this->getMod() )
142
- ->setIP( Services::IP()->getRequestIp() )
143
- ->run()
144
- ) );
145
-
146
- return $aMessages;
147
- }
148
-
149
- private function processBlacklist() {
150
- /** @var \ICWP_WPSF_FeatureHandler_Ips $oMod */
151
- $oMod = $this->getMod();
152
-
153
- $bIpBlocked = ( new IPs\Components\QueryIpBlock() )
154
- ->setMod( $oMod )
155
- ->setIp( Services::IP()->getRequestIp() )
156
- ->run();
157
-
158
- if ( $bIpBlocked ) {
159
- $this->setIfLogRequest( false ); // don't log traffic from killed requests
160
- try {
161
- if ( $this->processAutoUnblockRequest() ) {
162
- return;
163
- }
164
- }
165
- catch ( \Exception $oE ) {
166
- }
167
- $this->getCon()->fireEvent( 'conn_kill' );
168
- $this->renderKillPage();
169
- }
170
- }
171
-
172
- /**
173
- * @throws \Exception
174
- */
175
- private function processAutoUnblockRequest() {
176
- /** @var \ICWP_WPSF_FeatureHandler_Ips $oMod */
177
- $oMod = $this->getMod();
178
- /** @var IPs\Options $oOpts */
179
- $oOpts = $oMod->getOptions();
180
- $oReq = Services::Request();
181
-
182
- if ( $oOpts->isEnabledAutoUserRecover() && $oReq->isPost()
183
- && $oReq->request( 'action' ) == $oMod->prefix() && $oReq->request( 'exec' ) == 'uau' ) {
184
-
185
- if ( check_admin_referer( $oReq->request( 'exec' ), 'exec_nonce' ) !== 1 ) {
186
- throw new \Exception( 'Nonce failed' );
187
- }
188
- if ( strlen( $oReq->post( 'icwp_wpsf_login_email' ) ) > 0 ) {
189
- throw new \Exception( 'Email should not be provided in honeypot' );
190
- }
191
-
192
- $sIp = Services::IP()->getRequestIp();
193
- if ( $oReq->post( 'ip' ) != $sIp ) {
194
- throw new \Exception( 'IP does not match' );
195
- }
196
-
197
- $oLoginMod = $this->getCon()->getModule_LoginGuard();
198
- $sGasp = $oReq->post( $oLoginMod->getGaspKey() );
199
- if ( empty( $sGasp ) ) {
200
- throw new \Exception( 'GASP failed' );
201
- }
202
-
203
- if ( !$oOpts->getCanIpRequestAutoUnblock( $sIp ) ) {
204
- throw new \Exception( 'IP already processed in the last 24hrs' );
205
- }
206
- $oMod->updateIpRequestAutoUnblockTs( $sIp );
207
-
208
- ( new IPs\Lib\Ops\DeleteIp() )
209
- ->setDbHandler( $oMod->getDbHandler_IPs() )
210
- ->setIP( $sIp )
211
- ->fromBlacklist();
212
- Services::Response()->redirectToHome();
213
- }
214
-
215
- return false;
216
- }
217
-
218
- private function renderKillPage() {
219
- /** @var \ICWP_WPSF_FeatureHandler_Ips $oMod */
220
- $oMod = $this->getMod();
221
- /** @var IPs\Options $oOpts */
222
- $oOpts = $oMod->getOptions();
223
- $oCon = $this->getCon();
224
- $oLoginMod = $oCon->getModule_LoginGuard();
225
-
226
- $sUniqId = 'uau'.uniqid();
227
-
228
- $sIp = Services::IP()->getRequestIp();
229
- $nTimeRemaining = max( floor( $oOpts->getAutoExpireTime()/60 ), 0 );
230
- $aData = [
231
- 'strings' => [
232
- 'title' => sprintf( __( "You've been blocked by the %s plugin", 'wp-simple-firewall' ),
233
- sprintf( '<a href="%s" target="_blank">%s</a>',
234
- $oCon->getPluginSpec()[ 'meta' ][ 'url_repo_home' ],
235
- $oCon->getHumanName()
236
- )
237
- ),
238
- 'lines' => [
239
- sprintf( __( 'Time remaining on black list: %s', 'wp-simple-firewall' ),
240
- sprintf( _n( '%s minute', '%s minutes', $nTimeRemaining, 'wp-simple-firewall' ), $nTimeRemaining )
241
- ),
242
- sprintf( __( 'You tripped the security plugin defenses a total of %s times making you a suspect.', 'wp-simple-firewall' ), $oOpts->getOffenseLimit() ),
243
- sprintf( __( 'If you believe this to be in error, please contact the site owner and quote your IP address below.', 'wp-simple-firewall' ) ),
244
- ],
245
- 'your_ip' => 'Your IP address',
246
- 'unblock' => [
247
- 'title' => __( 'Auto-Unblock Your IP', 'wp-simple-firewall' ),
248
- 'you_can' => __( 'You can automatically unblock your IP address by clicking the button below.', 'wp-simple-firewall' ),
249
- 'button' => __( 'Unblock My IP Address', 'wp-simple-firewall' ),
250
- ],
251
- ],
252
- 'vars' => [
253
- 'nonce' => $oMod->getNonceActionData( 'uau' ),
254
- 'ip' => $sIp,
255
- 'gasp_element' => $oMod->renderTemplate(
256
- 'snippets/gasp_js.php',
257
- [
258
- 'sCbName' => $oLoginMod->getGaspKey(),
259
- 'sLabel' => $oLoginMod->getTextImAHuman(),
260
- 'sAlert' => $oLoginMod->getTextPleaseCheckBox(),
261
- 'sMustJs' => __( 'You MUST enable Javascript to be able to login', 'wp-simple-firewall' ),
262
- 'sUniqId' => $sUniqId,
263
- 'sUniqElem' => 'icwp_wpsf_login_p'.$sUniqId,
264
- 'strings' => [
265
- 'loading' => __( 'Loading', 'wp-simple-firewall' )
266
- ]
267
- ]
268
- ),
269
- ],
270
- 'flags' => [
271
- 'is_autorecover' => $oOpts->isEnabledAutoUserRecover(),
272
- 'is_uau_permitted' => $oOpts->getCanIpRequestAutoUnblock( $sIp ),
273
- ],
274
- ];
275
- Services::WpGeneral()
276
- ->wpDie(
277
- $oMod->renderTemplate( '/snippets/blacklist_die.twig', $aData, true )
278
- );
279
- }
280
-
281
- /**
282
- * TODO 8.6: make private
283
- */
284
- public function doBlackMarkCurrentVisitor() {
285
- /** @var \ICWP_WPSF_FeatureHandler_Ips $oMod */
286
- $oMod = $this->getMod();
287
-
288
- $oTracker = $oMod->loadOffenseTracker();
289
- if ( !$this->getCon()->isPluginDeleting()
290
- && $oTracker->hasVisitorOffended() && $oTracker->isCommit()
291
- && !$oMod->isVerifiedBot() ) {
292
-
293
- ( new IPs\Components\ProcessOffense() )
294
- ->setMod( $oMod )
295
- ->setIp( Services::IP()->getRequestIp() )
296
- ->run();
297
- }
298
- }
299
-
300
- /**
301
- * @deprecated 8.5
302
- */
303
- private function processTransgression() {
304
- return;
305
- }
306
-
307
- /**
308
- * @return string
309
- * @deprecated 8.5
310
- */
311
- public function getRemainingTransgressions() {
312
- return 0;
313
- }
314
-
315
- /**
316
- * @param string $sIp
317
- * @return int
318
- * @deprecated 8.5
319
- */
320
- private function getTransgressions( $sIp ) {
321
- return 0;
322
- }
323
-
324
- /**
325
- * @return string
326
- * @deprecated 8.5
327
- */
328
- private function getTextOfRemainingTransgressions() {
329
- return '';
330
- }
331
-
332
- /**
333
- * @return Databases\IPs\EntryVO[]
334
- * @deprecated 8.5
335
- */
336
- public function getWhitelistIpsData() {
337
- return [];
338
- }
339
-
340
- /**
341
- * @return string[]
342
- * @deprecated 8.5
343
- */
344
- public function getWhitelistIps() {
345
- return [];
346
- }
347
-
348
- /**
349
- * @param string $sIp
350
- * @param string $sLabel
351
- * @return Databases\IPs\EntryVO|null
352
- * @deprecated 8.5
353
- */
354
- public function addIpToWhiteList( $sIp, $sLabel = '' ) {
355
- return ( new IPs\Lib\Ops\AddIp() )
356
  ->setMod( $this->getMod() )
357
- ->setIP( $sIp )
358
- ->toManualWhitelist( $sLabel );
359
- }
360
-
361
- /**
362
- * @param string $sIp
363
- * @param string $sList
364
- * @param string $sLabel
365
- * @return Databases\IPs\EntryVO|null
366
- * @deprecated 8.5
367
- */
368
- private function addIpToManualList( $sIp, $sList, $sLabel = '' ) {
369
- return null;
370
- }
371
-
372
- /**
373
- * ADDITION OF ANY IP TO ANY LIST SHOULD GO THROUGH HERE.
374
- * @param string $sIp
375
- * @param string $sList
376
- * @param string $sLabel
377
- * @return Databases\IPs\EntryVO|null
378
- * @deprecated 8.5
379
- */
380
- private function addIpToList( $sIp, $sList, $sLabel = '' ) {
381
- return null;
382
- }
383
-
384
- /**
385
- * The auto black list isn't a simple lookup, but rather has an auto expiration
386
- * @param string $sIp
387
- * @return Databases\IPs\EntryVO|null
388
- * @deprecated 8.5
389
- */
390
- protected function getBlackListIp( $sIp ) {
391
- /** @var \ICWP_WPSF_FeatureHandler_Ips $oMod */
392
- $oMod = $this->getMod();
393
- /** @var IPs\Options $oOpts */
394
- $oOpts = $oMod->getOptions();
395
- /** @var Databases\IPs\Select $oSelect */
396
- $oSelect = $oMod->getDbHandler_IPs()->getQuerySelector();
397
- /** @var Databases\IPs\EntryVO $oIp */
398
- $oIp = $oSelect->filterByIp( $sIp )
399
- ->filterByBlacklist()
400
- ->filterByLastAccessAfter( Services::Request()->ts() - $oOpts->getAutoExpireTime() )
401
- ->first();
402
- return $oIp;
403
- }
404
-
405
- /**
406
- * The auto black list isn't a simple lookup, but rather has an auto expiration
407
- * @param string $sIp
408
- * @return Databases\IPs\EntryVO|null
409
- * @deprecated 8.5
410
- */
411
- protected function getAutoBlackListIp( $sIp ) {
412
- /** @var \ICWP_WPSF_FeatureHandler_Ips $oMod */
413
- $oMod = $this->getMod();
414
- /** @var IPs\Options $oOpts */
415
- $oOpts = $oMod->getOptions();
416
- /** @var Databases\IPs\Select $oSelect */
417
- $oSelect = $oMod->getDbHandler_IPs()->getQuerySelector();
418
- return $oSelect->filterByIp( $sIp )
419
- ->filterByList( $oMod::LIST_AUTO_BLACK )
420
- ->filterByLastAccessAfter( Services::Request()->ts() - $oOpts->getAutoExpireTime() )
421
- ->first();
422
  }
423
 
424
  /**
425
- * @deprecated 8.5
426
  */
427
- private function processAutoUnblockByFlag() {
428
  }
429
  }
1
  <?php
2
 
3
  use FernleafSystems\Wordpress\Plugin\Shield;
 
 
4
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
 
5
 
6
+ class ICWP_WPSF_Processor_Ips extends Shield\Modules\BaseShield\ShieldProcessor {
7
 
8
  /**
9
  */
10
  public function run() {
11
+ ( new IPs\Lib\BlacklistHandler() )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  ->setMod( $this->getMod() )
13
+ ->run();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  }
15
 
16
  /**
17
+ * @deprecated 8.6.2
18
  */
19
+ private function doBlackMarkCurrentVisitor() {
20
  }
21
  }
src/processors/license.php CHANGED
@@ -5,32 +5,37 @@ use FernleafSystems\Wordpress\Services\Services;
5
 
6
  class ICWP_WPSF_Processor_License extends Modules\BaseShield\ShieldProcessor {
7
 
8
- /**
9
- */
10
  public function run() {
11
- /** @var ICWP_WPSF_FeatureHandler_License $oFO */
12
- $oFO = $this->getMod();
 
13
  $oReq = Services::Request();
14
 
15
- // performs the license check
16
- add_action( $oFO->prefix( 'adhoc_cron_license_check' ), [ $oFO, 'verifyLicense' ] );
 
 
 
 
 
 
 
 
17
 
18
- switch ( $this->getCon()->getShieldAction() ) {
19
 
20
  case 'keyless_handshake':
21
  $sNonce = $oReq->query( 'nonce' );
22
- if ( !empty( $sNonce ) && $sNonce == $oFO->getKeylessRequestHash() ) {
23
- $aHandshakeData = [ 'success' => false ];
24
- if ( !$oFO->isKeylessHandshakeExpired() ) {
25
- $aHandshakeData[ 'success' ] = true;
26
- }
27
- die( json_encode( $aHandshakeData ) );
28
  }
29
  break;
30
 
31
  case 'license_check':
32
- if ( !wp_next_scheduled( $oFO->prefix( 'adhoc_cron_license_check' ) ) ) {
33
- wp_schedule_single_event( $oReq->ts() + 20, $oFO->prefix( 'adhoc_cron_license_check' ), [ true ] );
34
  }
35
  break;
36
  }
5
 
6
  class ICWP_WPSF_Processor_License extends Modules\BaseShield\ShieldProcessor {
7
 
 
 
8
  public function run() {
9
+ $oCon = $this->getCon();
10
+ /** @var Modules\License\Options $oOpts */
11
+ $oOpts = $this->getOptions();
12
  $oReq = Services::Request();
13
 
14
+ // performs the license check on-demand
15
+ add_action( $oCon->prefix( 'adhoc_cron_license_check' ), function () {
16
+ /** @var \ICWP_WPSF_FeatureHandler_License $oMod */
17
+ $oMod = $this->getMod();
18
+ try {
19
+ $oMod->getLicenseHandler()->verify( true );
20
+ }
21
+ catch ( \Exception $oE ) {
22
+ }
23
+ } );
24
 
25
+ switch ( $oCon->getShieldAction() ) {
26
 
27
  case 'keyless_handshake':
28
  $sNonce = $oReq->query( 'nonce' );
29
+ if ( !empty( $sNonce ) && $sNonce === $oOpts->getOpt( 'keyless_handshake_hash' ) ) {
30
+ die( json_encode( [
31
+ 'success' => $oOpts->getOpt( 'keyless_handshake_until', 0 ) >= $oReq->ts()
32
+ ] ) );
 
 
33
  }
34
  break;
35
 
36
  case 'license_check':
37
+ if ( !wp_next_scheduled( $oCon->prefix( 'adhoc_cron_license_check' ) ) ) {
38
+ wp_schedule_single_event( $oReq->ts() + 20, $oCon->prefix( 'adhoc_cron_license_check' ) );
39
  }
40
  break;
41
  }
src/processors/lockdown.php CHANGED
@@ -13,7 +13,7 @@ class ICWP_WPSF_Processor_Lockdown extends Modules\BaseShield\ShieldProcessor {
13
  $this->blockFileEditing();
14
  }
15
 
16
- $sWpVersionMask = $this->getOption( 'mask_wordpress_version' );
17
  if ( !empty( $sWpVersionMask ) ) {
18
  global $wp_version;
19
  $wp_version = $sWpVersionMask;
13
  $this->blockFileEditing();
14
  }
15
 
16
+ $sWpVersionMask = $this->getOptions()->getOpt( 'mask_wordpress_version' );
17
  if ( !empty( $sWpVersionMask ) ) {
18
  global $wp_version;
19
  $wp_version = $sWpVersionMask;
src/processors/login_protect.php CHANGED
@@ -1,6 +1,7 @@
1
  <?php
2
 
3
  use FernleafSystems\Wordpress\Plugin\Shield\Modules;
 
4
  use FernleafSystems\Wordpress\Services\Services;
5
 
6
  class ICWP_WPSF_Processor_LoginProtect extends Modules\BaseShield\ShieldProcessor {
@@ -20,30 +21,25 @@ class ICWP_WPSF_Processor_LoginProtect extends Modules\BaseShield\ShieldProcesso
20
 
21
  // So we can allow access to the login pages if IP is whitelisted
22
  if ( $oMod->isCustomLoginPathEnabled() ) {
23
- $this->getSubProRename()->execute();
24
  }
25
 
26
  if ( !$oMod->isVisitorWhitelisted() ) {
27
  if ( $oMod->isEnabledGaspCheck() ) {
28
- $this->getSubProGasp()->execute();
29
  }
30
 
31
  if ( $oOpts->isCooldownEnabled() ) {
32
  if ( Services::Request()->isPost() ) {
33
- $this->getSubProCooldown()->execute();
34
  }
35
- /*
36
- ( new Modules\LoginGuard\Lib\CooldownRedirect() )
37
- ->setMod( $oMod )
38
- ->run();
39
- */
40
  }
41
 
42
  if ( $oMod->isGoogleRecaptchaEnabled() ) {
43
- $this->getSubProRecaptcha()->execute();
44
  }
45
 
46
- $this->getSubProIntent()->execute();
47
  }
48
  }
49
 
@@ -117,6 +113,7 @@ class ICWP_WPSF_Processor_LoginProtect extends Modules\BaseShield\ShieldProcesso
117
 
118
  /**
119
  * @return \ICWP_WPSF_Processor_LoginProtect_Cooldown
 
120
  */
121
  private function getSubProCooldown() {
122
  return $this->getSubPro( 'cooldown' );
@@ -124,20 +121,15 @@ class ICWP_WPSF_Processor_LoginProtect extends Modules\BaseShield\ShieldProcesso
124
 
125
  /**
126
  * @return \ICWP_WPSF_Processor_LoginProtect_Gasp
 
127
  */
128
  private function getSubProGasp() {
129
  return $this->getSubPro( 'gasp' );
130
  }
131
 
132
- /**
133
- * @return \ICWP_WPSF_Processor_LoginProtect_Intent
134
- */
135
- public function getSubProIntent() {
136
- return $this->getSubPro( 'intent' );
137
- }
138
-
139
  /**
140
  * @return \ICWP_WPSF_Processor_LoginProtect_GoogleRecaptcha
 
141
  */
142
  private function getSubProRecaptcha() {
143
  return $this->getSubPro( 'recaptcha' );
@@ -145,8 +137,17 @@ class ICWP_WPSF_Processor_LoginProtect extends Modules\BaseShield\ShieldProcesso
145
 
146
  /**
147
  * @return \ICWP_WPSF_Processor_LoginProtect_WpLogin
 
148
  */
149
  private function getSubProRename() {
150
  return $this->getSubPro( 'rename' );
151
  }
 
 
 
 
 
 
 
 
152
  }
1
  <?php
2
 
3
  use FernleafSystems\Wordpress\Plugin\Shield\Modules;
4
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor;
5
  use FernleafSystems\Wordpress\Services\Services;
6
 
7
  class ICWP_WPSF_Processor_LoginProtect extends Modules\BaseShield\ShieldProcessor {
21
 
22
  // So we can allow access to the login pages if IP is whitelisted
23
  if ( $oMod->isCustomLoginPathEnabled() ) {
24
+ $this->getSubPro( 'rename' )->execute();
25
  }
26
 
27
  if ( !$oMod->isVisitorWhitelisted() ) {
28
  if ( $oMod->isEnabledGaspCheck() ) {
29
+ $this->getSubPro( 'gasp' )->execute();
30
  }
31
 
32
  if ( $oOpts->isCooldownEnabled() ) {
33
  if ( Services::Request()->isPost() ) {
34
+ $this->getSubPro( 'cooldown' )->execute();
35
  }
 
 
 
 
 
36
  }
37
 
38
  if ( $oMod->isGoogleRecaptchaEnabled() ) {
39
+ $this->getSubPro( 'recaptcha' )->execute();
40
  }
41
 
42
+ $oMod->getLoginIntentController()->run();
43
  }
44
  }
45
 
113
 
114
  /**
115
  * @return \ICWP_WPSF_Processor_LoginProtect_Cooldown
116
+ * @deprecated 8.6.0
117
  */
118
  private function getSubProCooldown() {
119
  return $this->getSubPro( 'cooldown' );
121
 
122
  /**
123
  * @return \ICWP_WPSF_Processor_LoginProtect_Gasp
124
+ * @deprecated 8.6.0
125
  */
126
  private function getSubProGasp() {
127
  return $this->getSubPro( 'gasp' );
128
  }
129
 
 
 
 
 
 
 
 
130
  /**
131
  * @return \ICWP_WPSF_Processor_LoginProtect_GoogleRecaptcha
132
+ * @deprecated 8.6.0
133
  */
134
  private function getSubProRecaptcha() {
135
  return $this->getSubPro( 'recaptcha' );
137
 
138
  /**
139
  * @return \ICWP_WPSF_Processor_LoginProtect_WpLogin
140
+ * @deprecated 8.6.0
141
  */
142
  private function getSubProRename() {
143
  return $this->getSubPro( 'rename' );
144
  }
145
+
146
+ /**
147
+ * @return \ICWP_WPSF_Processor_LoginProtect_Intent
148
+ * @deprecated 8.6.0
149
+ */
150
+ public function getSubProIntent() {
151
+ return $this->getSubPro( 'intent' );
152
+ }
153
  }
src/processors/loginprotect_intent.php CHANGED
@@ -1,8 +1,11 @@
1
  <?php
2
 
3
- use FernleafSystems\Wordpress\Services\Services;
4
  use FernleafSystems\Wordpress\Plugin\Shield;
 
5
 
 
 
 
6
  class ICWP_WPSF_Processor_LoginProtect_Intent extends Shield\Modules\BaseShield\ShieldProcessor {
7
 
8
  /**
@@ -18,168 +21,26 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends Shield\Modules\BaseShield\
18
  /**
19
  */
20
  public function run() {
21
- /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oMod */
22
- $oMod = $this->getMod();
23
- add_action( 'wp_logout', [ $this, 'onWpLogout' ] );
24
-
25
- // 100 priority is important as this takes priority
26
- // add_filter( $oMod->prefix( 'user_subject_to_login_intent' ), array( $this, 'applyUserCanMfaSkip' ), 100, 2 );
27
-
28
- if ( $oMod->getIfSupport3rdParty() ) {
29
- add_action( 'wc_social_login_before_user_login', [ $this, 'onWcSocialLogin' ] );
30
- }
31
  }
32
 
33
  /**
34
  * @param int $nUserId
35
  */
36
  public function onWcSocialLogin( $nUserId ) {
37
- $oUser = Services::WpUsers()->getUserById( $nUserId );
38
- if ( $oUser instanceof WP_User ) {
39
- $this->getCon()->getUserMeta( $oUser )->wc_social_login_valid = true;
40
- }
41
- }
42
-
43
- public function onWpInit() {
44
- $this->setupLoginIntent();
45
  }
46
 
47
  protected function setupLoginIntent() {
48
- /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
49
- $oFO = $this->getMod();
50
-
51
- if ( $oFO->isEnabledGoogleAuthenticator() ) {
52
- $this->getProcessorGoogleAuthenticator()->execute();
53
- }
54
-
55
- if ( $oFO->isEmailAuthenticationActive() ) {
56
- $this->getProcessorEmailAuth()->execute();
57
- }
58
-
59
- if ( $oFO->isYubikeyActive() ) {
60
- $this->getProcessorYubikey()->execute();
61
- }
62
-
63
- if ( $oFO->isEnabledBackupCodes() ) {
64
- $this->getProcessorBackupCodes()->execute();
65
- }
66
-
67
- if ( $this->getLoginTrack()->hasFactorsRemainingToTrack() ) {
68
- if ( Services::WpGeneral()->isLoginRequest() || $oFO->getIfSupport3rdParty() ) {
69
- /** 20180925 - now using set cookie auth instead so we can capture session */
70
- // add_action( 'authenticate', array( $this, 'initLoginIntent' ), 100, 1 );
71
- }
72
-
73
- // process the current login intent
74
- $oWpUsers = Services::WpUsers();
75
- if ( $oWpUsers->isUserLoggedIn() ) {
76
- if ( $this->isUserSubjectToLoginIntent() && !$oFO->canUserMfaSkip( $oWpUsers->getCurrentWpUser() ) ) {
77
- $this->processLoginIntent();
78
- }
79
- elseif ( $this->hasLoginIntent() ) {
80
- // This handles the case where an admin changes a setting while a user is logged-in
81
- // So to prevent this, we remove any intent for a user that isn't subject to it right now
82
- $this->removeLoginIntent();
83
- }
84
- }
85
- }
86
- }
87
-
88
- /**
89
- * @param string $sUsername
90
- * @param WP_User $oUser
91
- */
92
- public function onWpLogin( $sUsername, $oUser ) {
93
- $this->initLoginIntent( $oUser );
94
- }
95
-
96
- /**
97
- * @param string $sCookie
98
- * @param int $nExpire
99
- * @param int $nExpiration
100
- * @param int $nUserId
101
- */
102
- public function onWpSetLoggedInCookie( $sCookie, $nExpire, $nExpiration, $nUserId ) {
103
- $this->initLoginIntent( Services::WpUsers()->getUserById( $nUserId ) );
104
  }
105
 
106
  /**
107
  * @param WP_User|WP_Error $oUser
108
  */
109
- protected function initLoginIntent( $oUser ) {
110
-
111
- if ( !$this->isLoginCaptured() && $oUser instanceof WP_User
112
- && $this->getLoginTrack()->hasFactorsRemainingToTrack() ) {
113
-
114
- /** @var \ICWP_WPSF_FeatureHandler_LoginProtect $oF */
115
- $oF = $this->getMod();
116
- if ( !$oF->canUserMfaSkip( $oUser ) ) {
117
- $nTimeout = (int)apply_filters( $oF->prefix( 'login_intent_timeout' ), $oF->getDef( 'login_intent_timeout' ) );
118
- $this->setLoginIntentExpiresAt( Services::Request()->ts() + MINUTE_IN_SECONDS*$nTimeout );
119
- }
120
- }
121
- }
122
 
123
  /**
124
  * hooked to 'init' and only run if a user is logged-in (not on the login request)
125
  */
126
- private function processLoginIntent() {
127
- $oWpResp = Services::Response();
128
- $oWpUsers = Services::WpUsers();
129
-
130
- /** @var \ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
131
- $oFO = $this->getMod();
132
-
133
- if ( $this->hasValidLoginIntent() ) { // ie. valid login intent present
134
- $oReq = Services::Request();
135
-
136
- // Is 2FA/login-intent submit
137
- if ( $oReq->request( $oFO->getLoginIntentRequestFlag() ) == 1 ) {
138
-
139
- if ( $oReq->post( 'cancel' ) == 1 ) {
140
- $oWpUsers->logoutUser(); // clears the login and login intent
141
- $sRedirectHref = $oReq->post( 'cancel_href' );
142
- empty( $sRedirectHref ) ? $oWpResp->redirectToLogin() : $oWpResp->redirect( rawurldecode( $sRedirectHref ) );
143
- }
144
- elseif ( $this->isLoginIntentValid() ) {
145
-
146
- if ( $oReq->post( 'skip_mfa' ) === 'Y' ) { // store the browser hash
147
- $oFO->addMfaLoginHash( $oWpUsers->getCurrentWpUser() );
148
- }
149
-
150
- $this->removeLoginIntent();
151
- $sFlash = __( 'Success', 'wp-simple-firewall' ).'! '.__( 'Thank you for authenticating your login.', 'wp-simple-firewall' );
152
- if ( $oFO->isEnabledBackupCodes() ) {
153
- $sFlash .= ' '.__( 'If you used your Backup Code, you will need to reset it.', 'wp-simple-firewall' ); //TODO::
154
- }
155
-
156
- $this->getCon()->fireEvent( '2fa_success' );
157
- $oFO->setFlashAdminNotice( $sFlash );
158
-
159
- $sRedirectHref = $oReq->post( 'redirect_to' );
160
- empty( $sRedirectHref ) ? $oWpResp->redirectHere() : $oWpResp->redirect( rawurldecode( $sRedirectHref ) );
161
- }
162
- else {
163
- $oFO->setFlashAdminNotice( __( 'One or more of your authentication codes failed or was missing', 'wp-simple-firewall' ), true );
164
- // We don't protect against loops here to prevent by-passing of the login intent page.
165
- Services::Response()->redirect( Services::Request()->getUri(), [], true, false );
166
- }
167
- return; // we've redirected anyway.
168
- }
169
- if ( $this->printLoginIntentForm() ) {
170
- die();
171
- }
172
- }
173
- elseif ( $this->hasLoginIntent() ) { // there was an old login intent
174
- $oWpUsers->logoutUser(); // clears the login and login intent
175
- $oWpResp->redirectHere();
176
- }
177
- else {
178
- // no login intent present -
179
- // the login has already been fully validated and the login intent was deleted.
180
- // also means new installation don't get booted out
181
- }
182
- }
183
 
184
  /**
185
  * Use this ONLY when the login intent has been successfully verified.
@@ -194,13 +55,6 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends Shield\Modules\BaseShield\
194
  * @return $this
195
  */
196
  protected function setLoginIntentExpiresAt( $nExpirationTime ) {
197
- /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oMod */
198
- $oMod = $this->getMod();
199
- if ( $oMod->hasSession() ) {
200
- /** @var Shield\Databases\Session\Update $oUpd */
201
- $oUpd = $oMod->getDbHandler_Sessions()->getQueryUpdater();
202
- $oUpd->updateLoginIntentExpiresAt( $oMod->getSession(), $nExpirationTime );
203
- }
204
  return $this;
205
  }
206
 
@@ -228,157 +82,17 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends Shield\Modules\BaseShield\
228
  }
229
 
230
  /**
231
- * @return bool true if valid form printed, false otherwise. Should die() if true
232
  */
233
- private function printLoginIntentForm() {
234
- /** @var \ICWP_WPSF_FeatureHandler_LoginProtect $oMod */
235
- $oMod = $this->getMod();
236
- $oCon = $this->getCon();
237
- $oReq = Services::Request();
238
- $oWP = Services::WpGeneral();
239
- $aLoginIntentFields = apply_filters( $oCon->prefix( 'login-intent-form-fields' ), [] );
240
-
241
- if ( empty( $aLoginIntentFields ) ) {
242
- return false; // a final guard against displaying an empty form.
243
- }
244
-
245
- if ( $oMod->isChainedAuth() ) {
246
- $sMessage = __( 'Please supply all authentication codes', 'wp-simple-firewall' );
247
- }
248
- else {
249
- $sMessage = __( 'Please supply at least 1 authentication code', 'wp-simple-firewall' );
250
- }
251
-
252
- $sReferUrl = $oReq->server( 'HTTP_REFERER', '' );
253
- if ( strpos( $sReferUrl, '?' ) ) {
254
- list( $sReferUrl, $sReferQuery ) = explode( '?', $sReferUrl, 2 );
255
- }
256
- else {
257
- $sReferQuery = '';
258
- }
259
-
260
- $sRedirectTo = '';
261
- if ( !empty( $sReferQuery ) ) {
262
- parse_str( $sReferQuery, $aReferQueryItems );
263
- if ( !empty( $aReferQueryItems[ 'redirect_to' ] ) ) {
264
- $sRedirectTo = rawurlencode( $aReferQueryItems[ 'redirect_to' ] );
265
- }
266
- }
267
- if ( empty( $sRedirectTo ) ) {
268
- $sRedirectTo = rawurlencode( $oReq->post( 'redirect_to', $oReq->getUri() ) );
269
- }
270
-
271
- $sCancelHref = $oReq->post( 'cancel_href', '' );
272
- if ( empty( $sCancelHref ) && Services::Data()->isValidWebUrl( $sReferUrl ) ) {
273
- $sCancelHref = rawurlencode( parse_url( $sReferUrl, PHP_URL_PATH ) );
274
- }
275
-
276
- $aLabels = $oCon->getLabels();
277
- $sBannerUrl = empty( $aLabels[ 'url_login2fa_logourl' ] ) ? $oCon->getPluginUrl_Image( 'pluginlogo_banner-772x250.png' ) : $aLabels[ 'url_login2fa_logourl' ];
278
- $nMfaSkip = $oMod->getMfaSkip();
279
- $aDisplayData = [
280
- 'strings' => [
281
- 'cancel' => __( 'Cancel Login', 'wp-simple-firewall' ),
282
- 'time_remaining' => __( 'Time Remaining', 'wp-simple-firewall' ),
283
- 'calculating' => __( 'Calculating', 'wp-simple-firewall' ).' ...',
284
- 'seconds' => strtolower( __( 'Seconds', 'wp-simple-firewall' ) ),
285
- 'login_expired' => __( 'Login Expired', 'wp-simple-firewall' ),
286
- 'verify_my_login' => __( 'Verify My Login', 'wp-simple-firewall' ),
287
- 'more_info' => __( 'More Info', 'wp-simple-firewall' ),
288
- 'what_is_this' => __( 'What is this?', 'wp-simple-firewall' ),
289
- 'message' => $sMessage,
290
- 'page_title' => sprintf( __( '%s Login Verification', 'wp-simple-firewall' ), $oCon->getHumanName() ),
291
- 'skip_mfa' => sprintf(
292
- __( "Don't ask again on this browser for %s.", 'wp-simple-firewall' ),
293
- sprintf( _n( '%s day', '%s days', $nMfaSkip, 'wp-simple-firewall' ), $nMfaSkip )
294
- )
295
- ],
296
- 'data' => [
297
- 'login_fields' => $aLoginIntentFields,
298
- 'time_remaining' => $this->getLoginIntentExpiresAt() - $oReq->ts(),
299
- 'message_type' => 'info',
300
- 'login_intent_flag' => $oMod->getLoginIntentRequestFlag(),
301
- 'page_locale' => $oWP->getLocale( '-' )
302
- ],
303
- 'hrefs' => [
304
- 'form_action' => parse_url( $oWP->getAdminUrl( '', true ), PHP_URL_PATH ),
305
- 'css_bootstrap' => $oCon->getPluginUrl_Css( 'bootstrap4.min' ),
306
- 'js_bootstrap' => $oCon->getPluginUrl_Js( 'bootstrap4.min' ),
307
- 'shield_logo' => 'https://ps.w.org/wp-simple-firewall/assets/banner-772x250.png',
308
- 'redirect_to' => $sRedirectTo,
309
- 'what_is_this' => 'https://icontrolwp.freshdesk.com/support/solutions/articles/3000064840',
310
- 'cancel_href' => $sCancelHref
311
- ],
312
- 'imgs' => [
313
- 'banner' => $sBannerUrl,
314
- 'favicon' => $oCon->getPluginUrl_Image( 'pluginlogo_24x24.png' ),
315
- ],
316
- 'flags' => [
317
- 'can_skip_mfa' => $oMod->getMfaSkipEnabled(),
318
- 'show_branded_links' => !$oMod->isWlEnabled(), // white label mitigation
319
- ]
320
- ];
321
-
322
- echo $oMod->renderTemplate( '/pages/login_intent/index.twig',
323
- Services::DataManipulation()->mergeArraysRecursive( $oMod->getBaseDisplayData(), $aDisplayData ), true );
324
-
325
- return true;
326
- }
327
-
328
  /**
329
  */
330
  public function onWpLogout() {
331
- /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
332
- $oFO = $this->getMod();
333
-
334
- $this->removeLoginIntent();
335
-
336
- // support for WooCommerce Social Login
337
- $oMeta = $this->getCon()->getCurrentUserMeta();
338
- if ( $oFO->getIfSupport3rdParty() && $oMeta instanceof Shield\Users\ShieldUserMeta ) {
339
- $oMeta->wc_social_login_valid = false;
340
- }
341
- }
342
-
343
- /**
344
- * @return ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth
345
- */
346
- protected function getProcessorEmailAuth() {
347
- return ( new ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth( $this->getMod() ) )
348
- ->setLoginTrack( $this->getLoginTrack() );
349
- }
350
-
351
- /**
352
- * @return ICWP_WPSF_Processor_LoginProtect_Yubikey
353
- */
354
- protected function getProcessorYubikey() {
355
- return ( new ICWP_WPSF_Processor_LoginProtect_Yubikey( $this->getMod() ) )
356
- ->setLoginTrack( $this->getLoginTrack() );
357
- }
358
-
359
- /**
360
- * @return ICWP_WPSF_Processor_LoginProtect_BackupCodes
361
- */
362
- public function getProcessorBackupCodes() {
363
- return ( new ICWP_WPSF_Processor_LoginProtect_BackupCodes( $this->getMod() ) )
364
- ->setLoginTrack( $this->getLoginTrack() );
365
- }
366
-
367
- /**
368
- * @return ICWP_WPSF_Processor_LoginProtect_GoogleAuthenticator
369
- */
370
- public function getProcessorGoogleAuthenticator() {
371
- return ( new ICWP_WPSF_Processor_LoginProtect_GoogleAuthenticator( $this->getMod() ) )
372
- ->setLoginTrack( $this->getLoginTrack() );
373
  }
374
 
375
  /**
376
  * @return ICWP_WPSF_Processor_LoginProtect_Track
377
  */
378
  public function getLoginTrack() {
379
- if ( !isset( $this->oLoginTrack ) ) {
380
- $this->oLoginTrack = new ICWP_WPSF_Processor_LoginProtect_Track();
381
- }
382
  return $this->oLoginTrack;
383
  }
384
 
@@ -387,43 +101,20 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends Shield\Modules\BaseShield\
387
  * @return bool
388
  */
389
  private function isLoginIntentValid() {
390
- /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
391
- $oFO = $this->getMod();
392
- if ( !$this->isLoginIntentProcessed() ) {
393
- // This action sets up the necessary login tracker info
394
- do_action( $oFO->prefix( 'login-intent-validation' ), Services::WpUsers()->getCurrentWpUser() );
395
- $this->setLoginIntentProcessed();
396
- }
397
- $oTrk = $this->getLoginTrack();
398
-
399
- // 1st: if backup code was used, then chained auth is irrelevant
400
- $sBackupStub = ICWP_WPSF_Processor_LoginProtect_Track::Factor_BackupCode;
401
-
402
- // if backup code used, that's successful; or
403
- // It's not chained and you have any 1 successful; or
404
- // It's chained (and then you must exclude the backup code.
405
- $bSuccess = in_array( $sBackupStub, $oTrk->getFactorsSuccessful() )
406
- || ( !$oFO->isChainedAuth() && $oTrk->hasSuccessfulFactor() );
407
- if ( !$bSuccess && $oFO->isChainedAuth() ) {
408
- $bSuccess = !$oTrk->hasUnSuccessfulFactor()
409
- || ( $oTrk->getCountFactorsUnsuccessful() == 1 && in_array( $sBackupStub, $oTrk->getFactorsUnsuccessful() ) );
410
- }
411
-
412
- return $bSuccess;
413
  }
414
 
415
  /**
416
  * @return bool
417
  */
418
  public function isLoginIntentProcessed() {
419
- return (bool)$this->bLoginIntentProcessed;
420
  }
421
 
422
  /**
423
  * @return $this
424
  */
425
  public function setLoginIntentProcessed() {
426
- $this->bLoginIntentProcessed = true;
427
  return $this;
428
  }
429
 
@@ -432,7 +123,6 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends Shield\Modules\BaseShield\
432
  * @return $this
433
  */
434
  public function setLoginTrack( $oLoginTrack ) {
435
- $this->oLoginTrack = $oLoginTrack;
436
  return $this;
437
  }
438
  }
1
  <?php
2
 
 
3
  use FernleafSystems\Wordpress\Plugin\Shield;
4
+ use FernleafSystems\Wordpress\Services\Services;
5
 
6
+ /**
7
+ * @deprecated 8.6.0
8
+ */
9
  class ICWP_WPSF_Processor_LoginProtect_Intent extends Shield\Modules\BaseShield\ShieldProcessor {
10
 
11
  /**
21
  /**
22
  */
23
  public function run() {
 
 
 
 
 
 
 
 
 
 
24
  }
25
 
26
  /**
27
  * @param int $nUserId
28
  */
29
  public function onWcSocialLogin( $nUserId ) {
 
 
 
 
 
 
 
 
30
  }
31
 
32
  protected function setupLoginIntent() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  }
34
 
35
  /**
36
  * @param WP_User|WP_Error $oUser
37
  */
38
+ protected function initLoginIntent( $oUser ) {}
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
  /**
41
  * hooked to 'init' and only run if a user is logged-in (not on the login request)
42
  */
43
+ private function processLoginIntent() {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
  /**
46
  * Use this ONLY when the login intent has been successfully verified.
55
  * @return $this
56
  */
57
  protected function setLoginIntentExpiresAt( $nExpirationTime ) {
 
 
 
 
 
 
 
58
  return $this;
59
  }
60
 
82
  }
83
 
84
  /**
 
85
  */
86
+ private function printLoginIntentForm() {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  /**
88
  */
89
  public function onWpLogout() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  }
91
 
92
  /**
93
  * @return ICWP_WPSF_Processor_LoginProtect_Track
94
  */
95
  public function getLoginTrack() {
 
 
 
96
  return $this->oLoginTrack;
97
  }
98
 
101
  * @return bool
102
  */
103
  private function isLoginIntentValid() {
104
+ return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  }
106
 
107
  /**
108
  * @return bool
109
  */
110
  public function isLoginIntentProcessed() {
111
+ return true;
112
  }
113
 
114
  /**
115
  * @return $this
116
  */
117
  public function setLoginIntentProcessed() {
 
118
  return $this;
119
  }
120
 
123
  * @return $this
124
  */
125
  public function setLoginTrack( $oLoginTrack ) {
 
126
  return $this;
127
  }
128
  }
src/processors/loginprotect_intent_tracker.php CHANGED
@@ -1,5 +1,9 @@
1
  <?php
2
 
 
 
 
 
3
  class ICWP_WPSF_Processor_LoginProtect_Track {
4
 
5
  const Factor_Google_Authenticator = 'ga';
1
  <?php
2
 
3
+ /**
4
+ * Class ICWP_WPSF_Processor_LoginProtect_Track
5
+ * @deprecated 8.6.0
6
+ */
7
  class ICWP_WPSF_Processor_LoginProtect_Track {
8
 
9
  const Factor_Google_Authenticator = 'ga';
src/processors/loginprotect_intentprovider_backup.php CHANGED
@@ -2,55 +2,11 @@
2
 
3
  use FernleafSystems\Wordpress\Services\Services;
4
 
 
 
 
5
  class ICWP_WPSF_Processor_LoginProtect_BackupCodes extends ICWP_WPSF_Processor_LoginProtect_IntentProviderBase {
6
 
7
- /**
8
- * This MUST only ever be hooked into when the User is looking at their OWN profile, so we can use "current user"
9
- * functions. Otherwise we need to be careful of mixing up users.
10
- * @param \WP_User $oUser
11
- */
12
- public function addOptionsToUserProfile( $oUser ) {
13
- $oCon = $this->getCon();
14
-
15
- $bValidatedProfile = $this->hasValidatedProfile( $oUser );
16
- $aData = [
17
- 'has_mfa' => $this->isUserSubjectToLoginIntent( $oUser ),
18
- 'has_validated_profile' => $bValidatedProfile,
19
- 'user_google_authenticator_secret' => $this->getSecret( $oUser ),
20
- 'is_my_user_profile' => ( $oUser->ID == Services::WpUsers()->getCurrentWpUserId() ),
21
- 'i_am_valid_admin' => $oCon->isPluginAdmin(),
22
- 'user_to_edit_is_admin' => Services::WpUsers()->isUserAdmin( $oUser ),
23
- 'strings' => [
24
- 'button_gen_code' => __( 'Generate ONE-Time Backup 2FA Login Code', 'wp-simple-firewall' ),
25
- 'button_del_code' => __( 'Delete Login Backup Code', 'wp-simple-firewall' ),
26
- 'not_available' => __( 'Backup login codes are not available if you do not have any other two-factor authentication modes active.', 'wp-simple-firewall' ),
27
- 'description_code' => __( 'Click to generate a backup login code for your two-factor authentication.', 'wp-simple-firewall' ),
28
- 'description_code_ext1' => sprintf( '%s: %s',
29
- __( 'Important', 'wp-simple-firewall' ),
30
- __( 'This code will be displayed only once and you may use it to verify your login only once.', 'wp-simple-firewall' )
31
- .' '.__( 'Store it somewhere safe.', 'wp-simple-firewall' ) ),
32
- 'description_code_ext2' => __( 'Generating a new code will replace your existing code.', 'wp-simple-firewall' ),
33
- 'description_chart_url' => __( 'Use your Google Authenticator app to scan this QR code and enter the one time password below.', 'wp-simple-firewall' ),
34
- 'description_ga_secret' => __( 'If you have a problem with scanning the QR code enter this code manually into the app.', 'wp-simple-firewall' ),
35
- 'desc_remove' => __( 'Check the box to remove Google Authenticator login authentication.', 'wp-simple-firewall' ),
36
- 'label_check_to_remove' => sprintf( __( 'Remove %s', 'wp-simple-firewall' ), __( 'Google Authenticator', 'wp-simple-firewall' ) ),
37
- 'label_enter_code' => __( 'Create Backup 2FA Login Code', 'wp-simple-firewall' ),
38
- 'label_ga_secret' => __( 'Manual Code', 'wp-simple-firewall' ),
39
- 'label_scan_qr_code' => __( 'Scan This QR Code', 'wp-simple-firewall' ),
40
- 'title' => __( 'Backup Login Code', 'wp-simple-firewall' ),
41
- 'cant_add_other_user' => sprintf( __( "Sorry, %s may not be added to another user's account.", 'wp-simple-firewall' ), 'Backup Codes' ),
42
- 'cant_remove_admins' => sprintf( __( "Sorry, %s may only be removed from another user's account by a Security Administrator.", 'wp-simple-firewall' ), __( 'Backup Codes', 'wp-simple-firewall' ) ),
43
- 'provided_by' => sprintf( __( 'Provided by %s', 'wp-simple-firewall' ), $oCon->getHumanName() ),
44
- 'remove_more_info' => sprintf( __( 'Understand how to remove Google Authenticator', 'wp-simple-firewall' ) )
45
- ],
46
- 'data' => [
47
- 'otp_field_name' => $this->getLoginFormParameter()
48
- ]
49
- ];
50
-
51
- echo $this->getMod()->renderTemplate( 'snippets/user_profile_backupcode.php', $aData );
52
- }
53
-
54
  /**
55
  * @param \WP_User $oUser
56
  */
@@ -135,43 +91,6 @@ class ICWP_WPSF_Processor_LoginProtect_BackupCodes extends ICWP_WPSF_Processor_L
135
  );
136
  }
137
 
138
- /**
139
- * @param \WP_User $oUser
140
- * @param bool $bIsOtpSuccess
141
- * @param bool $bOtpProvided - whether a OTP was actually provided
142
- * @return $this
143
- */
144
- protected function postOtpProcessAction( $oUser, $bIsOtpSuccess, $bOtpProvided ) {
145
- parent::postOtpProcessAction( $oUser, $bIsOtpSuccess, $bOtpProvided );
146
-
147
- if ( $bOtpProvided && $bIsOtpSuccess ) {
148
- $this->sendBackupCodeUsedEmail( $oUser );
149
- }
150
- return $this;
151
- }
152
-
153
- /**
154
- * @param \WP_User $oUser
155
- */
156
- private function sendBackupCodeUsedEmail( $oUser ) {
157
- $aEmailContent = [
158
- __( 'This is a quick notice to inform you that your Backup Login code was just used.', 'wp-simple-firewall' ),
159
- __( "Your WordPress account had only 1 backup login code.", 'wp-simple-firewall' )
160
- .' '.__( "You must go to your profile and regenerate a new code if you want to use this method again.", 'wp-simple-firewall' ),
161
- '',
162
- sprintf( '<strong>%s</strong>', __( 'Login Details', 'wp-simple-firewall' ) ),
163
- sprintf( '%s: %s', __( 'URL', 'wp-simple-firewall' ), Services::WpGeneral()->getHomeUrl() ),
164
- sprintf( '%s: %s', __( 'Username', 'wp-simple-firewall' ), $oUser->user_login ),
165
- sprintf( '%s: %s', __( 'IP Address', 'wp-simple-firewall' ), Services::IP()->getRequestIp() ),
166
- '',
167
- __( 'Thank You.', 'wp-simple-firewall' ),
168
- ];
169
-
170
- $sTitle = sprintf( __( "Notice: %s", 'wp-simple-firewall' ), __( "Backup Login Code Just Used", 'wp-simple-firewall' ) );
171
- $this->getEmailProcessor()
172
- ->sendEmailWithWrap( $oUser->user_email, $sTitle, $aEmailContent );
173
- }
174
-
175
  /**
176
  * @param \WP_User $oUser
177
  * @return string
2
 
3
  use FernleafSystems\Wordpress\Services\Services;
4
 
5
+ /**
6
+ * @deprecated 8.6.0
7
+ */
8
  class ICWP_WPSF_Processor_LoginProtect_BackupCodes extends ICWP_WPSF_Processor_LoginProtect_IntentProviderBase {
9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  /**
11
  * @param \WP_User $oUser
12
  */
91
  );
92
  }
93
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  /**
95
  * @param \WP_User $oUser
96
  * @return string
src/processors/loginprotect_intentprovider_base.php CHANGED
@@ -3,6 +3,9 @@
3
  use FernleafSystems\Wordpress\Plugin\Shield\Modules;
4
  use FernleafSystems\Wordpress\Services\Services;
5
 
 
 
 
6
  abstract class ICWP_WPSF_Processor_LoginProtect_IntentProviderBase extends Modules\BaseShield\ShieldProcessor {
7
 
8
  /**
3
  use FernleafSystems\Wordpress\Plugin\Shield\Modules;
4
  use FernleafSystems\Wordpress\Services\Services;
5
 
6
+ /**
7
+ * @deprecated 8.6.0
8
+ */
9
  abstract class ICWP_WPSF_Processor_LoginProtect_IntentProviderBase extends Modules\BaseShield\ShieldProcessor {
10
 
11
  /**
src/processors/loginprotect_intentprovider_email.php CHANGED
@@ -2,6 +2,9 @@
2
 
3
  use FernleafSystems\Wordpress\Services\Services;
4
 
 
 
 
5
  class ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth extends ICWP_WPSF_Processor_LoginProtect_IntentProviderBase {
6
 
7
  /**
@@ -21,8 +24,7 @@ class ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth extends ICWP_WPSF_Processor
21
  $oUpd->setLoginIntentCodeEmail( $oMod->getSession(), $this->getSecret( $oUser ) );
22
 
23
  // Now send email with authentication link for user.
24
- $this->sendEmailTwoFactorVerify( $oUser )
25
- ->setLoginCaptured();
26
  }
27
  return $oUser;
28
  }
@@ -131,79 +133,6 @@ class ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth extends ICWP_WPSF_Processor
131
  return !empty( $sHash );
132
  }
133
 
134
- /**
135
- * @param \WP_User $oUser
136
- * @return $this
137
- */
138
- private function sendEmailTwoFactorVerify( \WP_User $oUser ) {
139
- $aMessage = [
140
- __( 'Someone attempted to login into this WordPress site using your account.', 'wp-simple-firewall' ),
141
- __( 'Login requires verification with the following code.', 'wp-simple-firewall' ),
142
- '',
143
- sprintf( __( 'Verification Code: %s', 'wp-simple-firewall' ), sprintf( '<strong>%s</strong>', $this->getSecret( $oUser ) ) ),
144
- '',
145
- sprintf( '<strong>%s</strong>', __( 'Login Details', 'wp-simple-firewall' ) ),
146
- sprintf( '%s: %s', __( 'URL', 'wp-simple-firewall' ), Services::WpGeneral()->getHomeUrl() ),
147
- sprintf( '%s: %s', __( 'Username', 'wp-simple-firewall' ), $oUser->user_login ),
148
- sprintf( '%s: %s', __( 'IP Address', 'wp-simple-firewall' ), Services::IP()->getRequestIp() ),
149
- '',
150
- ];
151
-
152
- if ( !$this->getCon()->isRelabelled() ) {
153
- $aMessage[] = sprintf( '- <a href="%s" target="_blank">%s</a>', 'https://shsec.io/96', __( 'Why no login link?', 'wp-simple-firewall' ) );
154
- $aContent[] = '';
155
- }
156
-
157
- $bResult = $this->getEmailProcessor()
158
- ->sendEmailWithWrap(
159
- $oUser->user_email,
160
- __( 'Two-Factor Login Verification', 'wp-simple-firewall' ),
161
- $aMessage
162
- );
163
-
164
- $this->getCon()->fireEvent(
165
- $bResult ? '2fa_email_send_success' : '2fa_email_send_fail',
166
- [
167
- 'audit' => [
168
- 'user_login' => $oUser->user_login,
169
- ]
170
- ]
171
- );
172
- return $this;
173
- }
174
-
175
- /**
176
- * This MUST only ever be hooked into when the User is looking at their OWN profile, so we can use "current user"
177
- * functions. Otherwise we need to be careful of mixing up users.
178
- * @param WP_User $oUser
179
- */
180
- public function addOptionsToUserProfile( $oUser ) {
181
- $oWp = Services::WpUsers();
182
- $bValidatedProfile = $this->hasValidatedProfile( $oUser );
183
- $aData = [
184
- 'user_has_email_authentication_active' => $bValidatedProfile,
185
- 'user_has_email_authentication_enforced' => $this->isSubjectToEmailAuthentication( $oUser ),
186
- 'is_my_user_profile' => ( $oUser->ID == $oWp->getCurrentWpUserId() ),
187
- 'i_am_valid_admin' => $this->getCon()->isPluginAdmin(),
188
- 'user_to_edit_is_admin' => $oWp->isUserAdmin( $oUser ),
189
- 'strings' => [
190
- 'label_email_authentication' => __( 'Email Authentication', 'wp-simple-firewall' ),
191
- 'title' => __( 'Email Authentication', 'wp-simple-firewall' ),
192
- 'description_email_authentication_checkbox' => __( 'Check the box to enable email-based login authentication.', 'wp-simple-firewall' ),
193
- 'provided_by' => sprintf( __( 'Provided by %s', 'wp-simple-firewall' ), $this->getCon()
194
- ->getHumanName() )
195
- ]
196
- ];
197
-
198
- $aData[ 'bools' ] = [
199
- 'checked' => $bValidatedProfile || $aData[ 'user_has_email_authentication_enforced' ],
200
- 'disabled' => true || $aData[ 'user_has_email_authentication_enforced' ]
201
- //TODO: Make email authentication a per-user setting
202
- ];
203
-
204
- echo $this->getMod()->renderTemplate( 'snippets/user_profile_emailauthentication.php', $aData );
205
- }
206
-
207
  /**
208
  * @return string
209
  */
2
 
3
  use FernleafSystems\Wordpress\Services\Services;
4
 
5
+ /**
6
+ * @deprecated 8.6.0
7
+ */
8
  class ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth extends ICWP_WPSF_Processor_LoginProtect_IntentProviderBase {
9
 
10
  /**
24
  $oUpd->setLoginIntentCodeEmail( $oMod->getSession(), $this->getSecret( $oUser ) );
25
 
26
  // Now send email with authentication link for user.
27
+ $this->setLoginCaptured();
 
28
  }
29
  return $oUser;
30
  }
133
  return !empty( $sHash );
134
  }
135
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  /**
137
  * @return string
138
  */
src/processors/loginprotect_intentprovider_ga.php CHANGED
@@ -3,6 +3,9 @@
3
  use FernleafSystems\Wordpress\Services\Services;
4
  use Dolondro\GoogleAuthenticator;
5
 
 
 
 
6
  class ICWP_WPSF_Processor_LoginProtect_GoogleAuthenticator extends ICWP_WPSF_Processor_LoginProtect_IntentProviderBase {
7
 
8
  /**
@@ -19,54 +22,6 @@ class ICWP_WPSF_Processor_LoginProtect_GoogleAuthenticator extends ICWP_WPSF_Pro
19
  }
20
  }
21
 
22
- /**
23
- * This MUST only ever be hooked into when the User is looking at their OWN profile, so we can use "current user"
24
- * functions. Otherwise we need to be careful of mixing up users.
25
- * @param WP_User $oUser
26
- */
27
- public function addOptionsToUserProfile( $oUser ) {
28
- $oCon = $this->getCon();
29
-
30
- $bValidatedProfile = $this->hasValidatedProfile( $oUser );
31
-
32
- if ( !$bValidatedProfile ) {
33
- $this->resetSecret( $oUser );
34
- }
35
-
36
- $aData = [
37
- 'has_validated_profile' => $bValidatedProfile,
38
- 'user_google_authenticator_secret' => $this->getSecret( $oUser ),
39
- 'is_my_user_profile' => ( $oUser->ID == Services::WpUsers()->getCurrentWpUserId() ),
40
- 'i_am_valid_admin' => $oCon->isPluginAdmin(),
41
- 'user_to_edit_is_admin' => Services::WpUsers()->isUserAdmin( $oUser ),
42
- 'strings' => [
43
- 'description_otp_code' => __( 'Provide the current code generated by your Google Authenticator app.', 'wp-simple-firewall' ),
44
- 'description_otp_code_ext' => __( 'To reset this QR Code enter fake data here.', 'wp-simple-firewall' ),
45
- 'description_chart_url' => __( 'Use your Google Authenticator app to scan this QR code and enter the one time password below.', 'wp-simple-firewall' ),
46
- 'description_ga_secret' => __( 'If you have a problem with scanning the QR code enter this code manually into the app.', 'wp-simple-firewall' ),
47
- 'desc_remove' => __( 'Check the box to remove Google Authenticator login authentication.', 'wp-simple-firewall' ),
48
- 'label_check_to_remove' => sprintf( __( 'Remove %s', 'wp-simple-firewall' ), __( 'Google Authenticator', 'wp-simple-firewall' ) ),
49
- 'label_enter_code' => __( 'Google Authenticator Code', 'wp-simple-firewall' ),
50
- 'label_ga_secret' => __( 'Manual Code', 'wp-simple-firewall' ),
51
- 'label_scan_qr_code' => __( 'Scan This QR Code', 'wp-simple-firewall' ),
52
- 'title' => __( 'Google Authenticator', 'wp-simple-firewall' ),
53
- 'cant_add_other_user' => sprintf( __( "Sorry, %s may not be added to another user's account.", 'wp-simple-firewall' ), 'Google Authenticator' ),
54
- 'cant_remove_admins' => sprintf( __( "Sorry, %s may only be removed from another user's account by a Security Administrator.", 'wp-simple-firewall' ), __( 'Google Authenticator', 'wp-simple-firewall' ) ),
55
- 'provided_by' => sprintf( __( 'Provided by %s', 'wp-simple-firewall' ), $oCon->getHumanName() ),
56
- 'remove_more_info' => sprintf( __( 'Understand how to remove Google Authenticator', 'wp-simple-firewall' ) )
57
- ],
58
- 'data' => [
59
- 'otp_field_name' => $this->getLoginFormParameter()
60
- ]
61
- ];
62
-
63
- if ( !$bValidatedProfile ) {
64
- $aData[ 'chart_url' ] = $this->getGaRegisterChartUrl( $oUser );
65
- }
66
-
67
- echo $this->getMod()->renderTemplate( 'snippets/user_profile_googleauthenticator.php', $aData );
68
- }
69
-
70
  /**
71
  * @param \WP_User $oUser
72
  * @return string
3
  use FernleafSystems\Wordpress\Services\Services;
4
  use Dolondro\GoogleAuthenticator;
5
 
6
+ /**
7
+ * @deprecated 8.6.0
8
+ */
9
  class ICWP_WPSF_Processor_LoginProtect_GoogleAuthenticator extends ICWP_WPSF_Processor_LoginProtect_IntentProviderBase {
10
 
11
  /**
22
  }
23
  }
24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  /**
26
  * @param \WP_User $oUser
27
  * @return string
src/processors/loginprotect_intentprovider_yubikey.php CHANGED
@@ -2,6 +2,9 @@
2
 
3
  use FernleafSystems\Wordpress\Services\Services;
4
 
 
 
 
5
  class ICWP_WPSF_Processor_LoginProtect_Yubikey extends ICWP_WPSF_Processor_LoginProtect_IntentProviderBase {
6
 
7
  const OTP_LENGTH = 12;
@@ -10,49 +13,6 @@ class ICWP_WPSF_Processor_LoginProtect_Yubikey extends ICWP_WPSF_Processor_Login
10
  */
11
  const URL_YUBIKEY_VERIFY = 'https://api.yubico.com/wsapi/2.0/verify';
12
 
13
- /**
14
- * This MUST only ever be hooked into when the User is looking at their OWN profile, so we can use "current user"
15
- * functions. Otherwise we need to be careful of mixing up users.
16
- * @param WP_User $oUser
17
- */
18
- public function addOptionsToUserProfile( $oUser ) {
19
- $oCon = $this->getCon();
20
- $oWpUsers = Services::WpUsers();
21
-
22
- $bValidatedProfile = $this->hasValidatedProfile( $oUser );
23
- $aData = [
24
- 'has_validated_profile' => $bValidatedProfile,
25
- 'is_my_user_profile' => ( $oUser->ID == $oWpUsers->getCurrentWpUserId() ),
26
- 'i_am_valid_admin' => $oCon->isPluginAdmin(),
27
- 'user_to_edit_is_admin' => $oWpUsers->isUserAdmin( $oUser ),
28
- 'strings' => [
29
- 'description_otp_code' => __( 'This is your unique Yubikey Device ID.', 'wp-simple-firewall' ),
30
- 'description_otp_code_ext' => '['.__( 'Pro Only', 'wp-simple-firewall' ).'] '
31
- .__( 'Multiple Yubikey Device IDs are separated by a comma.', 'wp-simple-firewall' ),
32
- 'description_otp' => __( 'Provide a One Time Password from your Yubikey.', 'wp-simple-firewall' ),
33
- 'description_otp_ext' => $bValidatedProfile ?
34
- __( 'This will remove the Yubikey Device ID from your profile.', 'wp-simple-firewall' )
35
- : __( 'This will add the Yubikey Device ID to your profile.', 'wp-simple-firewall' ),
36
- 'description_otp_ext_2' => $bValidatedProfile ?
37
- '['.__( 'Pro Only', 'wp-simple-firewall' ).'] '.__( 'If you provide a OTP from an alternative Yubikey device, it will also be added to your profile.', 'wp-simple-firewall' )
38
- : '',
39
- 'label_enter_code' => __( 'Yubikey ID', 'wp-simple-firewall' ),
40
- 'label_enter_otp' => __( 'Yubikey OTP', 'wp-simple-firewall' ),
41
- 'title' => __( 'Yubikey Authentication', 'wp-simple-firewall' ),
42
- 'cant_add_other_user' => sprintf( __( "Sorry, %s may not be added to another user's account.", 'wp-simple-firewall' ), 'Yubikey' ),
43
- 'cant_remove_admins' => sprintf( __( "Sorry, %s may only be removed from another user's account by a Security Administrator.", 'wp-simple-firewall' ), __( 'Yubikey', 'wp-simple-firewall' ) ),
44
- 'provided_by' => sprintf( __( 'Provided by %s', 'wp-simple-firewall' ), $oCon->getHumanName() ),
45
- 'remove_more_info' => sprintf( __( 'Understand how to remove Google Authenticator', 'wp-simple-firewall' ) )
46
- ],
47
- 'data' => [
48
- 'otp_field_name' => $this->getLoginFormParameter(),
49
- 'secret' => str_replace( ',', ', ', $this->getSecret( $oUser ) ),
50
- ]
51
- ];
52
-
53
- echo $this->getMod()->renderTemplate( 'snippets/user_profile_yubikey.php', $aData );
54
- }
55
-
56
  /**
57
  * This MUST only ever be hooked into when the User is looking at their OWN profile,
58
  * so we can use "current user" functions. Otherwise we need to be careful of mixing up users.
@@ -175,7 +135,7 @@ class ICWP_WPSF_Processor_LoginProtect_Yubikey extends ICWP_WPSF_Processor_Login
175
  $aParts = [
176
  'otp' => $sOTP,
177
  'nonce' => md5( uniqid( rand() ) ),
178
- 'id' => $this->getOption( 'yubikey_app_id' )
179
  ];
180
 
181
  $sReqUrl = add_query_arg( $aParts, self::URL_YUBIKEY_VERIFY );
2
 
3
  use FernleafSystems\Wordpress\Services\Services;
4
 
5
+ /**
6
+ * @deprecated 8.6.0
7
+ */
8
  class ICWP_WPSF_Processor_LoginProtect_Yubikey extends ICWP_WPSF_Processor_LoginProtect_IntentProviderBase {
9
 
10
  const OTP_LENGTH = 12;
13
  */
14
  const URL_YUBIKEY_VERIFY = 'https://api.yubico.com/wsapi/2.0/verify';
15
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  /**
17
  * This MUST only ever be hooked into when the User is looking at their OWN profile,
18
  * so we can use "current user" functions. Otherwise we need to be careful of mixing up users.
135
  $aParts = [
136
  'otp' => $sOTP,
137
  'nonce' => md5( uniqid( rand() ) ),
138
+ 'id' => $this->getOptions()->getOpt( 'yubikey_app_id' )
139
  ];
140
 
141
  $sReqUrl = add_query_arg( $aParts, self::URL_YUBIKEY_VERIFY );
src/processors/plugin.php CHANGED
@@ -1,5 +1,6 @@
1
  <?php
2
 
 
3
  use FernleafSystems\Wordpress\Plugin\Shield\Modules;
4
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin;
5
  use FernleafSystems\Wordpress\Services\Services;
@@ -13,11 +14,14 @@ class ICWP_WPSF_Processor_Plugin extends Modules\BaseShield\ShieldProcessor {
13
  /** @var Plugin\Options $oOpts */
14
  $oOpts = $this->getOptions();
15
 
16
- $this->getSubPro( 'crondaily' )->execute();
17
- $this->getSubPro( 'cronhourly' )->execute();
18
-
19
  $this->removePluginConflicts();
20
 
 
 
 
 
 
 
21
  ( new Plugin\Components\PluginBadge() )
22
  ->setMod( $this->getMod() )
23
  ->run();
@@ -81,12 +85,6 @@ class ICWP_WPSF_Processor_Plugin extends Modules\BaseShield\ShieldProcessor {
81
  );
82
  }
83
 
84
- /**
85
- * @deprecated 8.5.7
86
- */
87
- public function gatherPluginWidgetContent() {
88
- }
89
-
90
  /**
91
  * @return \ICWP_WPSF_Processor_Plugin_Tracking
92
  */
@@ -108,8 +106,6 @@ class ICWP_WPSF_Processor_Plugin extends Modules\BaseShield\ShieldProcessor {
108
  return [
109
  'importexport' => 'ICWP_WPSF_Processor_Plugin_ImportExport',
110
  'tracking' => 'ICWP_WPSF_Processor_Plugin_Tracking',
111
- 'crondaily' => 'ICWP_WPSF_Processor_Plugin_CronDaily',
112
- 'cronhourly' => 'ICWP_WPSF_Processor_Plugin_CronHourly',
113
  ];
114
  }
115
 
1
  <?php
2
 
3
+ use FernleafSystems\Wordpress\Plugin\Shield;
4
  use FernleafSystems\Wordpress\Plugin\Shield\Modules;
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin;
6
  use FernleafSystems\Wordpress\Services\Services;
14
  /** @var Plugin\Options $oOpts */
15
  $oOpts = $this->getOptions();
16
 
 
 
 
17
  $this->removePluginConflicts();
18
 
19
+ ( new Shield\Crons\HourlyCron() )
20
+ ->setMod( $this->getMod() )
21
+ ->run();
22
+ ( new Shield\Crons\DailyCron() )
23
+ ->setMod( $this->getMod() )
24
+ ->run();
25
  ( new Plugin\Components\PluginBadge() )
26
  ->setMod( $this->getMod() )
27
  ->run();
85
  );
86
  }
87
 
 
 
 
 
 
 
88
  /**
89
  * @return \ICWP_WPSF_Processor_Plugin_Tracking
90
  */
106
  return [
107
  'importexport' => 'ICWP_WPSF_Processor_Plugin_ImportExport',
108
  'tracking' => 'ICWP_WPSF_Processor_Plugin_Tracking',
 
 
109
  ];
110
  }
111
 
src/processors/plugin_importexport.php CHANGED
@@ -84,24 +84,24 @@ class ICWP_WPSF_Processor_Plugin_ImportExport extends Shield\Modules\BaseShield\
84
  * @return string
85
  */
86
  private function createExportFileDownloadLink() {
87
- /** @var ICWP_WPSF_FeatureHandler_Plugin $oFO */
88
- $oFO = $this->getMod();
89
- $aActionNonce = $oFO->getNonceActionData( 'export_file_download' );
90
- return add_query_arg( $aActionNonce, $oFO->getUrl_AdminPage() );
91
  }
92
 
93
  public function runWhitelistNotify() {
94
- /** @var ICWP_WPSF_FeatureHandler_Plugin $oFO */
95
- $oFO = $this->getMod();
96
  $oHttpReq = Services::HttpRequest();
97
 
98
- if ( $oFO->hasImportExportWhitelistSites() ) {
99
 
100
  $aQuery = [
101
  'blocking' => false,
102
  'body' => [ 'shield_action' => 'importexport_updatenotified' ]
103
  ];
104
- foreach ( $oFO->getImportExportWhitelist() as $sUrl ) {
105
  $oHttpReq->get( $sUrl, $aQuery );
106
  }
107
 
84
  * @return string
85
  */
86
  private function createExportFileDownloadLink() {
87
+ return add_query_arg(
88
+ $this->getMod()->getNonceActionData( 'export_file_download' ),
89
+ $this->getMod()->getUrl_AdminPage()
90
+ );
91
  }
92
 
93
  public function runWhitelistNotify() {
94
+ /** @var ICWP_WPSF_FeatureHandler_Plugin $oMod */
95
+ $oMod = $this->getMod();
96
  $oHttpReq = Services::HttpRequest();
97
 
98
+ if ( $oMod->hasImportExportWhitelistSites() ) {
99
 
100
  $aQuery = [
101
  'blocking' => false,
102
  'body' => [ 'shield_action' => 'importexport_updatenotified' ]
103
  ];
104
+ foreach ( $oMod->getImportExportWhitelist() as $sUrl ) {
105
  $oHttpReq->get( $sUrl, $aQuery );
106
  }
107
 
src/processors/sessions.php CHANGED
@@ -187,13 +187,4 @@ class ICWP_WPSF_Processor_Sessions extends Modules\BaseShield\ShieldProcessor {
187
  $oSel = $oMod->getDbHandler_Sessions()->getQuerySelector();
188
  return $oSel->retrieveUserSession( $sSessionId, $sUsername );
189
  }
190
-
191
- /**
192
- * @param int $nSessionId
193
- * @return bool
194
- * @deprecated 8.5
195
- */
196
- public function terminateSession( $nSessionId ) {
197
- return false;
198
- }
199
  }
187
  $oSel = $oMod->getDbHandler_Sessions()->getQuerySelector();
188
  return $oSel->retrieveUserSession( $sSessionId, $sUsername );
189
  }
 
 
 
 
 
 
 
 
 
190
  }
src/processors/user_management.php CHANGED
@@ -42,6 +42,10 @@ class ICWP_WPSF_Processor_UserManagement extends Modules\BaseShield\ShieldProces
42
  add_action( 'user_register', function ( $nUserId ) {
43
  $this->getCon()->getUserMeta( Services::WpUsers()->getUserById( $nUserId ) );
44
  } );
 
 
 
 
45
  }
46
 
47
  /**
@@ -254,30 +258,6 @@ class ICWP_WPSF_Processor_UserManagement extends Modules\BaseShield\ShieldProces
254
  );
255
  }
256
 
257
- /**
258
- * @return ICWP_WPSF_Processor_UserManagement_Passwords|mixed
259
- * @deprecated 8.5.2
260
- */
261
- protected function getProcessorPasswords() {
262
- return $this->getSubPro( 'passwords' );
263
- }
264
-
265
- /**
266
- * @return ICWP_WPSF_Processor_UserManagement_Sessions|mixed
267
- * @deprecated 8.5.2
268
- */
269
- public function getProcessorSessions() {
270
- return $this->getSubPro( 'sessions' );
271
- }
272
-
273
- /**
274
- * @return ICWP_WPSF_Processor_UserManagement_Suspend|mixed
275
- * @deprecated 8.5.2
276
- */
277
- protected function getProcessorSuspend() {
278
- return $this->getSubPro( 'suspend' );
279
- }
280
-
281
  /**
282
  * @return array
283
  */
42
  add_action( 'user_register', function ( $nUserId ) {
43
  $this->getCon()->getUserMeta( Services::WpUsers()->getUserById( $nUserId ) );
44
  } );
45
+
46
+ ( new UserManagement\Lib\Registration\EmailValidate() )
47
+ ->setMod( $this->getMod() )
48
+ ->run();
49
  }
50
 
51
  /**
258
  );
259
  }
260
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
261
  /**
262
  * @return array
263
  */
src/processors/usermanagement_sessions.php CHANGED
@@ -181,22 +181,4 @@ class ICWP_WPSF_Processor_UserManagement_Sessions extends Modules\BaseShield\Shi
181
  }
182
  return $oError;
183
  }
184
-
185
- /**
186
- * @deprecated 8.5
187
- */
188
- public function cleanExpiredSessions() {
189
- }
190
-
191
- /**
192
- * @deprecated 8.5
193
- */
194
- private function getLoginIdleExpiredBoundary() {
195
- }
196
-
197
- /**
198
- * @deprecated 8.5
199
- */
200
- private function getLoginExpiredBoundary() {
201
- }
202
  }
181
  }
182
  return $oError;
183
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
  }
src/wizards/login_protect.php CHANGED
@@ -1,5 +1,6 @@
1
  <?php
2
 
 
3
  use FernleafSystems\Wordpress\Services\Services;
4
 
5
  /**
@@ -99,8 +100,8 @@ class ICWP_WPSF_Wizard_LoginProtect extends ICWP_WPSF_Wizard_BaseWpsf {
99
  * @return \FernleafSystems\Utilities\Response
100
  */
101
  private function processAuthGa() {
102
- /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
103
- $oFO = $this->getMod();
104
  $oReq = Services::Request();
105
 
106
  $oResponse = new \FernleafSystems\Utilities\Response();
@@ -116,15 +117,14 @@ class ICWP_WPSF_Wizard_LoginProtect extends ICWP_WPSF_Wizard_BaseWpsf {
116
  $sMessage = __( 'Code was empty.', 'wp-simple-firewall' );
117
  }
118
  else {
 
 
 
119
  $oUser = Services::WpUsers()->getCurrentWpUser();
120
- /** @var ICWP_WPSF_Processor_LoginProtect $oProc */
121
- $oProc = $oFO->getProcessor();
122
- $oProcGa = $oProc->getSubProIntent()
123
- ->getProcessorGoogleAuthenticator();
124
- $bValidated = $oProcGa->validateGaCode( $oUser, $sCode );
125
 
126
  if ( $bValidated ) {
127
- $oProcGa->setProfileValidated( $oUser, true );
128
  $sMessage = 'Google Authenticator was validated.';
129
  $oResponse->setSuccessful( true );
130
  }
@@ -139,7 +139,7 @@ class ICWP_WPSF_Wizard_LoginProtect extends ICWP_WPSF_Wizard_BaseWpsf {
139
  }
140
 
141
  if ( $bEnableGa ) {
142
- $oFO->setEnabled2FaGoogleAuthenticator( true );
143
  $sMessage .= ' '.__( 'Google Authenticator was enabled for the site.', 'wp-simple-firewall' );
144
  }
145
 
@@ -188,7 +188,7 @@ class ICWP_WPSF_Wizard_LoginProtect extends ICWP_WPSF_Wizard_BaseWpsf {
188
  /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
189
  $oFO = $this->getMod();
190
 
191
- $aStepsSlugs = array( 'start' );
192
 
193
  if ( !$oFO->getIfCanSendEmailVerified() || !$oFO->isEmailAuthenticationActive() ) {
194
  $aStepsSlugs[] = 'authemail';
@@ -208,50 +208,49 @@ class ICWP_WPSF_Wizard_LoginProtect extends ICWP_WPSF_Wizard_BaseWpsf {
208
  * @return array
209
  */
210
  protected function getRenderData_SlideExtra( $sStep ) {
211
- /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
212
- $oFO = $this->getMod();
213
 
214
- $aAdditional = array();
215
 
216
  switch ( $sStep ) {
217
 
218
  case 'authemail':
219
  $oUser = Services::WpUsers()->getCurrentWpUser();
220
- $aAdditional = array(
221
- 'data' => array(
222
  'name' => $oUser->first_name,
223
  'user_email' => $oUser->user_email
224
- )
225
- );
226
  break;
227
 
228
  case 'authga':
229
  $oUser = Services::WpUsers()->getCurrentWpUser();
230
- /** @var ICWP_WPSF_Processor_LoginProtect $oProc */
231
- $oProc = $oFO->getProcessor();
232
- $oProcGa = $oProc->getSubProIntent()
233
- ->getProcessorGoogleAuthenticator();
234
- $sGaUrl = $oProcGa->getGaRegisterChartUrl( $oUser );
235
- $aAdditional = array(
236
- 'data' => array(
237
  'name' => $oUser->first_name,
238
  'user_email' => $oUser->user_email
239
- ),
240
- 'hrefs' => array(
241
  'ga_chart' => $sGaUrl,
242
- ),
243
- 'flags' => array(
244
- 'has_ga' => $oProcGa->getCurrentUserHasValidatedProfile(),
245
- )
246
- );
247
  break;
248
 
249
  case 'multiselect':
250
- $aAdditional = array(
251
- 'flags' => array(
252
- 'has_multiselect' => $oFO->isChainedAuth(),
253
- )
254
- );
255
  break;
256
 
257
  default:
1
  <?php
2
 
3
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor;
4
  use FernleafSystems\Wordpress\Services\Services;
5
 
6
  /**
100
  * @return \FernleafSystems\Utilities\Response
101
  */
102
  private function processAuthGa() {
103
+ /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oMod */
104
+ $oMod = $this->getMod();
105
  $oReq = Services::Request();
106
 
107
  $oResponse = new \FernleafSystems\Utilities\Response();
117
  $sMessage = __( 'Code was empty.', 'wp-simple-firewall' );
118
  }
119
  else {
120
+ /** @var TwoFactor\Provider\GoogleAuth $oGA */
121
+ $oGA = $oMod->getLoginIntentController()
122
+ ->getProviders()[ TwoFactor\Provider\GoogleAuth::SLUG ];
123
  $oUser = Services::WpUsers()->getCurrentWpUser();
124
+ $bValidated = $oGA->validateGaCode( $oUser, $sCode );
 
 
 
 
125
 
126
  if ( $bValidated ) {
127
+ $oGA->setProfileValidated( $oUser, true );
128
  $sMessage = 'Google Authenticator was validated.';
129
  $oResponse->setSuccessful( true );
130
  }
139
  }
140
 
141
  if ( $bEnableGa ) {
142
+ $oMod->setEnabled2FaGoogleAuthenticator( true );
143
  $sMessage .= ' '.__( 'Google Authenticator was enabled for the site.', 'wp-simple-firewall' );
144
  }
145
 
188
  /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
189
  $oFO = $this->getMod();
190
 
191
+ $aStepsSlugs = [ 'start' ];
192
 
193
  if ( !$oFO->getIfCanSendEmailVerified() || !$oFO->isEmailAuthenticationActive() ) {
194
  $aStepsSlugs[] = 'authemail';
208
  * @return array
209
  */
210
  protected function getRenderData_SlideExtra( $sStep ) {
211
+ /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oMod */
212
+ $oMod = $this->getMod();
213
 
214
+ $aAdditional = [];
215
 
216
  switch ( $sStep ) {
217
 
218
  case 'authemail':
219
  $oUser = Services::WpUsers()->getCurrentWpUser();
220
+ $aAdditional = [
221
+ 'data' => [
222
  'name' => $oUser->first_name,
223
  'user_email' => $oUser->user_email
224
+ ]
225
+ ];
226
  break;
227
 
228
  case 'authga':
229
  $oUser = Services::WpUsers()->getCurrentWpUser();
230
+ /** @var TwoFactor\Provider\GoogleAuth $oGA */
231
+ $oGA = $oMod->getLoginIntentController()
232
+ ->getProviders()[ TwoFactor\Provider\GoogleAuth::SLUG ];
233
+ $sGaUrl = $oGA->getGaRegisterChartUrl( $oUser );
234
+ $aAdditional = [
235
+ 'data' => [
 
236
  'name' => $oUser->first_name,
237
  'user_email' => $oUser->user_email
238
+ ],
239
+ 'hrefs' => [
240
  'ga_chart' => $sGaUrl,
241
+ ],
242
+ 'flags' => [
243
+ 'has_ga' => $oGA->hasValidatedProfile( $oUser ),
244
+ ]
245
+ ];
246
  break;
247
 
248
  case 'multiselect':
249
+ $aAdditional = [
250
+ 'flags' => [
251
+ 'has_multiselect' => $oMod->isChainedAuth(),
252
+ ]
253
+ ];
254
  break;
255
 
256
  default:
src/wizards/plugin.php CHANGED
@@ -371,7 +371,8 @@ class ICWP_WPSF_Wizard_Plugin extends ICWP_WPSF_Wizard_BaseWpsf {
371
  /** @var \ICWP_WPSF_FeatureHandler_License $oModule */
372
  $oModule = $this->getCon()->getModule( 'license' );
373
  try {
374
- $bSuccess = $oModule->verifyLicense( true )
 
375
  ->hasValidWorkingLicense();
376
  if ( $bSuccess ) {
377
  $sMessage = __( 'License was found and successfully installed.', 'wp-simple-firewall' );
371
  /** @var \ICWP_WPSF_FeatureHandler_License $oModule */
372
  $oModule = $this->getCon()->getModule( 'license' );
373
  try {
374
+ $bSuccess = $oModule->getLicenseHandler()
375
+ ->verify( true )
376
  ->hasValidWorkingLicense();
377
  if ( $bSuccess ) {
378
  $sMessage = __( 'License was found and successfully installed.', 'wp-simple-firewall' );
templates/php/snippets/user_profile_backupcode.php DELETED
@@ -1,47 +0,0 @@
1
- <div id="shield-options-backupcode" class="shield-user-options-block">
2
- <h3><?php echo $strings[ 'title' ]; ?>
3
- <small>(<?php echo $strings[ 'provided_by' ]; ?>)</small>
4
- </h3>
5
- <table class="form-table">
6
- <tbody>
7
-
8
- <?php if ( $is_my_user_profile ) : ?>
9
- <tr>
10
- <th>
11
- <label>
12
- <?php echo $strings[ 'label_enter_code' ]; ?>
13
- </label>
14
- </th>
15
- <td>
16
- <?php if ( !$has_mfa ) : ?>
17
- <?php echo $strings[ 'not_available' ]; ?>
18
- <?php else : ?>
19
- <a href="#" id="IcwpWpsfGenBackupLoginCode"
20
- class="button button-primary">
21
- <?php echo $strings[ 'button_gen_code' ]; ?>
22
- </a>
23
- <?php if ( $has_validated_profile ) : ?>
24
- <a href="#" id="IcwpWpsfDelBackupLoginCode"
25
- class="button">
26
- <?php echo $strings[ 'button_del_code' ]; ?>
27
- </a>
28
- <?php endif; ?>
29
- <p class="description">
30
- <?php echo $strings[ 'description_code' ]; ?>
31
- <br/><strong><?php echo $strings[ 'description_code_ext1' ]; ?></strong>
32
- <?php if ( $has_validated_profile ) : ?>
33
- <br /><?php echo $strings[ 'description_code_ext2' ]; ?>
34
- <?php endif; ?>
35
- </p>
36
- <?php endif; ?>
37
- </td>
38
- </tr>
39
- <?php else : ?>
40
- <td>
41
- <p class="description"><?php echo $strings[ 'cant_add_other_user' ]; ?></p>
42
- </td>
43
- <?php endif; ?>
44
-
45
- </tbody>
46
- </table>
47
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
templates/php/snippets/user_profile_emailauthentication.php DELETED
@@ -1,29 +0,0 @@
1
- <div id="shield-options-email-authentication" class="shield-user-options-block">
2
- <h3><?php echo $strings['title']; ?>
3
- <small>(<?php echo $strings['provided_by']; ?>)</small>
4
- </h3>
5
-
6
- <table class="form-table">
7
- <tbody>
8
-
9
- <tr>
10
- <th><label for="shield_email_authentication"><?php echo $strings['label_email_authentication']; ?></label></th>
11
- <td>
12
- <input
13
- type="checkbox"
14
- name="shield_email_authentication" id="shield_email_authentication"
15
- value="Y"
16
- <?php if ( $bools['checked'] ) : ?>
17
- checked="checked"
18
- <?php endif; ?>
19
- <?php if ( $bools['disabled'] ) : ?>
20
- disabled="disabled"
21
- <?php endif; ?>
22
- />
23
- <p class="description"><?php echo $strings['description_email_authentication_checkbox']; ?></p>
24
- </td>
25
- </tr>
26
-
27
- </tbody>
28
- </table>
29
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
templates/php/snippets/user_profile_googleauthenticator.php DELETED
@@ -1,89 +0,0 @@
1
- <style type="text/css">
2
- #shield_ga_secret {
3
- letter-spacing: 5px;
4
- font-family: monospace;
5
- font-size: 24px;
6
- text-shadow: 1px 1px 0 rgba(0,0,0,0.4);
7
- border: 1px solid rgba(0,0,0,0.1);
8
- padding: 0 7px;
9
- background-color: whitesmoke;
10
- }
11
- </style>
12
- <div id="shield-options-google-authenticator" class="shield-user-options-block">
13
- <h3><?php echo $strings['title']; ?>
14
- <small>(<?php echo $strings['provided_by']; ?>)</small>
15
- </h3>
16
- <table class="form-table">
17
- <tbody>
18
-
19
- <?php if ( $has_validated_profile ) : ?>
20
-
21
- <?php if ( $is_my_user_profile || $i_am_valid_admin ) : ?>
22
- <tr>
23
- <th><label for="shield_turn_off_google_authenticator"><?php echo $strings['label_check_to_remove']; ?></label></th>
24
- <td>
25
- <input type="checkbox" name="shield_turn_off_google_authenticator" id="shield_turn_off_google_authenticator" value="Y" />
26
- <p class="description">
27
- <?php echo $strings['desc_remove']; ?>
28
- </p>
29
- </td>
30
- </tr>
31
- <tr>
32
- <th><label for="<?php echo $data['otp_field_name']; ?>"><?php echo $strings['label_enter_code']; ?></label></th>
33
- <td>
34
- <input class="regular-text"
35
- type="text"
36
- id="<?php echo $data['otp_field_name']; ?>"
37
- name="<?php echo $data['otp_field_name']; ?>"
38
- value="" autocomplete="off" />
39
- <p class="description"><?php echo $strings['description_otp_code']; ?></p>
40
- </td>
41
- </tr>
42
- <?php else : ?>
43
- <td>
44
- <p class="description"><?php echo $strings['cant_remove_admins']; ?></p>
45
- </td>
46
- <?php endif; ?>
47
-
48
- <?php else : ?>
49
-
50
- <?php if ( $is_my_user_profile ) : ?>
51
- <tr>
52
- <th><?php echo $strings['label_scan_qr_code']; ?></th>
53
- <td>
54
- <img src="<?php echo $chart_url; ?>" />
55
- <p class="description"><?php echo $strings['description_chart_url']; ?></p>
56
- </td>
57
- </tr>
58
- <tr>
59
- <th><label for="shield_ga_secret"><?php echo $strings['label_ga_secret']; ?></label></th>
60
- <td>
61
- <span id="shield_ga_secret"><?php echo $user_google_authenticator_secret; ?></span>
62
- <p class="description"><?php echo $strings['description_ga_secret']; ?></p>
63
- </td>
64
- </tr>
65
- <tr>
66
- <th><label for="<?php echo $data['otp_field_name']; ?>"><?php echo $strings['label_enter_code']; ?></label></th>
67
- <td>
68
- <input class="regular-text"
69
- type="text"
70
- id="<?php echo $data['otp_field_name']; ?>"
71
- name="<?php echo $data['otp_field_name']; ?>"
72
- value="" autocomplete="off" />
73
- <p class="description">
74
- <?php echo $strings['description_otp_code']; ?>
75
- <br/><?php echo $strings['description_otp_code_ext']; ?>
76
- </p>
77
- </td>
78
- </tr>
79
- <?php else : ?>
80
- <td>
81
- <p class="description"><?php echo $strings['cant_add_other_user']; ?></p>
82
- </td>
83
- <?php endif; ?>
84
-
85
- <?php endif; ?>
86
-
87
- </tbody>
88
- </table>
89
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
templates/php/snippets/user_profile_yubikey.php DELETED
@@ -1,81 +0,0 @@
1
- <style type="text/css">
2
- #shield_ga_secret {
3
- letter-spacing: 5px;
4
- font-family: monospace;
5
- font-size: 24px;
6
- text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.4);
7
- border: 1px solid rgba(0, 0, 0, 0.1);
8
- padding: 0 7px;
9
- background-color: whitesmoke;
10
- }
11
- </style>
12
- <div id="shield-options-google-authenticator" class="shield-user-options-block">
13
- <h3><?php echo $strings[ 'title' ]; ?>
14
- <small>(<?php echo $strings[ 'provided_by' ]; ?>)</small>
15
- </h3>
16
- <table class="form-table">
17
- <tbody>
18
-
19
- <?php if ( $has_validated_profile ) : ?>
20
-
21
- <?php if ( $is_my_user_profile || $i_am_valid_admin ) : ?>
22
- <tr>
23
- <th><label for="yubi_code"><?php echo $strings[ 'label_enter_code' ]; ?></label></th>
24
- <td>
25
- <input class="regular-text" name="yubi_code" id="yubi_code"
26
- type="text" value="<?php echo $data[ 'secret' ]; ?>" readonly />
27
- <p class="description">
28
- <?php echo $strings[ 'description_otp_code' ]; ?>
29
- <br /><?php echo $strings[ 'description_otp_code_ext' ]; ?>
30
- </p>
31
- </td>
32
- </tr>
33
-
34
- <tr>
35
- <th><label for="<?php echo $data[ 'otp_field_name' ]; ?>"><?php echo $strings[ 'label_enter_otp' ]; ?></label></th>
36
- <td>
37
- <input class="regular-text"
38
- type="text"
39
- id="<?php echo $data[ 'otp_field_name' ]; ?>"
40
- name="<?php echo $data[ 'otp_field_name' ]; ?>"
41
- value="" autocomplete="off" />
42
- <p class="description"><?php echo $strings[ 'description_otp' ]; ?>
43
- <br /><?php echo $strings[ 'description_otp_ext' ]; ?>
44
- <br /><?php echo $strings[ 'description_otp_ext_2' ]; ?>
45
- </p>
46
- </td>
47
- </tr>
48
- <?php else : ?>
49
- <td>
50
- <p class="description"><?php echo $strings[ 'cant_remove_admins' ]; ?></p>
51
- </td>
52
- <?php endif; ?>
53
-
54
- <?php else : ?>
55
-
56
- <?php if ( $is_my_user_profile ) : ?>
57
- <tr>
58
- <th><label for="<?php echo $data[ 'otp_field_name' ]; ?>"><?php echo $strings[ 'label_enter_otp' ]; ?></label></th>
59
- <td>
60
- <input class="regular-text"
61
- type="text"
62
- id="<?php echo $data[ 'otp_field_name' ]; ?>"
63
- name="<?php echo $data[ 'otp_field_name' ]; ?>"
64
- value="" autocomplete="off" />
65
- <p class="description">
66
- <?php echo $strings[ 'description_otp' ]; ?>
67
- <br /><?php echo $strings[ 'description_otp_ext' ]; ?>
68
- </p>
69
- </td>
70
- </tr>
71
- <?php else : ?>
72
- <td>
73
- <p class="description"><?php echo $strings[ 'cant_add_other_user' ]; ?></p>
74
- </td>
75
- <?php endif; ?>
76
-
77
- <?php endif; ?>
78
-
79
- </tbody>
80
- </table>
81
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
templates/twig/notices/wphashes-token-fail.twig ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ {% extends "/notices/base-error.twig" %}
2
+
3
+ {% block notice_body %}
4
+ {% for msg in strings.messages %}
5
+ <p>{{ msg }}</p>
6
+ {% endfor %}
7
+ {% endblock %}
templates/twig/pages/login_intent/index.twig CHANGED
@@ -6,21 +6,10 @@
6
  body {
7
  background: #ffffff;
8
  }
9
- .message {
10
- padding: 15px;
11
- margin-bottom: 30px;
12
- }
13
- .submit.form-group {
14
- margin-top: 25px;
15
- }
16
  .input-group-addon a {
17
  font-weight: bold;
18
  display: block;
19
  }
20
- a.input-help {
21
- display: inline-block;
22
- padding: 0 0.5rem;
23
- }
24
  #countdown {
25
  font-weight: bolder;
26
  }
@@ -32,51 +21,9 @@
32
  margin: 30px 0;
33
  text-decoration: underline;
34
  }
35
- #skip_mfa {
36
- margin: 10px 10px 5px 20px;
37
- }
38
  </style>
39
  {% endblock %}
40
 
41
- {% block head_inline_scripts %}
42
-
43
- <script type="text/javascript">
44
- // Set the date we're counting down to
45
- var timeRemaining = {{ data.time_remaining }};
46
- // Update the count down every 1 second
47
- var x = setInterval( function () {
48
- timeRemaining -= 1;
49
- var timeRemainingText = '';
50
- if ( timeRemaining < 0 ) {
51
- timeRemainingText = '{{ strings.login_expired }}';
52
- clearInterval( x );
53
- loginExpired();
54
- }
55
- else {
56
- var minutes = Math.floor( timeRemaining / 60 );
57
- var seconds = Math.floor( timeRemaining % 60 );
58
- if ( minutes > 0 ) {
59
- timeRemainingText = minutes + " minutes and " + seconds
60
- + " {{ strings.seconds }}";
61
- }
62
- else {
63
- timeRemainingText = timeRemaining.toFixed( 0 )
64
- + " {{ strings.seconds }}";
65
- }
66
- }
67
- document.getElementById( "countdown" ).innerHTML = timeRemainingText;
68
- },
69
- 1000
70
- );
71
-
72
- function loginExpired() {
73
- document.getElementById( "mainSubmit" ).setAttribute( 'disabled', 'disabled' );
74
- document.getElementById( "TimeRemaining" ).className = "text-center alert alert-danger";
75
- }
76
- </script>
77
- {% endblock %}
78
-
79
-
80
  {% block body_content_header %}
81
  <div class="row">
82
  <div class="col-8 offset-2 col-md-6 offset-md-3 text-center">
@@ -88,80 +35,7 @@
88
 
89
  <div class="row">
90
  <div class="col-12 col-md-8 offset-md-2 col-lg-6 offset-lg-3">
91
-
92
- <div class="alert alert-{{ data.message_type }}" role="alert">{{ strings.message }}</div>
93
-
94
- <form action="{{ hrefs.form_action }}" method="post" class="form-horizontal">
95
- <input type="hidden" name="{{ data.login_intent_flag }}" value="1" />
96
- {% if not hrefs.redirect_to is empty %}
97
- <input type="hidden" name="redirect_to" value="{{ hrefs.redirect_to }}" />
98
- {% endif %}
99
- {% if not hrefs.redirect_to is empty %}
100
- <input type="hidden" name="cancel_href" value="{{ hrefs.cancel_href }}" />
101
- {% endif %}
102
-
103
- {% for key_field, aField in data.login_fields %}
104
- <div class="form-row">
105
- <div class="form-group col">
106
- <label for="{{ aField.name }}">{{ aField.text }}</label>
107
- <div class="input-group">
108
- <input type="{{ aField.type }}"
109
- name="{{ aField.name }}"
110
- value="{{ aField.value }}"
111
- class="form-control"
112
- id="{{ aField.name }}"
113
- placeholder="{{ aField.placeholder }}"
114
- autocomplete="off"
115
- {% if key_field == 0 %}autofocus{% endif %}
116
- />
117
-
118
- {% if flags.show_branded_links %}
119
- <div class="input-group-append">
120
- <div class="input-group-text">
121
- <a href="{{ aField.help_link }}"
122
- target="_blank" class="input-help">&quest;</a>
123
- </div>
124
- </div>
125
- {% endif %}
126
- </div>
127
- </div>
128
- </div>
129
-
130
- {% endfor %}
131
-
132
- {% if flags.can_skip_mfa %}
133
- <div class="form-row">
134
- <div class="form-group mb-0">
135
- <div class="input-group">
136
- <label for="skip_mfa">
137
- <input type="checkbox" value="Y" name="skip_mfa" id="skip_mfa">
138
- {{ strings.skip_mfa }}
139
- </label>
140
- </div>
141
- </div>
142
- </div>
143
- {% endif %}
144
-
145
- <div class="form-group row submit">
146
- <div class="col-6 order-2 text-right">
147
- <button type="submit" id="mainSubmit" class="pull-right btn btn-success">
148
- {{ strings.verify_my_login }}</button>
149
- </div>
150
- <div class="col-6 order-1 text-left">
151
- <button class="btn btn-outline-danger" name="cancel" value="1">
152
- &larr; {{ strings.cancel }}</button>
153
- </div>
154
- </div>
155
- </form>
156
-
157
- <div class="row">
158
- <div class="col">
159
- <p id="TimeRemaining" class="text-center alert alert-warning">
160
- {{ strings.time_remaining }}:
161
- <span id="countdown">{{ strings.calculating }}</span>
162
- </p>
163
- </div>
164
- </div>
165
  </div>
166
  </div>
167
  {% endblock %}
6
  body {
7
  background: #ffffff;
8
  }
 
 
 
 
 
 
 
9
  .input-group-addon a {
10
  font-weight: bold;
11
  display: block;
12
  }
 
 
 
 
13
  #countdown {
14
  font-weight: bolder;
15
  }
21
  margin: 30px 0;
22
  text-decoration: underline;
23
  }
 
 
 
24
  </style>
25
  {% endblock %}
26
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  {% block body_content_header %}
28
  <div class="row">
29
  <div class="col-8 offset-2 col-md-6 offset-md-3 text-center">
35
 
36
  <div class="row">
37
  <div class="col-12 col-md-8 offset-md-2 col-lg-6 offset-lg-3">
38
+ {{ content.form|raw }}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  </div>
40
  </div>
41
  {% endblock %}
templates/twig/snippets/login_intent/form.twig ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <style>
2
+ .message {
3
+ padding: 15px;
4
+ margin-bottom: 30px;
5
+ }
6
+ .submit.form-group {
7
+ margin-top: 25px;
8
+ }
9
+ .input-group-addon a {
10
+ font-weight: bold;
11
+ display: block;
12
+ }
13
+ a.input-help {
14
+ display: inline-block;
15
+ padding: 0 0.5rem;
16
+ }
17
+ #countdown {
18
+ font-weight: bolder;
19
+ }
20
+ #TimeRemaining {
21
+ margin-top: 30px;
22
+ padding: 10px;
23
+ }
24
+ #skip_mfa {
25
+ margin: 10px 10px 5px 20px;
26
+ }
27
+ </style>
28
+
29
+ <div class="alert alert-{{ data.message_type }}" role="alert">{{ strings.message }}</div>
30
+
31
+ <form action="{{ hrefs.form_action }}" method="post" class="form-horizontal">
32
+ <input type="hidden" name="{{ data.login_intent_flag }}" value="1" />
33
+ {% if not hrefs.redirect_to is empty %}
34
+ <input type="hidden" name="redirect_to" value="{{ hrefs.redirect_to }}" />
35
+ {% endif %}
36
+ {% if not hrefs.redirect_to is empty %}
37
+ <input type="hidden" name="cancel_href" value="{{ hrefs.cancel_href }}" />
38
+ {% endif %}
39
+
40
+ {% for key_field, aField in data.login_fields %}
41
+ <div class="form-row">
42
+ <div class="form-group col">
43
+ <label for="{{ aField.name }}">{{ aField.text }}</label>
44
+ <div class="input-group">
45
+ <input type="{{ aField.type }}"
46
+ name="{{ aField.name }}"
47
+ value="{{ aField.value }}"
48
+ class="form-control"
49
+ id="{{ aField.name }}"
50
+ placeholder="{{ aField.placeholder }}"
51
+ autocomplete="off"
52
+ {% if key_field == 0 %}autofocus{% endif %}
53
+ />
54
+
55
+ {% if flags.show_branded_links %}
56
+ <div class="input-group-append">
57
+ <div class="input-group-text">
58
+ <a href="{{ aField.help_link }}"
59
+ target="_blank" class="input-help">&quest;</a>
60
+ </div>
61
+ </div>
62
+ {% endif %}
63
+ </div>
64
+ </div>
65
+ </div>
66
+
67
+ {% endfor %}
68
+
69
+ {% if flags.can_skip_mfa %}
70
+ <div class="form-row">
71
+ <div class="form-group mb-0">
72
+ <div class="input-group">
73
+ <label for="skip_mfa">
74
+ <input type="checkbox" value="Y" name="skip_mfa" id="skip_mfa">
75
+ {{ strings.skip_mfa }}
76
+ </label>
77
+ </div>
78
+ </div>
79
+ </div>
80
+ {% endif %}
81
+
82
+ <div class="form-group row submit">
83
+ <div class="col-6 order-2 text-right">
84
+ <button type="submit" id="mainSubmit" class="pull-right btn btn-success">
85
+ {{ strings.verify_my_login }}</button>
86
+ </div>
87
+ <div class="col-6 order-1 text-left">
88
+ <button class="btn btn-outline-danger" name="cancel" value="1">
89
+ &larr; {{ strings.cancel }}</button>
90
+ </div>
91
+ </div>
92
+ </form>
93
+
94
+ <div class="row">
95
+ <div class="col">
96
+ <p id="TimeRemaining" class="text-center alert alert-warning">
97
+ {{ strings.time_remaining }}:
98
+ <span id="countdown">{{ strings.calculating }}</span>
99
+ </p>
100
+ </div>
101
+ </div>
102
+
103
+ <script type="text/javascript">
104
+ // Set the date we're counting down to
105
+ var timeRemaining = {{ data.time_remaining }};
106
+ // Update the count down every 1 second
107
+ var x = setInterval( function () {
108
+ timeRemaining -= 1;
109
+ var timeRemainingText = '';
110
+ if ( timeRemaining < 0 ) {
111
+ timeRemainingText = '{{ strings.login_expired }}';
112
+ clearInterval( x );
113
+ loginExpired();
114
+ }
115
+ else {
116
+ var minutes = Math.floor( timeRemaining / 60 );
117
+ var seconds = Math.floor( timeRemaining % 60 );
118
+ if ( minutes > 0 ) {
119
+ timeRemainingText = minutes + " minutes and " + seconds
120
+ + " {{ strings.seconds }}";
121
+ }
122
+ else {
123
+ timeRemainingText = timeRemaining.toFixed( 0 )
124
+ + " {{ strings.seconds }}";
125
+ }
126
+ }
127
+ document.getElementById( "countdown" ).innerHTML = timeRemainingText;
128
+ },
129
+ 1000
130
+ );
131
+
132
+ function loginExpired() {
133
+ document.getElementById( "mainSubmit" ).setAttribute( 'disabled', 'disabled' );
134
+ document.getElementById( "TimeRemaining" ).className = "text-center alert alert-danger";
135
+ }
136
+ </script>
templates/twig/snippets/user/profile/mfa/mfa_backup.twig ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <tr>
2
+ <th><label for="shield_backup_code">{{ strings.label_enter_code }}</label></th>
3
+ <td>
4
+ <a href="#" id="IcwpWpsfGenBackupLoginCode"
5
+ class="button button-primary">{{ strings.button_gen_code }}</a>
6
+ {% if flags.has_validated_profile %}
7
+ <a href="#" id="IcwpWpsfDelBackupLoginCode"
8
+ class="button">{{ strings.button_del_code }}</a>
9
+ {% endif %}
10
+ <p class="description">
11
+ {{ strings.description_code }}
12
+ <br /><strong>{{ strings.description_code_ext1 }}</strong>
13
+ {% if flags.has_validated_profile %}
14
+ <br />{{ strings.description_code_ext2 }}
15
+ {% endif %}
16
+ </p>
17
+ </td>
18
+ </tr>
templates/twig/snippets/user/profile/mfa/mfa_container.twig ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
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>
templates/twig/snippets/user/profile/mfa/mfa_email.twig ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <tr>
2
+ <th><label for="shield_enable_mfaemail">{{ strings.label_email_authentication }}</label></th>
3
+ <td>
4
+ <input type="checkbox" name="shield_enable_mfaemail" id="shield_enable_mfaemail" value="Y"
5
+ {% if flags.is_profile_active %}checked="checked"{% endif %}
6
+ {% if flags.is_enforced %}disabled="disabled"{% endif %}
7
+ />
8
+ <p class="description">{{ strings.description_email_authentication_checkbox }}</p>
9
+ {% if flags.is_enforced %}
10
+ <p class="description">{{ strings.is_enforced }}</p>
11
+ {% endif %}
12
+ </td>
13
+ </tr>
templates/twig/snippets/user/profile/mfa/mfa_ga.twig ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <style type="text/css">
2
+ #shield_ga_secret {
3
+ letter-spacing: 5px;
4
+ font-family: monospace;
5
+ font-size: 24px;
6
+ text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.4);
7
+ border: 1px solid rgba(0, 0, 0, 0.1);
8
+ padding: 0 7px;
9
+ background-color: whitesmoke;
10
+ }
11
+ </style>
12
+
13
+ {% if flags.is_profile_active %}
14
+
15
+ {% if (flags.is_my_user_profile or flags.i_am_valid_admin) %}
16
+ <tr>
17
+ <th><label for="shield_turn_off_ga">{{ strings.label_check_to_remove }}</label></th>
18
+ <td>
19
+ <input type="checkbox" name="shield_turn_off_ga" id="shield_turn_off_ga" value="Y" />
20
+ <p class="description">{{ strings.desc_remove }}</p>
21
+ </td>
22
+ </tr>
23
+ {% endif %}
24
+
25
+ {% else %}
26
+
27
+ {% if flags.is_my_user_profile %}
28
+ <tr>
29
+ <th><label for="{{ vars.otp_field_name }}">{{ strings.title }}</label></th>
30
+ <td>
31
+ <div style="width: 350px; margin-bottom: 15px">
32
+ <img src="{{ hrefs.src_chart_url }}" alt="{{ strings.description_chart_url }}"
33
+ title="{{ strings.description_chart_url }}"
34
+ style="display:block;margin:0 auto 10px" />
35
+ <div style="margin: auto;width: fit-content;text-align: center;"
36
+ id="shield_ga_secret">{{ vars.ga_secret }}</div>
37
+ </div>
38
+
39
+ <input class="regular-text"
40
+ type="text"
41
+ id="{{ vars.otp_field_name }}"
42
+ name="{{ vars.otp_field_name }}"
43
+ placeholder="{{ strings.enter_auth_app_code }}"
44
+ value="" autocomplete="off" />
45
+ <p class="description">
46
+ {{ strings.description_chart_url }}
47
+ </p>
48
+ <p class="description">
49
+ {{ strings.description_ga_secret }}
50
+ </p>
51
+ </td>
52
+ </tr>
53
+ {% endif %}
54
+
55
+ {% endif %}
templates/twig/snippets/user/profile/mfa/mfa_yubikey.twig ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% if (flags.is_my_user_profile or flags.i_am_valid_admin) %}
2
+ <tr>
3
+ <th><label for="{{ vars.otp_field_name }}">{{ strings.title }}</label></th>
4
+ <td>
5
+ {% if flags.is_profile_active %}
6
+ <p>{{ strings.current_yubi_ids }}</p>
7
+ <ul style=" list-style: circle inside; ">
8
+ {% for yubi_id in vars.yubi_ids %}
9
+ <li><code>{{ yubi_id }}</code></li>
10
+ {% endfor %}
11
+ </ul>
12
+ {% else %}
13
+ <p>{{ strings.no_active_yubi_ids }}</p>
14
+ {% endif %}
15
+
16
+ <p style="margin-bottom: 5px">{{ strings.enter_otp }}</p>
17
+ <input class="regular-text"
18
+ type="text"
19
+ id="{{ vars.otp_field_name }}"
20
+ name="{{ vars.otp_field_name }}"
21
+ value="" autocomplete="off" />
22
+ {% if flags.is_profile_active %}
23
+ <p class="description">
24
+ {{ strings.to_remove_device }}
25
+ </p>
26
+ {% endif %}
27
+ <p class="description">
28
+ {{ strings.multiple_for_pro }}
29
+ </p>
30
+ </td>
31
+ </tr>
32
+ {% else %}
33
+ <td>
34
+ <p class="description">{{ strings.cant_remove_admins }}</p>
35
+ </td>
36
+ {% endif %}
templates/twig/wpadmin_pages/insights/license/license.twig CHANGED
@@ -40,13 +40,18 @@
40
  <h5 class="mb-0">{{ strings.title_license_summary }}</h5>
41
  </div>
42
  <div class="card-body">
 
 
 
43
  <table class="table table-hover table-sm mb-0">
44
  <tbody>
45
  {% for license_key, license_val in vars.license_table %}
46
- <tr>
47
- <th scope="row">{{ attribute(strings, license_key) }}:</th>
48
- <td class="">{{ license_val|raw }}</td>
49
- </tr>
 
 
50
  {% endfor %}
51
  </tbody>
52
  </table>
@@ -128,7 +133,15 @@
128
  <div id="collone" class="collapse show" aria-labelledby="headingOne"
129
  data-parent="#accordion">
130
  <div class="card-body">
 
 
131
  <dl>
 
 
 
 
 
 
132
  <dt>Plugin and Theme Vulnerability Scanner</dt>
133
  <dd>Alerts to plugin/theme vulnerabilities.
134
  Shield can then automatically upgrade as updates become available.
40
  <h5 class="mb-0">{{ strings.title_license_summary }}</h5>
41
  </div>
42
  <div class="card-body">
43
+ {% if flags.has_error %}
44
+ <div class="alert alert-warning mb-0">{{ vars.error }}</div>
45
+ {% endif %}
46
  <table class="table table-hover table-sm mb-0">
47
  <tbody>
48
  {% for license_key, license_val in vars.license_table %}
49
+ {% if license_val is not empty %}
50
+ <tr>
51
+ <th scope="row">{{ attribute(strings, license_key) }}:</th>
52
+ <td class="">{{ license_val|raw }}</td>
53
+ </tr>
54
+ {% endif %}
55
  {% endfor %}
56
  </tbody>
57
  </table>
133
  <div id="collone" class="collapse show" aria-labelledby="headingOne"
134
  data-parent="#accordion">
135
  <div class="card-body">
136
+ <p><a href="https://shsec.io/gp" target="_blank" class="btn btn-success">
137
+ See All PRO Features and Extras &nearr;</a></p>
138
  <dl>
139
+ <dt>Powerful, Auto-Learning Malware Scanner</dt>
140
+ <dd>Detects common and uncommon malware patterns in PHP files and alerts you immediately.
141
+ <br/>With ShieldNET crowd-sourcing intelligence, Shield automatically hides false-positives
142
+ so you can focus on risks that matter, and can ignore the noise that wastes your time.
143
+ </dd>
144
+
145
  <dt>Plugin and Theme Vulnerability Scanner</dt>
146
  <dd>Alerts to plugin/theme vulnerabilities.
147
  Shield can then automatically upgrade as updates become available.
templates/twig/wpadmin_pages/insights/traffic/index.twig CHANGED
@@ -4,11 +4,13 @@
4
  <div class="row ">
5
  <div class="col-12 insights_section">
6
  {% if flags.can_traffic %}
7
- {% if flags.is_enabled %}
8
- {% include '/wpadmin_pages/insights/traffic/traffic_table.twig' %}
9
- {% else %}
10
- {% include '/wpadmin_pages/insights/traffic/traffic_disabled.twig' %}
 
11
  {% endif %}
 
12
  {% else %}
13
  {% include '/wpadmin_pages/insights/common/feature_unavailable.twig' %}
14
  {% endif %}
4
  <div class="row ">
5
  <div class="col-12 insights_section">
6
  {% if flags.can_traffic %}
7
+ {% if not flags.is_enabled %}
8
+ <div class="alert alert-info">
9
+ <h6 class="alert-heading">{{ strings.not_enabled }}</h6>
10
+ <p class="m-0"><a class="alert-link" href="{{ hrefs.please_enable }}">{{ strings.please_enable }}</a></p>
11
+ </div>
12
  {% endif %}
13
+ {% include '/wpadmin_pages/insights/traffic/traffic_table.twig' %}
14
  {% else %}
15
  {% include '/wpadmin_pages/insights/common/feature_unavailable.twig' %}
16
  {% endif %}