Shield Security for WordPress - Version 14.1.0

Version Description

Download this release

Release Info

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

Code changes from version 14.0.3 to 14.1.0

Files changed (215) hide show
  1. cl.json +356 -203
  2. config/admin_access_restriction.json +14 -0
  3. config/audit_trail.json +61 -21
  4. config/data.json +32 -5
  5. config/deprecated/license.php +0 -1
  6. config/hack_protect.json +12 -0
  7. config/ips.json +14 -0
  8. config/license.json +10 -1
  9. config/plugin.json +16 -0
  10. config/user_management.json +0 -7
  11. icwp-wpsf.php +1 -1
  12. languages/wp-simple-firewall-nl_NL.mo +0 -0
  13. plugin-spec.php +18 -12
  14. plugin.json +18 -12
  15. readme.txt +1 -1
  16. resources/css/global-plugin.css +6 -1
  17. resources/js/shield/audit_trail.js +9 -3
  18. resources/js/shield/traffic.js +9 -3
  19. src/lib/src/Controller/Admin/AdminBarMenu.php +31 -19
  20. src/lib/src/Controller/Assets/Enqueue.php +29 -0
  21. src/lib/src/Controller/Config/ConfigVO.php +1 -2
  22. src/lib/src/Controller/Controller.php +52 -39
  23. src/lib/src/Databases/IPs/CommonFilters.php +3 -3
  24. src/lib/src/Databases/IPs/EntryVO.php +0 -1
  25. src/lib/src/Databases/IPs/Select.php +1 -1
  26. src/lib/src/Logging/Processors/RequestMetaProcessor.php +39 -8
  27. src/lib/src/Modules/AuditTrail/Auditors/Plugins.php +15 -0
  28. src/lib/src/Modules/AuditTrail/Auditors/Themes.php +15 -0
  29. src/lib/src/Modules/AuditTrail/Auditors/Users.php +43 -0
  30. src/lib/src/Modules/AuditTrail/DB/LoadLogs.php +70 -24
  31. src/lib/src/Modules/AuditTrail/Lib/LogTable/BuildAuditTableData.php +195 -0
  32. src/lib/src/Modules/AuditTrail/Lib/LogTable/BuildSearchPanesData.php +75 -0
  33. src/lib/src/Modules/AuditTrail/Lib/LogTable/DelegateAjaxHandler.php +4 -8
  34. src/lib/src/Modules/AuditTrail/Lib/LogTable/LoadRawTableData.php +27 -13
  35. src/lib/src/Modules/AuditTrail/ModCon.php +1 -1
  36. src/lib/src/Modules/AuditTrail/Processor.php +11 -13
  37. src/lib/src/Modules/AuditTrail/Strings.php +68 -26
  38. src/lib/src/Modules/Base/AdminNotices.php +1 -1
  39. src/lib/src/Modules/Base/Lib/Rest/Request/Process.php +0 -138
  40. src/lib/src/Modules/Base/Lib/Rest/Request/RequestVO.php +0 -16
  41. src/lib/src/Modules/Base/Lib/Rest/Route/RouteBase.php +0 -254
  42. src/lib/src/Modules/Base/Lib/Rest/Route/RouteCache.php +0 -45
  43. src/lib/src/Modules/Base/Lib/Rest/Utility/PreChecks.php +0 -33
  44. src/lib/src/Modules/Base/Lib/Rest/Utility/RestLocker.php +0 -64
  45. src/lib/src/Modules/Base/ModCon.php +33 -35
  46. src/lib/src/Modules/Base/Options.php +2 -17
  47. src/lib/src/Modules/Base/Options/OptValueSanitize.php +2 -3
  48. src/lib/src/Modules/Base/Options/Storage.php +0 -2
  49. src/lib/src/Modules/Base/Processor.php +7 -1
  50. src/lib/src/Modules/Base/Reporting.php +3 -3
  51. src/lib/src/Modules/Base/Rest.php +37 -0
  52. src/lib/src/Modules/Base/Rest/Request/Process.php +26 -0
  53. src/lib/src/Modules/Base/Rest/Request/RequestVO.php +38 -0
  54. src/lib/src/Modules/Base/{Lib/Rest → Rest}/RequestVoConsumer.php +2 -2
  55. src/lib/src/Modules/Base/Rest/Route/RouteBase.php +31 -0
  56. src/lib/src/Modules/Base/Rest/Route/RouteCache.php +10 -0
  57. src/lib/src/Modules/Base/RestHandler.php +0 -66
  58. src/lib/src/Modules/Base/Strings.php +0 -2
  59. src/lib/src/Modules/Data/DB/IPs/IPRecords.php +4 -3
  60. src/lib/src/Modules/Data/DB/IPs/Ops/Insert.php +1 -1
  61. src/lib/src/Modules/Data/DB/ReqLogs/GetRequestMeta.php +12 -1
  62. src/lib/src/Modules/Data/DB/ReqLogs/LoadLogs.php +65 -11
  63. src/lib/src/Modules/Data/DB/ReqLogs/LogRecord.php +1 -3
  64. src/lib/src/Modules/Data/DB/ReqLogs/Ops/Handler.php +26 -0
  65. src/lib/src/Modules/Data/DB/ReqLogs/Ops/Record.php +21 -0
  66. src/lib/src/Modules/Data/Lib/UpgradeReqLogsTable.php +109 -0
  67. src/lib/src/Modules/Data/Upgrade.php +15 -0
  68. src/lib/src/Modules/Firewall/Lib/Scan/Checks/Standard.php +1 -2
  69. src/lib/src/Modules/Firewall/Lib/Scan/Handlers/Base.php +3 -3
  70. src/lib/src/Modules/HackGuard/Lib/Snapshots/StoreAction/BaseBulk.php +0 -13
  71. src/lib/src/Modules/HackGuard/Lib/Snapshots/StoreAction/CleanAll.php +0 -29
  72. src/lib/src/Modules/HackGuard/Lib/Snapshots/StoreAction/ScheduleBuildAll.php +1 -4
  73. src/lib/src/Modules/HackGuard/ModCon.php +0 -7
  74. src/lib/src/Modules/HackGuard/Processor.php +26 -0
  75. src/lib/src/Modules/HackGuard/Rest.php +20 -0
  76. src/lib/src/Modules/HackGuard/Rest/Request/Base.php +44 -0
  77. src/lib/src/Modules/HackGuard/Rest/Request/RequestVO.php +30 -0
  78. src/lib/src/Modules/HackGuard/Rest/Request/Results/GetAll.php +75 -0
  79. src/lib/src/Modules/HackGuard/Rest/Request/Scans/Base.php +7 -0
  80. src/lib/src/Modules/HackGuard/Rest/Request/Scans/Start.php +23 -0
  81. src/lib/src/Modules/HackGuard/Rest/Request/Scans/Status.php +10 -0
  82. src/lib/src/Modules/HackGuard/Rest/Route/Base.php +76 -0
  83. src/lib/src/Modules/HackGuard/Rest/Route/Results/GetAll.php +36 -0
  84. src/lib/src/Modules/HackGuard/Rest/Route/Scans/ScansBase.php +12 -0
  85. src/lib/src/Modules/HackGuard/Rest/Route/Scans/Start.php +20 -0
  86. src/lib/src/Modules/HackGuard/Rest/Route/Scans/Status.php +12 -0
  87. src/lib/src/Modules/HackGuard/Scan/Controller/Afs.php +9 -2
  88. src/lib/src/Modules/HackGuard/Scan/Controller/Apc.php +10 -2
  89. src/lib/src/Modules/HackGuard/Scan/Controller/Base.php +8 -2
  90. src/lib/src/Modules/HackGuard/Scan/Controller/Wpv.php +8 -1
  91. src/lib/src/Modules/HackGuard/Scan/ScansController.php +6 -0
  92. src/lib/src/Modules/IPs/Components/QueryIpBlock.php +3 -3
  93. src/lib/src/Modules/IPs/Lib/Bots/NotBot/InsertNotBotJs.php +1 -11
  94. src/lib/src/Modules/IPs/Lib/Bots/NotBot/NotBotHandler.php +9 -0
  95. src/lib/src/Modules/IPs/Lib/IpAnalyse/BuildDisplay.php +22 -22
  96. src/lib/src/Modules/IPs/Lib/Ops/RetrieveIpsForLists.php +25 -25
  97. src/lib/src/Modules/IPs/Processor.php +53 -0
  98. src/lib/src/Modules/IPs/Rest.php +22 -0
  99. src/lib/src/Modules/IPs/Rest/Exceptions/NotIpAddressException.php +9 -0
  100. src/lib/src/Modules/IPs/Rest/Request/IPs/Base.php +41 -0
  101. src/lib/src/Modules/IPs/Rest/Request/IPs/GetIP.php +106 -0
  102. src/lib/src/Modules/IPs/Rest/Request/IPs/RequestVO.php +10 -0
  103. src/lib/src/Modules/IPs/Rest/Request/Lists/AddIP.php +33 -0
  104. src/lib/src/Modules/IPs/Rest/Request/Lists/Base.php +41 -0
  105. src/lib/src/Modules/IPs/Rest/Request/Lists/GetList.php +26 -0
  106. src/lib/src/Modules/IPs/Rest/Request/Lists/GetListIP.php +13 -0
  107. src/lib/src/Modules/IPs/Rest/Route/Base.php +50 -0
  108. src/lib/src/Modules/IPs/Rest/Route/IPs/GetIP.php +22 -0
  109. src/lib/src/Modules/IPs/Rest/Route/IPs/IPsBase.php +22 -0
  110. src/lib/src/Modules/IPs/Rest/Route/Lists/AddIP.php +30 -0
  111. src/lib/src/Modules/IPs/Rest/Route/Lists/GetList.php +22 -0
  112. src/lib/src/Modules/IPs/Rest/Route/Lists/GetListIP.php +23 -0
  113. src/lib/src/Modules/IPs/Rest/Route/Lists/ListsBase.php +34 -0
  114. src/lib/src/Modules/IPs/Strings.php +1 -1
  115. src/lib/src/Modules/Insights/ModCon.php +9 -1
  116. src/lib/src/Modules/License/AjaxHandler.php +12 -21
  117. src/lib/src/Modules/License/Lib/LookupRequest.php +0 -1
  118. src/lib/src/Modules/License/Rest.php +18 -0
  119. src/lib/src/Modules/License/Rest/Request/Base.php +32 -0
  120. src/lib/src/Modules/License/Rest/Request/LicenseCheck.php +15 -0
  121. src/lib/src/Modules/License/Rest/Request/LicenseStatus.php +10 -0
  122. src/lib/src/Modules/License/Rest/Request/RequestVO.php +20 -0
  123. src/lib/src/Modules/License/Rest/Route/Base.php +23 -0
  124. src/lib/src/Modules/License/Rest/Route/LicenseCheck.php +14 -0
  125. src/lib/src/Modules/License/Rest/Route/LicenseStatus.php +12 -0
  126. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/MfaProfilesController.php +0 -6
  127. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/BaseProvider.php +0 -7
  128. src/lib/src/Modules/LoginGuard/ModCon.php +0 -8
  129. src/lib/src/Modules/Plugin/Debug.php +7 -1
  130. src/lib/src/Modules/Plugin/Lib/Debug/Collate.php +1 -3
  131. src/lib/src/Modules/Plugin/Lib/ImportExport/Export.php +25 -12
  132. src/lib/src/Modules/Plugin/Lib/Ops/ResetPlugin.php +1 -5
  133. src/lib/src/Modules/Plugin/Lib/Ops/VerifyDatabaseIntegrity.php +91 -0
  134. src/lib/src/Modules/Plugin/Lib/OverrideLocale.php +0 -4
  135. src/lib/src/Modules/Plugin/Lib/TourManager.php +0 -4
  136. src/lib/src/Modules/Plugin/Options.php +2 -1
  137. src/lib/src/Modules/Plugin/Rest.php +21 -0
  138. src/lib/src/Modules/Plugin/Rest/Exceptions/OptionDoesNotExistException.php +9 -0
  139. src/lib/src/Modules/Plugin/Rest/Request/Debug/Retrieve.php +15 -0
  140. src/lib/src/Modules/Plugin/Rest/Request/Options/Base.php +50 -0
  141. src/lib/src/Modules/Plugin/Rest/Request/Options/GetAll.php +13 -0
  142. src/lib/src/Modules/Plugin/Rest/Request/Options/GetSingle.php +25 -0
  143. src/lib/src/Modules/Plugin/Rest/Request/Options/RequestVO.php +30 -0
  144. src/lib/src/Modules/Plugin/Rest/Request/Options/SetBulk.php +35 -0
  145. src/lib/src/Modules/Plugin/Rest/Request/Options/SetSingle.php +22 -0
  146. src/lib/src/Modules/Plugin/Rest/Route/Debug/Retrieve.php +16 -0
  147. src/lib/src/Modules/Plugin/Rest/Route/Options/Base.php +79 -0
  148. src/lib/src/Modules/Plugin/Rest/Route/Options/BaseBulk.php +24 -0
  149. src/lib/src/Modules/Plugin/Rest/Route/Options/BaseSingle.php +19 -0
  150. src/lib/src/Modules/Plugin/Rest/Route/Options/GetAll.php +12 -0
  151. src/lib/src/Modules/Plugin/Rest/Route/Options/GetSingle.php +12 -0
  152. src/lib/src/Modules/Plugin/Rest/Route/Options/SetBulk.php +31 -0
  153. src/lib/src/Modules/Plugin/Rest/Route/Options/SetSingle.php +20 -0
  154. src/lib/src/Modules/Plugin/Strings.php +14 -14
  155. src/lib/src/Modules/SecurityAdmin/ModCon.php +20 -0
  156. src/lib/src/Modules/SecurityAdmin/Options.php +4 -0
  157. src/lib/src/Modules/SecurityAdmin/Strings.php +63 -54
  158. src/lib/src/Modules/Traffic/Lib/LogHandlers/LocalDbWriter.php +18 -9
  159. src/lib/src/Modules/Traffic/Lib/RequestLogger.php +31 -10
  160. src/lib/src/Modules/Traffic/Lib/TrafficTable/BuildSearchPanesData.php +105 -0
  161. src/lib/src/Modules/Traffic/Lib/TrafficTable/BuildTrafficTableData.php +277 -0
  162. src/lib/src/Modules/Traffic/Lib/TrafficTable/DelegateAjaxHandler.php +10 -8
  163. src/lib/src/Modules/Traffic/Lib/TrafficTable/LoadRawTableData.php +24 -7
  164. src/lib/src/Modules/UserManagement/AjaxHandler.php +7 -8
  165. src/lib/src/Modules/UserManagement/Lib/Suspend/PasswordExpiry.php +0 -7
  166. src/lib/src/Modules/UserManagement/Options.php +0 -12
  167. src/lib/src/Modules/UserManagement/Processor.php +31 -14
  168. src/lib/src/Modules/UserManagement/Upgrade.php +0 -9
  169. src/lib/src/Tables/Build/Ip.php +10 -14
  170. src/lib/src/Tables/Build/Sessions.php +14 -18
  171. src/lib/src/Tables/DataTables/Build/AuditTrail/ForAuditTrail.php +61 -54
  172. src/lib/src/Tables/DataTables/Build/Base.php +15 -9
  173. src/lib/src/Tables/DataTables/Build/Traffic/ForTraffic.php +23 -11
  174. src/lib/src/Tables/DataTables/LoadData/BaseBuildTableData.php +154 -0
  175. src/lib/src/Tables/DataTables/LoadData/BaseLoadTableData.php +89 -1
  176. src/lib/src/Tables/Render/WpCliTable/AuditTrail.php +2 -2
  177. src/lib/src/Tests/RunTests.php +1 -1
  178. src/lib/src/Users/BulkUpdateUserMeta.php +2 -1
  179. src/lib/src/Users/ShieldUserMeta.php +0 -8
  180. src/lib/src/Utilities/AdminNotices/Controller.php +31 -37
  181. src/lib/src/Utilities/MU/.mu-template.txt +24 -0
  182. src/lib/src/Utilities/MU/MUHandler.php +106 -0
  183. src/lib/vendor/composer/ClassLoader.php +109 -14
  184. src/lib/vendor/composer/autoload_classmap.php +82 -14
  185. src/lib/vendor/composer/autoload_real.php +7 -2
  186. src/lib/vendor/composer/autoload_static.php +82 -14
  187. src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Databases/Base/Handler.php +21 -8
  188. src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Databases/Common/CreateTable.php +0 -4
  189. src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Databases/Common/TableReadyCache.php +58 -0
  190. src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Rest/Exceptions/ApiException.php +20 -0
  191. src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Rest/Exceptions/ClientSideException.php +8 -0
  192. src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Rest/Exceptions/CouldNotObtainLockException.php +8 -0
  193. src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Rest/Exceptions/InvalidRequestParametersException.php +8 -0
  194. src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Rest/Exceptions/ServerSideException.php +9 -0
  195. src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Rest/Request/Process.php +167 -0
  196. src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Rest/Request/RequestVO.php +21 -0
  197. src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Rest/RestHandler.php +88 -0
  198. src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Rest/Route/RestRequestConsumer.php +23 -0
  199. src/lib/{src/Modules/Base/Lib → vendor/fernleafsystems/wordpress-plugin-core/src}/Rest/Route/RestRouteConsumer.php +25 -26
  200. src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Rest/Route/RouteBase.php +330 -0
  201. src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Rest/Route/RouteCache.php +52 -0
  202. src/lib/vendor/fernleafsystems/wordpress-services/src/Core/Rest.php +21 -12
  203. src/lib/vendor/fernleafsystems/wordpress-services/src/Core/Users.php +20 -12
  204. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Consumers/WpUserConsumer.php +23 -0
  205. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Iterators/WpUserIterator.php +0 -4
  206. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Base.php +3 -4
  207. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Lookup.php +2 -4
  208. src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Ping.php +3 -16
  209. src/lib/vendor/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php +5 -3
  210. src/lib/vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php +23 -4
  211. templates/twig/wpadmin_pages/insights/ips/ip_analyse/ip_audittrail.twig +5 -2
  212. templates/twig/wpadmin_pages/insights/ips/ip_analyse/ip_info.twig +5 -5
  213. templates/twig/wpadmin_pages/insights/ips/ip_analyse/ip_sessions.twig +8 -2
  214. templates/twig/wpadmin_pages/insights/ips/ip_analyse/ip_traffic.twig +5 -2
  215. templates/twig/wpadmin_pages/insights/scans/modal/code_render.twig +0 -20
cl.json CHANGED
@@ -1,120 +1,234 @@
1
  {
2
- "14.0": {
3
- "version": "14.0",
4
- "released_at": 1643364060,
5
  "hrefs": {
6
- "release": "https://shsec.io/shieldrelease140",
7
- "upgrade": "https://shsec.io/shieldupgradeguide140"
8
  },
9
- "title": "Two-Factor Authentication Overhaul",
10
  "description": [
11
  ],
12
  "items": [
13
  {
14
  "type": "new",
15
- "pro_only": false,
16
- "title": "WP Login Style 2FA Screen",
17
  "description": [
18
- "Users can complete their 2FA login using the UI they're most familiar with."
19
  ]
20
  },
21
  {
22
  "type": "new",
23
- "pro_only": false,
24
- "title": "Custom Redirect For Hide WP Login & Admin",
25
  "description": [
26
- "Rather than display an unfriendly 404 error page for the hidden login page, you can decide to redirect requests to any page you wish."
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  ]
28
  },
29
  {
30
  "type": "new",
31
  "pro_only": false,
32
- "title": "Easier Access To User 2FA Settings with WP Admin Menu",
33
  "description": [
34
- "Users can now update their 2FA account settings from a dedicated WP admin page."
35
  ]
36
  },
37
  {
38
  "type": "new",
39
  "pro_only": false,
40
- "title": "Improved 2FA User Experience",
41
  "description": [
42
- "Smoother, faster, more reliable and more secure 2FA experience."
43
  ]
44
  },
45
  {
46
- "type": "changed",
47
  "pro_only": false,
48
- "title": "Mutli-factor Authentication Removed",
49
  "description": [
50
- "The option to force users to supply ALL two-factor authentication options has been removed."
51
  ]
52
  },
53
  {
54
  "type": "improved",
55
  "pro_only": false,
56
- "title": "Dedicated table for User meta information",
57
  "description": [
58
- "This allows for new filters and better user status on the WP Admin User page."
59
  ]
60
  },
61
  {
62
  "type": "improved",
63
  "pro_only": false,
64
- "title": "Updated Translations - Dutch (thanks J.P.!)",
65
  "description": [
 
66
  ]
67
  },
68
  {
69
  "type": "improved",
70
  "pro_only": false,
71
- "title": "Further page caching mitigation for NotBot",
72
  "description": [
 
73
  ]
74
  },
75
  {
76
- "type": "changed",
77
  "pro_only": false,
78
- "title": "Updated Bootstrap Libraries",
 
 
 
 
 
 
 
 
79
  "description": [
80
  ]
81
  },
82
  {
83
  "type": "fixed",
84
  "pro_only": false,
85
- "title": "Various bugs and errors",
86
  "description": [
87
  ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  },
89
  {
 
 
 
 
90
  "type": "improved",
91
- "title": "Integration with some 3rd party membership plugins + 2FA.",
92
- "description": [],
93
- "patch": "14.0.2"
94
  },
95
  {
96
- "type": "fixed",
97
- "title": "Alert displayed that U2F isn't support when U2F isn't in-use.",
98
- "description": [],
99
- "patch": "14.0.2"
100
  },
101
  {
102
- "type": "fixed",
103
- "title": "A rare issue which Custom MFA login triggering an HTTP 402 error!",
104
- "description": [],
105
- "patch": "14.0.2"
106
  },
107
  {
108
- "type": "fixed",
109
- "title": "Options Search dialog failed to open (can't find-as-you-type yet).",
110
- "description": [],
111
- "patch": "14.0.2"
 
112
  },
113
  {
114
  "type": "fixed",
115
- "title": "Work around WP Engine login mechanism blocking 2FA verification.",
116
- "description": [],
117
- "patch": "14.0.3"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  }
119
  ]
120
  },
@@ -212,105 +326,106 @@
212
  "description": [
213
  "Adding and removing Yubikey devices to and from your WP user profile is more reliable."
214
  ]
215
- },
216
- {
217
- "type": "fixed",
218
- "title": "Reduce scan chunk size to improve MySQL query memory usage.",
219
- "description": [],
220
- "patch": "13.0.1"
221
- },
222
- {
223
- "type": "fixed",
224
- "title": "Automatic selection of IP addresses in IP Analyse tool after switching to AJAX source.",
225
- "description": [],
226
- "patch": "13.0.1"
227
- },
228
- {
229
- "type": "fixed",
230
- "title": "Ensure database states are handled correctly.",
231
- "description": [],
232
- "patch": "13.0.3"
233
- },
234
- {
235
- "type": "fixed",
236
- "title": "MySQL requirements are checked more flexibly.",
237
- "description": [],
238
- "patch": "13.0.3"
239
- },
240
- {
241
- "type": "fixed",
242
- "title": "Add a class to Google Authenticator QR image.",
243
- "description": [],
244
- "patch": "13.0.3"
245
- },
246
- {
247
- "type": "fixed",
248
- "title": "Error with MainWP loading in certain cases.",
249
- "description": [],
250
- "patch": "13.0.4"
251
- },
252
- {
253
- "type": "improved",
254
- "title": "Options to provide custom roles for Email 2FA enforcement is now free-form.",
255
- "description": [],
256
- "patch": "13.0.5"
257
- },
258
- {
259
- "type": "improved",
260
- "title": "Multi-factor authentication settings are available even when your IP is on the bypass lists.",
261
- "description": [],
262
- "patch": "13.0.5"
263
- },
264
- {
265
- "type": "improved",
266
- "title": "ShieldPRO license lookups when using separate domains for multilingual site versions.",
267
- "description": [],
268
- "patch": "13.0.5"
269
- },
270
- {
271
- "type": "improved",
272
- "title": "FluentForms integration wasn't always loading and so SPAM submissions could still come through.",
273
- "description": [],
274
- "patch": "13.0.5"
275
- },
276
- {
277
- "type": "improved",
278
- "title": "NotBot Javascript is improved to better handle server timeouts and work around Page Caching limitations.",
279
- "description": [],
280
- "patch": "13.0.5"
281
- },
282
- {
283
- "type": "fixed",
284
- "title": "Prevent some fatal errors when integrating with 3rd parties and their data isn't as expected.",
285
- "description": [],
286
- "patch": "13.0.5"
287
- },
288
- {
289
- "type": "improved",
290
- "title": "Improved handling of ClassicPress versions and file scanning for migrated WP sites.",
291
- "description": [],
292
- "patch": "13.0.6"
293
- },
294
- {
295
- "type": "changed",
296
- "title": "Official WP.org themes that are inactive no longer display a warning in results tables.",
297
- "description": [],
298
- "patch": "13.0.6"
299
- },
300
- {
301
- "type": "fixed",
302
- "title": "[Minor Security Vulnerability] An authenticated (administrator+) Persistent XSS.",
303
- "description": [
304
- "Privately disclosed to us by Yoru Oni - thank you."
305
- ],
306
- "href": "https://shsec.io/kh",
307
- "patch": "13.0.6"
308
- },
309
- {
310
- "type": "changed",
311
- "title": "It's now possible to add custom exclusions to the anonymous REST API block.",
312
- "description": [],
313
- "patch": "13.0.6"
 
314
  }
315
  ]
316
  },
@@ -437,48 +552,66 @@
437
  "With this upgrade, the minimum required MySQL database engine is moving to 5.6."
438
  ],
439
  "href": "https://shsec.io/shieldsystemrequirements"
440
- },
441
- {
442
- "type": "fixed",
443
- "title": "Prevent PHP exception being thrown in certain cases.",
444
- "description": [],
445
- "patch": "12.0.4"
446
- },
447
- {
448
- "type": "fixed",
449
- "title": "Ensure Shield runs only on supported MySQL servers.",
450
- "description": [],
451
- "patch": "12.0.8"
452
- },
453
  {
454
- "type": "fixed",
455
- "title": "Error when processing certain types of query strings in the firewall.",
456
- "description": [],
457
- "patch": "12.0.9"
 
 
 
 
458
  },
459
  {
460
- "type": "fixed",
461
- "title": "Yubikey 2FA verification was failing with a nonce less than 16 characters. Who knew?",
462
- "description": [],
463
- "patch": "12.0.9"
 
 
 
 
464
  },
465
  {
466
- "type": "fixed",
467
- "title": "A few minor fixes, along with slight optimisation of NotBot JS.",
468
- "description": [],
469
- "patch": "12.0.11"
 
 
 
 
 
 
 
 
470
  },
471
  {
472
- "type": "fixed",
473
- "title": "Issue with managing Shield Central profiles.",
474
- "description": [],
475
- "patch": "12.0.11"
 
 
 
 
 
 
 
 
476
  },
477
  {
478
- "type": "improved",
479
- "title": "Improve support for auto-login systems like ManageWP admin login.",
480
- "description": [],
481
- "patch": "12.0.13"
 
 
 
 
482
  }
483
  ]
484
  },
@@ -582,42 +715,62 @@
582
  "type": "improved",
583
  "title": "Improved support and fixes for PHP 8 and WordPress 5.8.",
584
  "description": []
585
- },
586
- {
587
- "type": "improved",
588
- "title": "Prevent overloading ShieldNET API in some cases.",
589
- "description": [],
590
- "patch": "11.5.1"
591
- },
592
  {
593
- "type": "improved",
594
- "title": "Add some limited details into the Audit Trail entries for scan results.",
595
- "description": [],
596
- "patch": "11.5.2"
 
 
 
 
597
  },
598
  {
599
- "type": "fixed",
600
- "title": "Plugin/Theme scanning could result in large quantities of unrecognised files.",
601
- "description": [],
602
- "patch": "11.5.3"
 
 
 
 
603
  },
604
  {
605
- "type": "improved",
606
- "title": "Scan results were being reported, but not displayed in results tables in some cases.",
607
- "description": [],
608
- "patch": "11.5.4"
 
 
 
 
609
  },
610
  {
611
- "type": "fixed",
612
- "title": "Scan results wouldn't be updated after scans completed in some cases.",
613
- "description": [],
614
- "patch": "11.5.5"
 
 
 
 
615
  },
616
  {
617
- "type": "fixed",
618
- "title": "Shield would apply login blocks for requests originating from a whitelisted IP addresses.",
619
- "description": [],
620
- "patch": "11.5.5"
 
 
 
 
 
 
 
 
621
  }
622
  ]
623
  },
1
  {
2
+ "14.1": {
3
+ "version": "14.1",
4
+ "released_at": 1647269718,
5
  "hrefs": {
6
+ "release": "https://shsec.io/shieldrelease141",
7
+ "upgrade": "https://shsec.io/shieldupgradeguide141"
8
  },
9
+ "title": "REST API Integrations",
10
  "description": [
11
  ],
12
  "items": [
13
  {
14
  "type": "new",
15
+ "pro_only": true,
16
+ "title": "Complete REST API",
17
  "description": [
18
+ "Partners and developers can now manage the Shield Security plugin completely with the new REST API."
19
  ]
20
  },
21
  {
22
  "type": "new",
23
+ "pro_only": true,
24
+ "title": "REST API Routes",
25
  "description": [
26
+ "New REST API endpoints let you: get/set option(s), get scan results & status, start new scans, add/remove IP addresses.",
27
+ "get/set any single option, or group of options.",
28
+ "get scan results & status, and start new scans and check their status.",
29
+ "add/remove IP addresses to any list (block or bypass).",
30
+ "check for, and remove, ShieldPRO license.",
31
+ "run Debug to get general site information summary for debug purposes."
32
+ ]
33
+ },
34
+ {
35
+ "type": "new",
36
+ "pro_only": true,
37
+ "title": "Option To Load Shield as a WordPress Must-Use (MU) Plugin",
38
+ "description": [
39
+ "To prevent unwanted or accidental deactivation of the Shield plugin, Shield can be converted to an MU plugin."
40
  ]
41
  },
42
  {
43
  "type": "new",
44
  "pro_only": false,
45
+ "title": "Show Recent User Session In Admin Bar",
46
  "description": [
47
+ "Show quick links to recently active (10 minutes) user sessions in the admin bar and the most recently active sessions."
48
  ]
49
  },
50
  {
51
  "type": "new",
52
  "pro_only": false,
53
+ "title": "Support For Application Password Authentication Failures",
54
  "description": [
55
+ "Shield detects and logs when application passwords have been used incorrectly and applies offenses."
56
  ]
57
  },
58
  {
59
+ "type": "improved",
60
  "pro_only": false,
61
+ "title": "Speed-Up For Audit Trail and Traffic Log Tables",
62
  "description": [
63
+ "Audit Trail and Traffic Log tables are usually huge and loading them were slow. They're now entirely AJAX based and fast-loading."
64
  ]
65
  },
66
  {
67
  "type": "improved",
68
  "pro_only": false,
69
+ "title": "IP Record Management Error",
70
  "description": [
71
+ "When inserting a duplicate IP address record into the database, we use INSERT IGNORE to reduce error messages in logs."
72
  ]
73
  },
74
  {
75
  "type": "improved",
76
  "pro_only": false,
77
+ "title": "Support 3rd Party Traffic Log Handlers",
78
  "description": [
79
+ "3rd parties can now easily integrate with Shield's Traffic Log to send log records to any destination."
80
  ]
81
  },
82
  {
83
  "type": "improved",
84
  "pro_only": false,
85
+ "title": "Support 3rd Party Audit Trail Handlers",
86
  "description": [
87
+ "3rd parties can now easily integrate with Shield's Audit Trail to send log records to any destination."
88
  ]
89
  },
90
  {
91
+ "type": "improved",
92
  "pro_only": false,
93
+ "title": "IP Record Management Error",
94
+ "description": [
95
+ "When inserting a duplicate IP address record into the database, we now INSERT IGNORE to reduce error messages in logs."
96
+ ]
97
+ },
98
+ {
99
+ "type": "improved",
100
+ "pro_only": false,
101
+ "title": "Updated Dutch Translations",
102
  "description": [
103
  ]
104
  },
105
  {
106
  "type": "fixed",
107
  "pro_only": false,
108
+ "title": "Firewall didn't always scan all parameters in some cases",
109
  "description": [
110
  ]
111
+ }
112
+ ],
113
+ "patches": [
114
+ ]
115
+ },
116
+ "14.0": {
117
+ "version": "14.0",
118
+ "released_at": 1643364060,
119
+ "hrefs": {
120
+ "release": "https://shsec.io/shieldrelease140",
121
+ "upgrade": "https://shsec.io/shieldupgradeguide140"
122
+ },
123
+ "title": "Two-Factor Authentication Overhaul",
124
+ "description": [
125
+ ],
126
+ "items": [
127
+ {
128
+ "title": "WP Login Style 2FA Screen",
129
+ "description": [
130
+ "Users can complete their 2FA login using the UI they're most familiar with."
131
+ ],
132
+ "type": "new",
133
+ "pro_only": false
134
+ },
135
+ {
136
+ "title": "Custom Redirect For Hide WP Login & Admin",
137
+ "description": [
138
+ "Rather than display an unfriendly 404 error page for the hidden login page, you can decide to redirect requests to any page you wish."
139
+ ],
140
+ "type": "new",
141
+ "pro_only": false
142
+ },
143
+ {
144
+ "title": "Easier Access To User 2FA Settings with WP Admin Menu",
145
+ "description": [
146
+ "Users can now update their 2FA account settings from a dedicated WP admin page."
147
+ ],
148
+ "type": "new",
149
+ "pro_only": false
150
+ },
151
+ {
152
+ "title": "Improved 2FA User Experience",
153
+ "description": [
154
+ "Smoother, faster, more reliable and more secure 2FA experience."
155
+ ],
156
+ "type": "new",
157
+ "pro_only": false
158
+ },
159
+ {
160
+ "title": "Multi-factor Authentication Removed",
161
+ "description": [
162
+ "The option to force users to supply ALL two-factor authentication options has been removed."
163
+ ],
164
+ "type": "changed",
165
+ "pro_only": false
166
  },
167
  {
168
+ "title": "Dedicated table for User meta information",
169
+ "description": [
170
+ "This allows for new filters and better user status on the WP Admin User page."
171
+ ],
172
  "type": "improved",
173
+ "pro_only": false
 
 
174
  },
175
  {
176
+ "title": "Updated Translations - Dutch (thanks J.P.!)",
177
+ "type": "improved",
178
+ "pro_only": false
 
179
  },
180
  {
181
+ "title": "Further page caching mitigation for NotBot",
182
+ "type": "improved",
183
+ "pro_only": false
 
184
  },
185
  {
186
+ "type": "changed",
187
+ "pro_only": false,
188
+ "title": "Updated Bootstrap Libraries",
189
+ "description": [
190
+ ]
191
  },
192
  {
193
  "type": "fixed",
194
+ "pro_only": false,
195
+ "title": "Various bugs and errors",
196
+ "description": [
197
+ ]
198
+ }
199
+ ],
200
+ "patches": [
201
+ {
202
+ "version": "2",
203
+ "released_at": 1644400200,
204
+ "items": [
205
+ {
206
+ "title": "Integration with some 3rd party membership plugins + 2FA.",
207
+ "type": "improved"
208
+ },
209
+ {
210
+ "title": "Alert displayed that U2F isn't support when U2F isn't in-use.",
211
+ "type": "fixed"
212
+ },
213
+ {
214
+ "title": "A rare issue which Custom MFA login triggering an HTTP 402 error!",
215
+ "type": "fixed"
216
+ },
217
+ {
218
+ "title": "Options Search dialog failed to open (can't find-as-you-type yet).",
219
+ "type": "fixed"
220
+ }
221
+ ]
222
+ },
223
+ {
224
+ "version": "3",
225
+ "released_at": 1645005000,
226
+ "items": [
227
+ {
228
+ "title": "Work around WP Engine login mechanism blocking 2FA verification.",
229
+ "type": "fixed"
230
+ }
231
+ ]
232
  }
233
  ]
234
  },
326
  "description": [
327
  "Adding and removing Yubikey devices to and from your WP user profile is more reliable."
328
  ]
329
+ }
330
+ ],
331
+ "patches": [
332
+ {
333
+ "version": "1",
334
+ "released_at": 1636968900,
335
+ "items": [
336
+ {
337
+ "type": "fixed",
338
+ "title": "Reduce scan chunk size to improve MySQL query memory usage."
339
+ },
340
+ {
341
+ "type": "fixed",
342
+ "title": "Automatic selection of IP addresses in IP Analyse tool after switching to AJAX source."
343
+ }
344
+ ]
345
+ },
346
+ {
347
+ "version": "3",
348
+ "released_at": 1640079300,
349
+ "items": [
350
+ {
351
+ "type": "fixed",
352
+ "title": "Ensure database states are handled correctly."
353
+ },
354
+ {
355
+ "type": "fixed",
356
+ "title": "MySQL requirements are checked more flexibly."
357
+ },
358
+ {
359
+ "type": "fixed",
360
+ "title": "Add a class to Google Authenticator QR image."
361
+ }
362
+ ]
363
+ },
364
+ {
365
+ "version": "4",
366
+ "released_at": 1640165700,
367
+ "items": [
368
+ {
369
+ "type": "fixed",
370
+ "title": "Error with MainWP loading in certain cases."
371
+ }
372
+ ]
373
+ },
374
+ {
375
+ "version": "5",
376
+ "released_at": 1641980100,
377
+ "items": [
378
+ {
379
+ "type": "improved",
380
+ "title": "Options to provide custom roles for Email 2FA enforcement is now free-form."
381
+ },
382
+ {
383
+ "type": "improved",
384
+ "title": "Multi-factor authentication settings are available even when your IP is on the bypass lists."
385
+ },
386
+ {
387
+ "type": "improved",
388
+ "title": "ShieldPRO license lookups when using separate domains for multilingual site versions."
389
+ },
390
+ {
391
+ "type": "improved",
392
+ "title": "FluentForms integration wasn't always loading and so SPAM submissions could still come through."
393
+ },
394
+ {
395
+ "type": "improved",
396
+ "title": "NotBot Javascript is improved to better handle server timeouts and work around Page Caching limitations."
397
+ },
398
+ {
399
+ "type": "fixed",
400
+ "title": "Prevent some fatal errors when integrating with 3rd parties and their data isn't as expected."
401
+ }
402
+ ]
403
+ },
404
+ {
405
+ "version": "6",
406
+ "released_at": 1642152900,
407
+ "items": [
408
+ {
409
+ "type": "improved",
410
+ "title": "Improved handling of ClassicPress versions and file scanning for migrated WP sites."
411
+ },
412
+ {
413
+ "type": "changed",
414
+ "title": "Official WP.org themes that are inactive no longer display a warning in results tables."
415
+ },
416
+ {
417
+ "type": "fixed",
418
+ "title": "[Minor Security Vulnerability] An authenticated (administrator+) Persistent XSS.",
419
+ "description": [
420
+ "Privately disclosed to us by Yoru Oni - thank you."
421
+ ],
422
+ "href": "https://shsec.io/kh"
423
+ },
424
+ {
425
+ "type": "changed",
426
+ "title": "It's now possible to add custom exclusions to the anonymous REST API block."
427
+ }
428
+ ]
429
  }
430
  ]
431
  },
552
  "With this upgrade, the minimum required MySQL database engine is moving to 5.6."
553
  ],
554
  "href": "https://shsec.io/shieldsystemrequirements"
555
+ }
556
+ ],
557
+ "patches": [
 
 
 
 
 
 
 
 
 
 
558
  {
559
+ "version": "4",
560
+ "released_at": 1632303300,
561
+ "items": [
562
+ {
563
+ "type": "fixed",
564
+ "title": "Prevent PHP exception being thrown in certain cases."
565
+ }
566
+ ]
567
  },
568
  {
569
+ "version": "8",
570
+ "released_at": 1632389700,
571
+ "items": [
572
+ {
573
+ "type": "fixed",
574
+ "title": "Ensure Shield runs only on supported MySQL servers."
575
+ }
576
+ ]
577
  },
578
  {
579
+ "version": "9",
580
+ "released_at": 1632908100,
581
+ "items": [
582
+ {
583
+ "type": "fixed",
584
+ "title": "Error when processing certain types of query strings in the firewall."
585
+ },
586
+ {
587
+ "type": "fixed",
588
+ "title": "Yubikey 2FA verification was failing with a nonce less than 16 characters. Who knew?"
589
+ }
590
+ ]
591
  },
592
  {
593
+ "version": "11",
594
+ "released_at": 1633599300,
595
+ "items": [
596
+ {
597
+ "type": "fixed",
598
+ "title": "A few minor fixes, along with slight optimisation of NotBot JS."
599
+ },
600
+ {
601
+ "type": "fixed",
602
+ "title": "Issue with managing Shield Central profiles."
603
+ }
604
+ ]
605
  },
606
  {
607
+ "version": "13",
608
+ "released_at": 1633858500,
609
+ "items": [
610
+ {
611
+ "type": "improved",
612
+ "title": "Improve support for auto-login systems like ManageWP admin login."
613
+ }
614
+ ]
615
  }
616
  ]
617
  },
715
  "type": "improved",
716
  "title": "Improved support and fixes for PHP 8 and WordPress 5.8.",
717
  "description": []
718
+ }
719
+ ],
720
+ "patches": [
 
 
 
 
721
  {
722
+ "version": "1",
723
+ "released_at": 1627551300,
724
+ "items": [
725
+ {
726
+ "type": "improved",
727
+ "title": "Prevent overloading ShieldNET API in some cases."
728
+ }
729
+ ]
730
  },
731
  {
732
+ "version": "2",
733
+ "released_at": 1627637700,
734
+ "items": [
735
+ {
736
+ "type": "improved",
737
+ "title": "Add some limited details into the Audit Trail entries for scan results."
738
+ }
739
+ ]
740
  },
741
  {
742
+ "version": "3",
743
+ "released_at": 1627896900,
744
+ "items": [
745
+ {
746
+ "type": "fixed",
747
+ "title": "Plugin/Theme scanning could result in large quantities of unrecognised files."
748
+ }
749
+ ]
750
  },
751
  {
752
+ "version": "4",
753
+ "released_at": 1628069700,
754
+ "items": [
755
+ {
756
+ "type": "improved",
757
+ "title": "Scan results were being reported, but not displayed in results tables in some cases."
758
+ }
759
+ ]
760
  },
761
  {
762
+ "version": "5",
763
+ "released_at": 1631180100,
764
+ "items": [
765
+ {
766
+ "type": "fixed",
767
+ "title": "Scan results wouldn't be updated after scans completed in some cases."
768
+ },
769
+ {
770
+ "type": "fixed",
771
+ "title": "Shield would apply login blocks for requests originating from a whitelisted IP addresses."
772
+ }
773
+ ]
774
  }
775
  ]
776
  },
config/admin_access_restriction.json CHANGED
@@ -151,6 +151,20 @@
151
  "summary": "Allow Email Override Of Admin Access Restrictions",
152
  "description": "Allow the use of verification emails to override and switch off the Security Admin restrictions."
153
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
  {
155
  "key": "admin_access_restrict_options",
156
  "section": "section_admin_access_restriction_areas",
151
  "summary": "Allow Email Override Of Admin Access Restrictions",
152
  "description": "Allow the use of verification emails to override and switch off the Security Admin restrictions."
153
  },
154
+ {
155
+ "key": "enable_mu",
156
+ "section": "section_security_admin_settings",
157
+ "advanced": true,
158
+ "premium": true,
159
+ "default": "N",
160
+ "type": "checkbox",
161
+ "link_info": "https://shsec.io/i1",
162
+ "link_blog": "https://shsec.io/i2",
163
+ "beacon_id": 308,
164
+ "name": "Run In MU Mode",
165
+ "summary": "Run Plugin In Must-Use (MU) Mode",
166
+ "description": "Setup the plugin to run as an MU-plugin to prevent accidental deactivation."
167
+ },
168
  {
169
  "key": "admin_access_restrict_options",
170
  "section": "section_admin_access_restriction_areas",
config/audit_trail.json CHANGED
@@ -250,27 +250,34 @@
250
  },
251
  "max_free_days": 7,
252
  "events": {
253
- "plugin_activated": {
254
  "audit_params": [
255
  "plugin"
256
  ],
257
  "level": "notice",
258
  "audit_multiple": true
259
  },
260
- "plugin_deactivated": {
 
 
 
 
 
 
 
261
  "audit_params": [
262
  "plugin"
263
  ],
264
  "level": "notice",
265
  "audit_multiple": true
266
  },
267
- "plugin_file_edited": {
268
  "audit_params": [
269
  "file"
270
  ],
271
  "level": "warning"
272
  },
273
- "plugin_upgraded": {
274
  "audit_params": [
275
  "plugin",
276
  "from",
@@ -279,19 +286,26 @@
279
  "level": "notice",
280
  "audit_multiple": true
281
  },
282
- "theme_activated": {
283
  "audit_params": [
284
  "theme"
285
  ],
286
  "level": "notice"
287
  },
288
- "theme_file_edited": {
 
 
 
 
 
 
 
289
  "audit_params": [
290
  "file"
291
  ],
292
  "level": "warning"
293
  },
294
- "theme_upgraded": {
295
  "audit_params": [
296
  "theme",
297
  "from",
@@ -300,28 +314,28 @@
300
  "level": "notice",
301
  "audit_multiple": true
302
  },
303
- "core_updated": {
304
  "audit_params": [
305
  "from",
306
  "to"
307
  ],
308
  "level": "notice"
309
  },
310
- "permalinks_structure": {
311
  "audit_params": [
312
  "from",
313
  "to"
314
  ],
315
  "level": "warning"
316
  },
317
- "post_deleted": {
318
  "audit_params": [
319
  "title"
320
  ],
321
  "level": "warning",
322
  "audit_multiple": true
323
  },
324
- "post_trashed": {
325
  "audit_params": [
326
  "title",
327
  "type"
@@ -329,7 +343,7 @@
329
  "level": "warning",
330
  "audit_multiple": true
331
  },
332
- "post_recovered": {
333
  "audit_params": [
334
  "title",
335
  "type"
@@ -337,7 +351,7 @@
337
  "level": "info",
338
  "audit_multiple": true
339
  },
340
- "post_updated": {
341
  "audit_params": [
342
  "title",
343
  "type"
@@ -345,7 +359,7 @@
345
  "level": "notice",
346
  "audit_multiple": true
347
  },
348
- "post_published": {
349
  "audit_params": [
350
  "title",
351
  "type"
@@ -353,7 +367,7 @@
353
  "level": "notice",
354
  "audit_multiple": true
355
  },
356
- "post_unpublished": {
357
  "audit_params": [
358
  "title",
359
  "type"
@@ -361,26 +375,26 @@
361
  "level": "warning",
362
  "audit_multiple": true
363
  },
364
- "user_login": {
365
  "audit_params": [
366
  "user_login"
367
  ],
368
  "level": "warning"
369
  },
370
- "user_login_app": {
371
  "audit_params": [
372
  "user_login"
373
  ],
374
  "level": "warning"
375
  },
376
- "user_registered": {
377
  "audit_params": [
378
  "user_login",
379
  "email"
380
  ],
381
  "level": "alert"
382
  },
383
- "user_deleted": {
384
  "audit_params": [
385
  "user_login",
386
  "email"
@@ -388,13 +402,39 @@
388
  "level": "warning",
389
  "audit_multiple": true
390
  },
391
- "user_deleted_reassigned": {
 
 
 
 
 
 
392
  "audit_params": [
393
  "user_login"
394
  ],
395
  "level": "notice"
396
  },
397
- "email_attempt_send": {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
398
  "audit_params": [
399
  "to",
400
  "subject",
250
  },
251
  "max_free_days": 7,
252
  "events": {
253
+ "plugin_activated": {
254
  "audit_params": [
255
  "plugin"
256
  ],
257
  "level": "notice",
258
  "audit_multiple": true
259
  },
260
+ "plugin_installed": {
261
+ "audit_params": [
262
+ "plugin"
263
+ ],
264
+ "level": "warning",
265
+ "audit_multiple": true
266
+ },
267
+ "plugin_deactivated": {
268
  "audit_params": [
269
  "plugin"
270
  ],
271
  "level": "notice",
272
  "audit_multiple": true
273
  },
274
+ "plugin_file_edited": {
275
  "audit_params": [
276
  "file"
277
  ],
278
  "level": "warning"
279
  },
280
+ "plugin_upgraded": {
281
  "audit_params": [
282
  "plugin",
283
  "from",
286
  "level": "notice",
287
  "audit_multiple": true
288
  },
289
+ "theme_activated": {
290
  "audit_params": [
291
  "theme"
292
  ],
293
  "level": "notice"
294
  },
295
+ "theme_installed": {
296
+ "audit_params": [
297
+ "theme"
298
+ ],
299
+ "level": "warning",
300
+ "audit_multiple": true
301
+ },
302
+ "theme_file_edited": {
303
  "audit_params": [
304
  "file"
305
  ],
306
  "level": "warning"
307
  },
308
+ "theme_upgraded": {
309
  "audit_params": [
310
  "theme",
311
  "from",
314
  "level": "notice",
315
  "audit_multiple": true
316
  },
317
+ "core_updated": {
318
  "audit_params": [
319
  "from",
320
  "to"
321
  ],
322
  "level": "notice"
323
  },
324
+ "permalinks_structure": {
325
  "audit_params": [
326
  "from",
327
  "to"
328
  ],
329
  "level": "warning"
330
  },
331
+ "post_deleted": {
332
  "audit_params": [
333
  "title"
334
  ],
335
  "level": "warning",
336
  "audit_multiple": true
337
  },
338
+ "post_trashed": {
339
  "audit_params": [
340
  "title",
341
  "type"
343
  "level": "warning",
344
  "audit_multiple": true
345
  },
346
+ "post_recovered": {
347
  "audit_params": [
348
  "title",
349
  "type"
351
  "level": "info",
352
  "audit_multiple": true
353
  },
354
+ "post_updated": {
355
  "audit_params": [
356
  "title",
357
  "type"
359
  "level": "notice",
360
  "audit_multiple": true
361
  },
362
+ "post_published": {
363
  "audit_params": [
364
  "title",
365
  "type"
367
  "level": "notice",
368
  "audit_multiple": true
369
  },
370
+ "post_unpublished": {
371
  "audit_params": [
372
  "title",
373
  "type"
375
  "level": "warning",
376
  "audit_multiple": true
377
  },
378
+ "user_login": {
379
  "audit_params": [
380
  "user_login"
381
  ],
382
  "level": "warning"
383
  },
384
+ "user_login_app": {
385
  "audit_params": [
386
  "user_login"
387
  ],
388
  "level": "warning"
389
  },
390
+ "user_registered": {
391
  "audit_params": [
392
  "user_login",
393
  "email"
394
  ],
395
  "level": "alert"
396
  },
397
+ "user_deleted": {
398
  "audit_params": [
399
  "user_login",
400
  "email"
402
  "level": "warning",
403
  "audit_multiple": true
404
  },
405
+ "user_deleted_reassigned": {
406
+ "audit_params": [
407
+ "user_login"
408
+ ],
409
+ "level": "notice"
410
+ },
411
+ "app_pass_success": {
412
  "audit_params": [
413
  "user_login"
414
  ],
415
  "level": "notice"
416
  },
417
+ "app_invalid_email": {
418
+ "level": "warning",
419
+ "offense": true
420
+ },
421
+ "app_invalid_username": {
422
+ "level": "warning",
423
+ "offense": true
424
+ },
425
+ "app_incorrect_password": {
426
+ "level": "warning",
427
+ "offense": true
428
+ },
429
+ "app_passwords_disabled": {
430
+ "level": "warning",
431
+ "offense": true
432
+ },
433
+ "app_passwords_disabled_user": {
434
+ "level": "warning",
435
+ "offense": true
436
+ },
437
+ "email_attempt_send": {
438
  "audit_params": [
439
  "to",
440
  "subject",
config/data.json CHANGED
@@ -47,11 +47,11 @@
47
  }
48
  },
49
  "db_table_req_logs": {
50
- "slug": "req_logs",
51
- "autoexpire": 0,
52
- "has_updated_at": false,
53
- "has_deleted_at": false,
54
- "cols_custom": {
55
  "req_id": {
56
  "macro_type": "varchar",
57
  "length": 10,
@@ -65,6 +65,33 @@
65
  "ref_table": "icwp_wpsf_ips"
66
  }
67
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  "meta": {
69
  "macro_type": "meta"
70
  }
47
  }
48
  },
49
  "db_table_req_logs": {
50
+ "slug": "req_logs",
51
+ "autoexpire": 0,
52
+ "has_updated_at": false,
53
+ "has_deleted_at": false,
54
+ "cols_custom": {
55
  "req_id": {
56
  "macro_type": "varchar",
57
  "length": 10,
65
  "ref_table": "icwp_wpsf_ips"
66
  }
67
  },
68
+ "type": {
69
+ "macro_type": "varchar",
70
+ "length": 5,
71
+ "comment": "Type of request"
72
+ },
73
+ "verb": {
74
+ "macro_type": "varchar",
75
+ "length": 8,
76
+ "comment": "Request Verb"
77
+ },
78
+ "path": {
79
+ "macro_type": "varchar",
80
+ "length": 256,
81
+ "comment": "Request Path"
82
+ },
83
+ "code": {
84
+ "macro_type": "unsigned_int",
85
+ "type": "smallint",
86
+ "length": 3,
87
+ "default": 0,
88
+ "comment": "Response Code"
89
+ },
90
+ "offense": {
91
+ "macro_type": "bool",
92
+ "default": 0,
93
+ "comment": "Was Offense"
94
+ },
95
  "meta": {
96
  "macro_type": "meta"
97
  }
config/deprecated/license.php CHANGED
@@ -143,7 +143,6 @@
143
  }
144
  ],
145
  "definitions": {
146
- "license_store_url_api": "https://api.getshieldsecurity.com/wp-json/odp-eddkeyless/v1",
147
  "keyless_cp": "https://shsec.io/c5",
148
  "license_item_name": "Shield Security Pro",
149
  "license_item_id": "6047",
143
  }
144
  ],
145
  "definitions": {
 
146
  "keyless_cp": "https://shsec.io/c5",
147
  "license_item_name": "Shield Security Pro",
148
  "license_item_id": "6047",
config/hack_protect.json CHANGED
@@ -374,6 +374,18 @@
374
  }
375
  ],
376
  "definitions": {
 
 
 
 
 
 
 
 
 
 
 
 
377
  "all_scan_slugs": [
378
  "apc",
379
  "wpv",
374
  }
375
  ],
376
  "definitions": {
377
+ "rest_api": {
378
+ "publish": true,
379
+ "pro_only": true,
380
+ "route_defs": {
381
+ "scan_status": {
382
+ },
383
+ "scan_start": {
384
+ },
385
+ "scan_results": {
386
+ }
387
+ }
388
+ },
389
  "all_scan_slugs": [
390
  "apc",
391
  "wpv",
config/ips.json CHANGED
@@ -588,6 +588,20 @@
588
  }
589
  ],
590
  "definitions": {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
591
  "allowable_ext_404s": [
592
  "js",
593
  "css",
588
  }
589
  ],
590
  "definitions": {
591
+ "rest_api": {
592
+ "publish": true,
593
+ "pro_only": true,
594
+ "route_defs": {
595
+ "ips_get": {
596
+ },
597
+ "lists_get": {
598
+ },
599
+ "lists_getip": {
600
+ },
601
+ "lists_setip": {
602
+ }
603
+ }
604
+ },
605
  "allowable_ext_404s": [
606
  "js",
607
  "css",
config/license.json CHANGED
@@ -143,7 +143,16 @@
143
  }
144
  ],
145
  "definitions": {
146
- "license_store_url_api": "https://api.getshieldsecurity.com/wp-json/odp-eddkeyless/v1",
 
 
 
 
 
 
 
 
 
147
  "keyless_cp": "https://shsec.io/c5",
148
  "license_item_name": "Shield Security Pro",
149
  "license_item_id": "6047",
143
  }
144
  ],
145
  "definitions": {
146
+ "rest_api": {
147
+ "publish": true,
148
+ "pro_only": false,
149
+ "route_defs": {
150
+ "license_check": {
151
+ },
152
+ "license_status": {
153
+ }
154
+ }
155
+ },
156
  "keyless_cp": "https://shsec.io/c5",
157
  "license_item_name": "Shield Security Pro",
158
  "license_item_id": "6047",
config/plugin.json CHANGED
@@ -541,6 +541,22 @@
541
  }
542
  ],
543
  "definitions": {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
544
  "href_privacy_policy": "https://shsec.io/wpshieldprivacypolicy",
545
  "db_classes": {
546
  "notes": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\AdminNotes\\Handler"
541
  }
542
  ],
543
  "definitions": {
544
+ "rest_api": {
545
+ "publish": true,
546
+ "pro_only": true,
547
+ "route_defs": {
548
+ "debug_get": {
549
+ },
550
+ "option_get": {
551
+ },
552
+ "option_set": {
553
+ },
554
+ "options_get": {
555
+ },
556
+ "options_set": {
557
+ }
558
+ }
559
+ },
560
  "href_privacy_policy": "https://shsec.io/wpshieldprivacypolicy",
561
  "db_classes": {
562
  "notes": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\AdminNotes\\Handler"
config/user_management.json CHANGED
@@ -401,13 +401,6 @@
401
  "type": "integer",
402
  "default": 0,
403
  "transferable": false
404
- },
405
- {
406
- "key": "hard_suspended_userids",
407
- "section": "section_non_ui",
408
- "transferable": false,
409
- "type": "array",
410
- "default": []
411
  }
412
  ],
413
  "definitions": {
401
  "type": "integer",
402
  "default": 0,
403
  "transferable": false
 
 
 
 
 
 
 
404
  }
405
  ],
406
  "definitions": {
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: 14.0.3
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: 14.1.0
7
  * Text Domain: wp-simple-firewall
8
  * Domain Path: /languages
9
  * Author: Shield Security
languages/wp-simple-firewall-nl_NL.mo CHANGED
Binary file
plugin-spec.php CHANGED
@@ -1,8 +1,8 @@
1
  {
2
  "properties": {
3
- "version": "14.0.3",
4
- "release_timestamp": 1645003743,
5
- "build": "202202.1601",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
  "human_name": "Shield Security",
@@ -23,6 +23,10 @@
23
  "wordpress": "3.7",
24
  "mysql": "5.6"
25
  },
 
 
 
 
26
  "upgrade_reqs": {
27
  "10.0": {
28
  "php": "7.0",
@@ -105,25 +109,25 @@
105
  ]
106
  },
107
  "datatables-bootstrap": {
108
- "url": "https://cdn.datatables.net/1.11.3/css/dataTables.bootstrap5.min.css",
109
  "deps": [
110
  "bootstrap"
111
  ]
112
  },
113
  "datatables-searchpanes": {
114
- "url": "https://cdn.datatables.net/searchpanes/1.4.0/css/searchPanes.dataTables.min.css",
115
  "deps": [
116
  "datatables-bootstrap"
117
  ]
118
  },
119
  "datatables-select": {
120
- "url": "https://cdn.datatables.net/select/1.3.3/css/select.dataTables.min.css",
121
  "deps": [
122
  "datatables-bootstrap"
123
  ]
124
  },
125
  "datatables-buttons": {
126
- "url": "https://cdn.datatables.net/buttons/1.7.1/css/buttons.dataTables.min.css",
127
  "deps": [
128
  "datatables-bootstrap"
129
  ]
@@ -220,32 +224,32 @@
220
  ]
221
  },
222
  "datatables": {
223
- "url": "https://cdn.datatables.net/1.11.3/js/jquery.dataTables.min.js",
224
  "deps": [
225
  "bootstrap",
226
  "wp-jquery"
227
  ]
228
  },
229
  "datatables-bootstrap": {
230
- "url": "https://cdn.datatables.net/1.11.3/js/dataTables.bootstrap5.min.js",
231
  "deps": [
232
  "datatables"
233
  ]
234
  },
235
  "datatables-searchpanes": {
236
- "url": "https://cdn.datatables.net/searchpanes/1.4.0/js/dataTables.searchPanes.min.js",
237
  "deps": [
238
  "datatables-bootstrap"
239
  ]
240
  },
241
  "datatables-select": {
242
- "url": "https://cdn.datatables.net/select/1.3.3/js/dataTables.select.min.js",
243
  "deps": [
244
  "datatables-bootstrap"
245
  ]
246
  },
247
  "datatables-buttons": {
248
- "url": "https://cdn.datatables.net/buttons/1.7.1/js/dataTables.buttons.min.js",
249
  "deps": [
250
  "datatables-bootstrap"
251
  ]
@@ -358,6 +362,7 @@
358
  "datatables-select",
359
  "datatables-buttons",
360
  "datatables-bootstrap",
 
361
  "tp/highlightjs"
362
  ]
363
  },
@@ -462,6 +467,7 @@
462
  }
463
  ],
464
  "version_upgrades": [
 
465
  "11.2.0",
466
  "12.0.0",
467
  "12.0.1",
1
  {
2
  "properties": {
3
+ "version": "14.1.0",
4
+ "release_timestamp": 1647422166,
5
+ "build": "202203.1601",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
  "human_name": "Shield Security",
23
  "wordpress": "3.7",
24
  "mysql": "5.6"
25
  },
26
+ "reqs_rest": {
27
+ "php": "7.0",
28
+ "wp": "5.7"
29
+ },
30
  "upgrade_reqs": {
31
  "10.0": {
32
  "php": "7.0",
109
  ]
110
  },
111
  "datatables-bootstrap": {
112
+ "url": "https://cdn.datatables.net/1.11.5/css/dataTables.bootstrap5.min.css",
113
  "deps": [
114
  "bootstrap"
115
  ]
116
  },
117
  "datatables-searchpanes": {
118
+ "url": "https://cdn.datatables.net/searchpanes/2.0.0/css/searchPanes.dataTables.min.css",
119
  "deps": [
120
  "datatables-bootstrap"
121
  ]
122
  },
123
  "datatables-select": {
124
+ "url": "https://cdn.datatables.net/select/1.3.4/css/select.dataTables.min.css",
125
  "deps": [
126
  "datatables-bootstrap"
127
  ]
128
  },
129
  "datatables-buttons": {
130
+ "url": "https://cdn.datatables.net/buttons/2.2.2/css/buttons.dataTables.min.css",
131
  "deps": [
132
  "datatables-bootstrap"
133
  ]
224
  ]
225
  },
226
  "datatables": {
227
+ "url": "https://cdn.datatables.net/1.11.5/js/jquery.dataTables.min.js",
228
  "deps": [
229
  "bootstrap",
230
  "wp-jquery"
231
  ]
232
  },
233
  "datatables-bootstrap": {
234
+ "url": "https://cdn.datatables.net/1.11.5/js/dataTables.bootstrap5.min.js",
235
  "deps": [
236
  "datatables"
237
  ]
238
  },
239
  "datatables-searchpanes": {
240
+ "url": "https://cdn.datatables.net/searchpanes/2.0.0/js/dataTables.searchPanes.min.js",
241
  "deps": [
242
  "datatables-bootstrap"
243
  ]
244
  },
245
  "datatables-select": {
246
+ "url": "https://cdn.datatables.net/select/1.3.4/js/dataTables.select.min.js",
247
  "deps": [
248
  "datatables-bootstrap"
249
  ]
250
  },
251
  "datatables-buttons": {
252
+ "url": "https://cdn.datatables.net/buttons/2.2.2/js/dataTables.buttons.min.js",
253
  "deps": [
254
  "datatables-bootstrap"
255
  ]
362
  "datatables-select",
363
  "datatables-buttons",
364
  "datatables-bootstrap",
365
+ "datatables-searchpanes",
366
  "tp/highlightjs"
367
  ]
368
  },
467
  }
468
  ],
469
  "version_upgrades": [
470
+ "14.1.0",
471
  "11.2.0",
472
  "12.0.0",
473
  "12.0.1",
plugin.json CHANGED
@@ -1,8 +1,8 @@
1
  {
2
  "properties": {
3
- "version": "14.0.3",
4
- "release_timestamp": 1645003743,
5
- "build": "202202.1601",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
  "human_name": "Shield Security",
@@ -23,6 +23,10 @@
23
  "wordpress": "3.7",
24
  "mysql": "5.6"
25
  },
 
 
 
 
26
  "upgrade_reqs": {
27
  "10.0": {
28
  "php": "7.0",
@@ -105,25 +109,25 @@
105
  ]
106
  },
107
  "datatables-bootstrap": {
108
- "url": "https://cdn.datatables.net/1.11.3/css/dataTables.bootstrap5.min.css",
109
  "deps": [
110
  "bootstrap"
111
  ]
112
  },
113
  "datatables-searchpanes": {
114
- "url": "https://cdn.datatables.net/searchpanes/1.4.0/css/searchPanes.dataTables.min.css",
115
  "deps": [
116
  "datatables-bootstrap"
117
  ]
118
  },
119
  "datatables-select": {
120
- "url": "https://cdn.datatables.net/select/1.3.3/css/select.dataTables.min.css",
121
  "deps": [
122
  "datatables-bootstrap"
123
  ]
124
  },
125
  "datatables-buttons": {
126
- "url": "https://cdn.datatables.net/buttons/1.7.1/css/buttons.dataTables.min.css",
127
  "deps": [
128
  "datatables-bootstrap"
129
  ]
@@ -220,32 +224,32 @@
220
  ]
221
  },
222
  "datatables": {
223
- "url": "https://cdn.datatables.net/1.11.3/js/jquery.dataTables.min.js",
224
  "deps": [
225
  "bootstrap",
226
  "wp-jquery"
227
  ]
228
  },
229
  "datatables-bootstrap": {
230
- "url": "https://cdn.datatables.net/1.11.3/js/dataTables.bootstrap5.min.js",
231
  "deps": [
232
  "datatables"
233
  ]
234
  },
235
  "datatables-searchpanes": {
236
- "url": "https://cdn.datatables.net/searchpanes/1.4.0/js/dataTables.searchPanes.min.js",
237
  "deps": [
238
  "datatables-bootstrap"
239
  ]
240
  },
241
  "datatables-select": {
242
- "url": "https://cdn.datatables.net/select/1.3.3/js/dataTables.select.min.js",
243
  "deps": [
244
  "datatables-bootstrap"
245
  ]
246
  },
247
  "datatables-buttons": {
248
- "url": "https://cdn.datatables.net/buttons/1.7.1/js/dataTables.buttons.min.js",
249
  "deps": [
250
  "datatables-bootstrap"
251
  ]
@@ -358,6 +362,7 @@
358
  "datatables-select",
359
  "datatables-buttons",
360
  "datatables-bootstrap",
 
361
  "tp/highlightjs"
362
  ]
363
  },
@@ -462,6 +467,7 @@
462
  }
463
  ],
464
  "version_upgrades": [
 
465
  "11.2.0",
466
  "12.0.0",
467
  "12.0.1",
1
  {
2
  "properties": {
3
+ "version": "14.1.0",
4
+ "release_timestamp": 1647422166,
5
+ "build": "202203.1601",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
  "human_name": "Shield Security",
23
  "wordpress": "3.7",
24
  "mysql": "5.6"
25
  },
26
+ "reqs_rest": {
27
+ "php": "7.0",
28
+ "wp": "5.7"
29
+ },
30
  "upgrade_reqs": {
31
  "10.0": {
32
  "php": "7.0",
109
  ]
110
  },
111
  "datatables-bootstrap": {
112
+ "url": "https://cdn.datatables.net/1.11.5/css/dataTables.bootstrap5.min.css",
113
  "deps": [
114
  "bootstrap"
115
  ]
116
  },
117
  "datatables-searchpanes": {
118
+ "url": "https://cdn.datatables.net/searchpanes/2.0.0/css/searchPanes.dataTables.min.css",
119
  "deps": [
120
  "datatables-bootstrap"
121
  ]
122
  },
123
  "datatables-select": {
124
+ "url": "https://cdn.datatables.net/select/1.3.4/css/select.dataTables.min.css",
125
  "deps": [
126
  "datatables-bootstrap"
127
  ]
128
  },
129
  "datatables-buttons": {
130
+ "url": "https://cdn.datatables.net/buttons/2.2.2/css/buttons.dataTables.min.css",
131
  "deps": [
132
  "datatables-bootstrap"
133
  ]
224
  ]
225
  },
226
  "datatables": {
227
+ "url": "https://cdn.datatables.net/1.11.5/js/jquery.dataTables.min.js",
228
  "deps": [
229
  "bootstrap",
230
  "wp-jquery"
231
  ]
232
  },
233
  "datatables-bootstrap": {
234
+ "url": "https://cdn.datatables.net/1.11.5/js/dataTables.bootstrap5.min.js",
235
  "deps": [
236
  "datatables"
237
  ]
238
  },
239
  "datatables-searchpanes": {
240
+ "url": "https://cdn.datatables.net/searchpanes/2.0.0/js/dataTables.searchPanes.min.js",
241
  "deps": [
242
  "datatables-bootstrap"
243
  ]
244
  },
245
  "datatables-select": {
246
+ "url": "https://cdn.datatables.net/select/1.3.4/js/dataTables.select.min.js",
247
  "deps": [
248
  "datatables-bootstrap"
249
  ]
250
  },
251
  "datatables-buttons": {
252
+ "url": "https://cdn.datatables.net/buttons/2.2.2/js/dataTables.buttons.min.js",
253
  "deps": [
254
  "datatables-bootstrap"
255
  ]
362
  "datatables-select",
363
  "datatables-buttons",
364
  "datatables-bootstrap",
365
+ "datatables-searchpanes",
366
  "tp/highlightjs"
367
  ]
368
  },
467
  }
468
  ],
469
  "version_upgrades": [
470
+ "14.1.0",
471
  "11.2.0",
472
  "12.0.0",
473
  "12.0.1",
readme.txt CHANGED
@@ -8,7 +8,7 @@ Requires at least: 3.7
8
  Requires PHP: 7.0
9
  Recommended PHP: 7.4
10
  Tested up to: 5.9
11
- Stable tag: 14.0.3
12
 
13
  No-Nonsense Security Hardening that protects WordPress against hackers, malicious bots, and spammers (no captchas!). Now with exclusive ShieldNET Technology.
14
 
8
  Requires PHP: 7.0
9
  Recommended PHP: 7.4
10
  Tested up to: 5.9
11
+ Stable tag: 14.1.0
12
 
13
  No-Nonsense Security Hardening that protects WordPress against hackers, malicious bots, and spammers (no captchas!). Now with exclusive ShieldNET Technology.
14
 
resources/css/global-plugin.css CHANGED
@@ -59,6 +59,7 @@
59
  .notice-icon {
60
  display: block;
61
  }
 
62
  .notice-content {
63
  margin-left: 62px;
64
  }
@@ -347,10 +348,14 @@ tr.icwp-plugin-vulnerability dd {
347
  }
348
  #wpadminbar .shield-counter {
349
  display: inline;
350
- padding: 1px 7px 1px 6px!important;
351
  border-radius: 50%;
352
  margin-left: 6px;
353
  /*background-color: rgb(0, 128, 0);*/
354
  }
355
 
 
 
 
 
356
  /* override boostrap */
59
  .notice-icon {
60
  display: block;
61
  }
62
+
63
  .notice-content {
64
  margin-left: 62px;
65
  }
348
  }
349
  #wpadminbar .shield-counter {
350
  display: inline;
351
+ padding: 1px 7px 1px 6px !important;
352
  border-radius: 50%;
353
  margin-left: 6px;
354
  /*background-color: rgb(0, 128, 0);*/
355
  }
356
 
357
+ #wp-admin-bar-icwp-wpsf-adminbarmenu .ab-submenu > li {
358
+ padding: 0 0 5px;
359
+ }
360
+
361
  /* override boostrap */
resources/js/shield/audit_trail.js CHANGED
@@ -135,15 +135,18 @@
135
  this.$table = this.$el.DataTable(
136
  $.extend( base.options.datatables_init,
137
  {
 
 
138
  ajax: function ( data, callback, settings ) {
139
  iCWP_WPSF_BodyOverlay.show();
140
  let reqData = base.getBaseAjaxData();
141
  reqData.sub_action = 'retrieve_table_data';
142
  reqData.type = base.options.type;
143
  reqData.file = base.options.file;
 
144
  $.post( ajaxurl, reqData, function ( response ) {
145
  if ( response.success ) {
146
- callback( response.data.vars );
147
  }
148
  else {
149
  let msg = 'Communications error with site.';
@@ -163,10 +166,13 @@
163
  },
164
  dom: 'PBfrptip',
165
  searchPanes: {
166
- cascadePanes: true,
167
- viewTotal: true,
 
168
  initCollapsed: true
169
  },
 
 
170
  buttons: [
171
  {
172
  text: 'Reload',
135
  this.$table = this.$el.DataTable(
136
  $.extend( base.options.datatables_init,
137
  {
138
+ serverSide: true,
139
+ searchDelay: 600,
140
  ajax: function ( data, callback, settings ) {
141
  iCWP_WPSF_BodyOverlay.show();
142
  let reqData = base.getBaseAjaxData();
143
  reqData.sub_action = 'retrieve_table_data';
144
  reqData.type = base.options.type;
145
  reqData.file = base.options.file;
146
+ reqData.table_data = data;
147
  $.post( ajaxurl, reqData, function ( response ) {
148
  if ( response.success ) {
149
+ callback( response.data.datatable_data );
150
  }
151
  else {
152
  let msg = 'Communications error with site.';
166
  },
167
  dom: 'PBfrptip',
168
  searchPanes: {
169
+ cascadePanes: false,
170
+ viewTotal: false,
171
+ viewCount: false,
172
  initCollapsed: true
173
  },
174
+ search: {
175
+ },
176
  buttons: [
177
  {
178
  text: 'Reload',
resources/js/shield/traffic.js CHANGED
@@ -99,14 +99,17 @@
99
  this.$table = this.$el.DataTable(
100
  $.extend( base.options.datatables_init,
101
  {
 
 
102
  ajax: function ( data, callback, settings ) {
103
  let reqData = base.getBaseAjaxData();
104
  reqData.sub_action = 'retrieve_table_data';
105
  reqData.type = base.options.type;
106
  reqData.file = base.options.file;
 
107
  $.post( ajaxurl, reqData, function ( response ) {
108
  if ( response.success ) {
109
- callback( response.data.vars );
110
  }
111
  else {
112
  let msg = 'Communications error with site.';
@@ -123,10 +126,13 @@
123
  },
124
  dom: 'PBfrptip',
125
  searchPanes: {
126
- cascadePanes: true,
127
- viewTotal: true,
 
128
  initCollapsed: true
129
  },
 
 
130
  buttons: [
131
  {
132
  text: 'Reload',
99
  this.$table = this.$el.DataTable(
100
  $.extend( base.options.datatables_init,
101
  {
102
+ serverSide: true,
103
+ searchDelay: 600,
104
  ajax: function ( data, callback, settings ) {
105
  let reqData = base.getBaseAjaxData();
106
  reqData.sub_action = 'retrieve_table_data';
107
  reqData.type = base.options.type;
108
  reqData.file = base.options.file;
109
+ reqData.table_data = data;
110
  $.post( ajaxurl, reqData, function ( response ) {
111
  if ( response.success ) {
112
+ callback( response.data.datatable_data );
113
  }
114
  else {
115
  let msg = 'Communications error with site.';
126
  },
127
  dom: 'PBfrptip',
128
  searchPanes: {
129
+ cascadePanes: false,
130
+ viewTotal: false,
131
+ viewCount: false,
132
  initCollapsed: true
133
  },
134
+ search: {
135
+ },
136
  buttons: [
137
  {
138
  text: 'Reload',
src/lib/src/Controller/Admin/AdminBarMenu.php CHANGED
@@ -12,39 +12,51 @@ class AdminBarMenu {
12
 
13
  protected function canRun() :bool {
14
  $con = $this->getCon();
15
- return $con->isValidAdminArea( true ) &&
16
  apply_filters( $con->prefix( 'shield/show_admin_bar_menu' ), $con->cfg->properties[ 'show_admin_bar_menu' ] );
17
  }
18
 
19
  protected function run() {
20
  add_action( 'admin_bar_menu', function ( $adminBar ) {
21
- $this->createAdminBarMenu( $adminBar );
 
 
22
  }, 100 );
23
  }
24
 
25
- /**
26
- * @param \WP_Admin_Bar $adminBar
27
- */
28
- private function createAdminBarMenu( $adminBar ) {
29
  $con = $this->getCon();
30
 
31
- $items = apply_filters( $con->prefix( 'admin_bar_menu_items' ), [] );
32
- if ( !empty( $items ) && is_array( $items ) ) {
33
- $warningCount = 0;
34
- foreach ( $items as $item ) {
35
- $warningCount += $item[ 'warnings' ] ?? 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  }
37
 
38
- $nodeId = $con->prefix( 'adminbarmenu' );
39
  $adminBar->add_node( [
40
- 'id' => $nodeId,
41
- 'title' => $con->getHumanName()
42
- .sprintf( '<div class="wp-core-ui wp-ui-notification shield-counter"><span aria-hidden="true">%s</span></div>', $warningCount ),
 
 
43
  ] );
44
- foreach ( $items as $item ) {
45
- $item[ 'parent' ] = $nodeId;
46
- $adminBar->add_menu( $item );
47
- }
48
  }
49
  }
50
  }
12
 
13
  protected function canRun() :bool {
14
  $con = $this->getCon();
15
+ return $con->getMeetsBasePermissions() &&
16
  apply_filters( $con->prefix( 'shield/show_admin_bar_menu' ), $con->cfg->properties[ 'show_admin_bar_menu' ] );
17
  }
18
 
19
  protected function run() {
20
  add_action( 'admin_bar_menu', function ( $adminBar ) {
21
+ if ( $adminBar instanceof \WP_Admin_Bar ) {
22
+ $this->createAdminBarMenu( $adminBar );
23
+ }
24
  }, 100 );
25
  }
26
 
27
+ private function createAdminBarMenu( \WP_Admin_Bar $adminBar ) {
 
 
 
28
  $con = $this->getCon();
29
 
30
+ $groups = array_filter( apply_filters( $con->prefix( 'admin_bar_menu_groups' ), [] ) );
31
+ $totalWarnings = 0;
32
+
33
+ if ( !empty( $groups ) ) {
34
+
35
+ $topNodeID = $con->prefix( 'adminbarmenu' );
36
+
37
+ foreach ( $groups as $key => $group ) {
38
+
39
+ $group[ 'id' ] = $con->prefix( 'adminbarmenu-sub'.$key );
40
+
41
+ foreach ( $group[ 'items' ] as $item ) {
42
+ $totalWarnings += $item[ 'warnings' ] ?? 0;
43
+ $item[ 'parent' ] = $group[ 'id' ];
44
+ $adminBar->add_node( $item );
45
+ }
46
+
47
+ unset( $group[ 'items' ] );
48
+ $group[ 'parent' ] = $topNodeID;
49
+ $adminBar->add_node( $group );
50
  }
51
 
52
+ // The top menu item.
53
  $adminBar->add_node( [
54
+ 'id' => $topNodeID,
55
+ 'title' => sprintf( '%s %s', $con->getHumanName(),
56
+ empty( $totalWarnings ) ? '' : sprintf( '<div class="wp-core-ui wp-ui-notification shield-counter"><span aria-hidden="true">%s</span></div>', $totalWarnings )
57
+ ),
58
+ 'href' => $con->getPluginUrl_DashboardHome()
59
  ] );
 
 
 
 
60
  }
61
  }
62
  }
src/lib/src/Controller/Assets/Enqueue.php CHANGED
@@ -45,6 +45,35 @@ class Enqueue {
45
  $this->dequeue();
46
  }, -1000 );
47
  }, 1000 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  }
49
 
50
  protected function dequeue() {
45
  $this->dequeue();
46
  }, -1000 );
47
  }, 1000 );
48
+
49
+ add_action( 'admin_enqueue_scripts', function () {
50
+ if ( $this->getCon()->getIsPage_PluginAdmin() ) {
51
+ global $wp_scripts;
52
+ global $wp_styles;
53
+ $this->removeConflictingAdminAssets( $wp_scripts );
54
+ $this->removeConflictingAdminAssets( $wp_styles );
55
+ }
56
+ }, PHP_INT_MAX );
57
+ }
58
+
59
+ /**
60
+ * @param \WP_Styles|\WP_Scripts $depContainer
61
+ */
62
+ private function removeConflictingAdminAssets( $depContainer ) {
63
+ $toDequeue = [];
64
+ $prefix = $this->getCon()->prefix();
65
+ $conflictHandles = array_map( 'preg_quote', [
66
+ 'bootstrap',
67
+ 'wp-notes',
68
+ ] );
69
+ foreach ( $depContainer->queue as $script ) {
70
+ $handle = (string)$depContainer->registered[ $script ]->handle;
71
+ if ( strpos( $handle, $prefix ) === false
72
+ && preg_match( sprintf( '/(%s)/i', implode( '|', $conflictHandles ) ), $handle ) ) {
73
+ $toDequeue[] = $handle;
74
+ }
75
+ }
76
+ $depContainer->dequeue( $toDequeue );
77
  }
78
 
79
  protected function dequeue() {
src/lib/src/Controller/Config/ConfigVO.php CHANGED
@@ -5,8 +5,6 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Controller\Config;
5
  use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
6
 
7
  /**
8
- * Class ConfigVO
9
- * @package FernleafSystems\Wordpress\Plugin\Shield\Controller\Config
10
  * @property array $properties
11
  * @property array $requirements
12
  * @property array $paths
@@ -18,6 +16,7 @@ use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
18
  * @property array $plugin_meta
19
  * @property array $upgrade_reqs
20
  * @property array $version_upgrades
 
21
  * -- not part of config file --
22
  * @property string $hash
23
  * @property string $previous_version
5
  use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
6
 
7
  /**
 
 
8
  * @property array $properties
9
  * @property array $requirements
10
  * @property array $paths
16
  * @property array $plugin_meta
17
  * @property array $upgrade_reqs
18
  * @property array $version_upgrades
19
+ * @property array $reqs_rest
20
  * -- not part of config file --
21
  * @property string $hash
22
  * @property string $previous_version
src/lib/src/Controller/Controller.php CHANGED
@@ -18,6 +18,7 @@ use FernleafSystems\Wordpress\Services\Utilities\Options\Transient;
18
  * @property bool $is_mode_staging
19
  * @property bool $is_mode_live
20
  * @property bool $is_my_upgrade
 
21
  * @property bool $modules_loaded
22
  * @property bool $plugin_deactivating
23
  * @property bool $plugin_deleting
@@ -29,6 +30,7 @@ use FernleafSystems\Wordpress\Services\Utilities\Options\Transient;
29
  * @property string $base_file
30
  * @property string $root_file
31
  * @property Shield\Modules\Integrations\Lib\MainWP\Common\MainWPVO $mwpVO
 
32
  * @property Shield\Utilities\Nonce\Handler $nonce_handler
33
  * @property Shield\Modules\Events\Lib\EventsService $service_events
34
  * @property Shield\Users\UserMetas $user_metas
@@ -59,11 +61,6 @@ class Controller extends DynPropertiesClass {
59
  */
60
  protected $oNotices;
61
 
62
- /**
63
- * @var Shield\Modules\Events\Lib\EventsService
64
- */
65
- private $oEventsService;
66
-
67
  public function fireEvent( string $event, array $meta = [] ) :self {
68
  $this->loadEventsService()->fireEvent( $event, $meta );
69
  return $this;
@@ -97,7 +94,6 @@ class Controller extends DynPropertiesClass {
97
  }
98
 
99
  /**
100
- * @param string $rootFile
101
  * @throws \Exception
102
  */
103
  protected function __construct( string $rootFile ) {
@@ -106,6 +102,9 @@ class Controller extends DynPropertiesClass {
106
  $this->modules = [];
107
 
108
  $this->loadServices();
 
 
 
109
  $this->loadConfig();
110
 
111
  $this->checkMinimumRequirements();
@@ -117,7 +116,6 @@ class Controller extends DynPropertiesClass {
117
  }
118
 
119
  /**
120
- * @param string $key
121
  * @return mixed
122
  */
123
  public function __get( string $key ) {
@@ -136,6 +134,15 @@ class Controller extends DynPropertiesClass {
136
  $val = (bool)$val;
137
  break;
138
 
 
 
 
 
 
 
 
 
 
139
  case 'cache_dir_handler':
140
  if ( empty( $val ) ) {
141
  $val = ( new Shield\Utilities\CacheDir() )->setCon( $this );
@@ -200,6 +207,14 @@ class Controller extends DynPropertiesClass {
200
  }
201
  break;
202
 
 
 
 
 
 
 
 
 
203
  case 'reqs_not_met':
204
  if ( !is_array( $val ) ) {
205
  $val = [];
@@ -376,14 +391,6 @@ class Controller extends DynPropertiesClass {
376
  return $path;
377
  }
378
 
379
- /**
380
- * @deprecated 14
381
- */
382
- public function hasCacheDir() :bool {
383
- return !empty( $this->getPluginCachePath() );
384
- // return $this->cache_dir_handler->dirExists();
385
- }
386
-
387
  protected function doRegisterHooks() {
388
  register_deactivation_hook( $this->getRootFile(), [ $this, 'onWpDeactivatePlugin' ] );
389
 
@@ -559,13 +566,7 @@ class Controller extends DynPropertiesClass {
559
  return $this->oNotices;
560
  }
561
 
562
- /**
563
- * @throws \Exception
564
- */
565
- public function getNonceActionData( string $action = '' ) :array {
566
- if ( empty( $action ) ) {
567
- throw new \Exception( 'Empty actions are not allowed.' );
568
- }
569
  return [
570
  'action' => $this->prefix(), //wp ajax doesn't work without this.
571
  'exec' => $action,
@@ -583,8 +584,8 @@ class Controller extends DynPropertiesClass {
583
 
584
  if ( $pluginFile === $this->base_file ) {
585
  $template = '<strong><a href="%s" target="_blank">%s</a></strong>';
586
- foreach ( $this->cfg->plugin_meta as $aHref ) {
587
- array_push( $pluginMeta, sprintf( $template, $aHref[ 'href' ], $aHref[ 'name' ] ) );
588
  }
589
  }
590
  return $pluginMeta;
@@ -595,6 +596,18 @@ class Controller extends DynPropertiesClass {
595
  * @return array
596
  */
597
  public function onWpPluginActionLinks( $actionLinks ) {
 
 
 
 
 
 
 
 
 
 
 
 
598
 
599
  if ( $this->isValidAdminArea() ) {
600
 
@@ -607,9 +620,9 @@ class Controller extends DynPropertiesClass {
607
 
608
  $isPro = $this->isPremiumActive();
609
  $DP = Services::Data();
610
- $sLinkTemplate = '<a href="%s" target="%s" title="%s">%s</a>';
611
- foreach ( $links as $aLink ) {
612
- $aLink = array_merge(
613
  [
614
  'highlight' => false,
615
  'show' => 'always',
@@ -618,29 +631,29 @@ class Controller extends DynPropertiesClass {
618
  'href' => '',
619
  'target' => '_top',
620
  ],
621
- $aLink
622
  );
623
 
624
- $show = $aLink[ 'show' ];
625
- $bShow = ( $show == 'always' ) || ( $isPro && $show == 'pro' ) || ( !$isPro && $show == 'free' );
626
- if ( !$DP->isValidWebUrl( $aLink[ 'href' ] ) && method_exists( $this, $aLink[ 'href' ] ) ) {
627
- $aLink[ 'href' ] = $this->{$aLink[ 'href' ]}();
628
  }
629
 
630
- if ( !$bShow || !$DP->isValidWebUrl( $aLink[ 'href' ] )
631
- || empty( $aLink[ 'name' ] ) || empty( $aLink[ 'href' ] ) ) {
632
  continue;
633
  }
634
 
635
- $aLink[ 'name' ] = __( $aLink[ 'name' ], 'wp-simple-firewall' );
636
 
637
- $sLink = sprintf( $sLinkTemplate, $aLink[ 'href' ], $aLink[ 'target' ], $aLink[ 'title' ], $aLink[ 'name' ] );
638
- if ( $aLink[ 'highlight' ] ) {
639
- $sLink = sprintf( '<span style="font-weight: bold;">%s</span>', $sLink );
640
  }
641
 
642
  $actionLinks = array_merge(
643
- [ $this->prefix( sanitize_key( $aLink[ 'name' ] ) ) => $sLink ],
644
  $actionLinks
645
  );
646
  }
18
  * @property bool $is_mode_staging
19
  * @property bool $is_mode_live
20
  * @property bool $is_my_upgrade
21
+ * @property bool $is_rest_enabled
22
  * @property bool $modules_loaded
23
  * @property bool $plugin_deactivating
24
  * @property bool $plugin_deleting
30
  * @property string $base_file
31
  * @property string $root_file
32
  * @property Shield\Modules\Integrations\Lib\MainWP\Common\MainWPVO $mwpVO
33
+ * @property Shield\Utilities\MU\MUHandler $mu_handler
34
  * @property Shield\Utilities\Nonce\Handler $nonce_handler
35
  * @property Shield\Modules\Events\Lib\EventsService $service_events
36
  * @property Shield\Users\UserMetas $user_metas
61
  */
62
  protected $oNotices;
63
 
 
 
 
 
 
64
  public function fireEvent( string $event, array $meta = [] ) :self {
65
  $this->loadEventsService()->fireEvent( $event, $meta );
66
  return $this;
94
  }
95
 
96
  /**
 
97
  * @throws \Exception
98
  */
99
  protected function __construct( string $rootFile ) {
102
  $this->modules = [];
103
 
104
  $this->loadServices();
105
+ if ( $this->mu_handler->isActiveMU() && !Services::WpPlugins()->isActive( $this->base_file ) ) {
106
+ Services::WpPlugins()->activate( $this->base_file );
107
+ }
108
  $this->loadConfig();
109
 
110
  $this->checkMinimumRequirements();
116
  }
117
 
118
  /**
 
119
  * @return mixed
120
  */
121
  public function __get( string $key ) {
134
  $val = (bool)$val;
135
  break;
136
 
137
+ case 'is_rest_enabled':
138
+ if ( is_null( $val ) ) {
139
+ $restReqs = $this->cfg->reqs_rest;
140
+ $val = Services::WpGeneral()->getWordpressIsAtLeastVersion( $restReqs[ 'wp' ] )
141
+ && Services::Data()->getPhpVersionIsAtLeast( $restReqs[ 'php' ] );
142
+ $this->is_rest_enabled = $val;
143
+ }
144
+ break;
145
+
146
  case 'cache_dir_handler':
147
  if ( empty( $val ) ) {
148
  $val = ( new Shield\Utilities\CacheDir() )->setCon( $this );
207
  }
208
  break;
209
 
210
+ case 'mu_handler':
211
+ if ( is_null( $val ) ) {
212
+ $val = ( new Shield\Utilities\MU\MUHandler() )
213
+ ->setCon( $this );
214
+ $this->mu_handler = $val;
215
+ }
216
+ break;
217
+
218
  case 'reqs_not_met':
219
  if ( !is_array( $val ) ) {
220
  $val = [];
391
  return $path;
392
  }
393
 
 
 
 
 
 
 
 
 
394
  protected function doRegisterHooks() {
395
  register_deactivation_hook( $this->getRootFile(), [ $this, 'onWpDeactivatePlugin' ] );
396
 
566
  return $this->oNotices;
567
  }
568
 
569
+ public function getNonceActionData( string $action ) :array {
 
 
 
 
 
 
570
  return [
571
  'action' => $this->prefix(), //wp ajax doesn't work without this.
572
  'exec' => $action,
584
 
585
  if ( $pluginFile === $this->base_file ) {
586
  $template = '<strong><a href="%s" target="_blank">%s</a></strong>';
587
+ foreach ( $this->cfg->plugin_meta as $href ) {
588
+ $pluginMeta[] = sprintf( $template, $href[ 'href' ], $href[ 'name' ] );
589
  }
590
  }
591
  return $pluginMeta;
596
  * @return array
597
  */
598
  public function onWpPluginActionLinks( $actionLinks ) {
599
+ $WP = Services::WpGeneral();
600
+
601
+ if ( $this->mu_handler->isActiveMU() ) {
602
+ foreach ( $actionLinks as $key => $actionHref ) {
603
+ if ( strpos( $actionHref, 'action=deactivate' ) ) {
604
+ $actionLinks[ $key ] = sprintf( '<a href="%s">%s</a>',
605
+ add_query_arg( [ 'plugin_status' => 'mustuse' ], $WP->getAdminUrl_Plugins() ),
606
+ __( 'Disable MU To Deactivate', 'wp-simple-firewall' )
607
+ );
608
+ }
609
+ }
610
+ }
611
 
612
  if ( $this->isValidAdminArea() ) {
613
 
620
 
621
  $isPro = $this->isPremiumActive();
622
  $DP = Services::Data();
623
+ $linkTemplate = '<a href="%s" target="%s" title="%s">%s</a>';
624
+ foreach ( $links as $link ) {
625
+ $link = array_merge(
626
  [
627
  'highlight' => false,
628
  'show' => 'always',
631
  'href' => '',
632
  'target' => '_top',
633
  ],
634
+ $link
635
  );
636
 
637
+ $show = $link[ 'show' ];
638
+ $show = ( $show == 'always' ) || ( $isPro && $show == 'pro' ) || ( !$isPro && $show == 'free' );
639
+ if ( !$DP->isValidWebUrl( $link[ 'href' ] ) && method_exists( $this, $link[ 'href' ] ) ) {
640
+ $link[ 'href' ] = $this->{$link[ 'href' ]}();
641
  }
642
 
643
+ if ( !$show || !$DP->isValidWebUrl( $link[ 'href' ] )
644
+ || empty( $link[ 'name' ] ) || empty( $link[ 'href' ] ) ) {
645
  continue;
646
  }
647
 
648
+ $link[ 'name' ] = __( $link[ 'name' ], 'wp-simple-firewall' );
649
 
650
+ $href = sprintf( $linkTemplate, $link[ 'href' ], $link[ 'target' ], $link[ 'title' ], $link[ 'name' ] );
651
+ if ( $link[ 'highlight' ] ) {
652
+ $href = sprintf( '<span style="font-weight: bold;">%s</span>', $href );
653
  }
654
 
655
  $actionLinks = array_merge(
656
+ [ $this->prefix( sanitize_key( $link[ 'name' ] ) ) => $href ],
657
  $actionLinks
658
  );
659
  }
src/lib/src/Databases/IPs/CommonFilters.php CHANGED
@@ -15,11 +15,11 @@ trait CommonFilters {
15
  }
16
 
17
  /**
18
- * @param bool $bIsBlocked
19
  * @return $this
20
  */
21
- public function filterByBlocked( $bIsBlocked ) {
22
- return $this->addWhere( 'blocked_at', 0, $bIsBlocked ? '>' : '=' );
23
  }
24
 
25
  /**
15
  }
16
 
17
  /**
18
+ * @param bool $isBlocked
19
  * @return $this
20
  */
21
+ public function filterByBlocked( $isBlocked ) {
22
+ return $this->addWhere( 'blocked_at', 0, $isBlocked ? '>' : '=' );
23
  }
24
 
25
  /**
src/lib/src/Databases/IPs/EntryVO.php CHANGED
@@ -5,7 +5,6 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\IPs;
5
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
6
 
7
  /**
8
- * Class EntryVO
9
  * @property string $ip
10
  * @property int $transgressions
11
  * @property bool $is_range
5
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
6
 
7
  /**
 
8
  * @property string $ip
9
  * @property int $transgressions
10
  * @property bool $is_range
src/lib/src/Databases/IPs/Select.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\IPs;
4
 
1
+ <?php declare( strict_types=1 );
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\IPs;
4
 
src/lib/src/Logging/Processors/RequestMetaProcessor.php CHANGED
@@ -2,6 +2,7 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Logging\Processors;
4
 
 
5
  use FernleafSystems\Wordpress\Services\Services;
6
  use Monolog\Processor\ProcessorInterface;
7
 
@@ -11,28 +12,58 @@ class RequestMetaProcessor implements ProcessorInterface {
11
  * @return array
12
  */
13
  public function __invoke( array $record ) {
14
- $isWpCli = Services::WpGeneral()->isWpCli();
 
15
 
16
  $req = Services::Request();
17
  $leadingPath = Services::WpGeneral()->isMultisite_SubdomainInstall() ? $req->getHost() : '';
18
 
19
  if ( $isWpCli ) {
20
  global $argv;
21
- $path = implode( ' ', $argv );
 
22
  }
23
  else {
24
- $path = ( $leadingPath.$req->getPath().( empty( $_GET ) ? '' : '?'.http_build_query( $_GET ) ) );
 
25
  }
26
 
27
- $record[ 'extra' ][ 'meta_request' ] = [
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  'ip' => $isWpCli ? '' : (string)Services::IP()->getRequestIp(),
29
- 'rid' => Services::Request()->getID( true, 10 ),
30
  'ts' => microtime( true ),
31
- 'ua' => $isWpCli ? 'wpcli' : $req->getUserAgent(),
32
- 'verb' => $isWpCli ? '' : strtoupper( $req->getMethod() ),
33
  'path' => $path,
34
- 'code' => $isWpCli ? '' : http_response_code(),
35
  ];
 
 
 
 
 
 
 
 
 
 
36
 
37
  return $record;
38
  }
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Logging\Processors;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\DB\ReqLogs\Ops\Handler;
6
  use FernleafSystems\Wordpress\Services\Services;
7
  use Monolog\Processor\ProcessorInterface;
8
 
12
  * @return array
13
  */
14
  public function __invoke( array $record ) {
15
+ $WP = Services::WpGeneral();
16
+ $isWpCli = $WP->isWpCli();
17
 
18
  $req = Services::Request();
19
  $leadingPath = Services::WpGeneral()->isMultisite_SubdomainInstall() ? $req->getHost() : '';
20
 
21
  if ( $isWpCli ) {
22
  global $argv;
23
+ $path = $argv[ 0 ];
24
+ $query = count( $argv ) === 1 ? '' : implode( ' ', array_slice( $argv, 1 ) );
25
  }
26
  else {
27
+ $path = $leadingPath.$req->getPath();
28
+ $query = empty( $_GET ) ? '' : http_build_query( $_GET );
29
  }
30
 
31
+ if ( $isWpCli ) {
32
+ $type = Handler::TYPE_WPCLI;
33
+ }
34
+ elseif ( $WP->isAjax() ) {
35
+ $type = Handler::TYPE_AJAX;
36
+ }
37
+ elseif ( Services::Rest()->isRest() ) {
38
+ $type = Handler::TYPE_REST;
39
+ }
40
+ elseif ( $WP->isXmlrpc() ) {
41
+ $type = Handler::TYPE_XMLRPC;
42
+ }
43
+ elseif ( $WP->isCron() ) {
44
+ $type = Handler::TYPE_CRON;
45
+ }
46
+ else {
47
+ $type = Handler::TYPE_HTTP;
48
+ }
49
+
50
+ $data = [
51
  'ip' => $isWpCli ? '' : (string)Services::IP()->getRequestIp(),
52
+ 'rid' => Services::Request()->getID( true ),
53
  'ts' => microtime( true ),
 
 
54
  'path' => $path,
55
+ 'type' => $type,
56
  ];
57
+ if ( !$isWpCli ) {
58
+ $data[ 'ua' ] = $req->getUserAgent();
59
+ $data[ 'code' ] = http_response_code();
60
+ $data[ 'verb' ] = strtoupper( $req->getMethod() );
61
+ }
62
+ if ( !empty( $query ) ) {
63
+ $data[ 'query' ] = $query;
64
+ }
65
+
66
+ $record[ 'extra' ][ 'meta_request' ] = $data;
67
 
68
  return $record;
69
  }
src/lib/src/Modules/AuditTrail/Auditors/Plugins.php CHANGED
@@ -6,12 +6,27 @@ use FernleafSystems\Wordpress\Services\Services;
6
 
7
  class Plugins extends Base {
8
 
 
 
9
  protected function run() {
 
 
10
  add_action( 'deactivated_plugin', [ $this, 'auditDeactivatedPlugin' ] );
11
  add_action( 'activated_plugin', [ $this, 'auditActivatedPlugin' ] );
12
  add_action( 'wp_ajax_edit-theme-plugin-file', [ $this, 'auditEditedFile' ], -1 ); // they hook on 1
13
  }
14
 
 
 
 
 
 
 
 
 
 
 
 
15
  /**
16
  * @param string $plugin
17
  */
6
 
7
  class Plugins extends Base {
8
 
9
+ private $slugs;
10
+
11
  protected function run() {
12
+ $this->slugs = Services::WpPlugins()->getInstalledPluginFiles();
13
+ add_action( 'upgrader_process_complete', [ $this, 'auditInstall' ], 10, 0 );
14
  add_action( 'deactivated_plugin', [ $this, 'auditDeactivatedPlugin' ] );
15
  add_action( 'activated_plugin', [ $this, 'auditActivatedPlugin' ] );
16
  add_action( 'wp_ajax_edit-theme-plugin-file', [ $this, 'auditEditedFile' ], -1 ); // they hook on 1
17
  }
18
 
19
+ public function auditInstall() {
20
+ $current = Services::WpPlugins()->getInstalledPluginFiles();
21
+ foreach ( array_diff( $current, $this->slugs ) as $new ) {
22
+ $this->getCon()->fireEvent(
23
+ 'plugin_installed',
24
+ [ 'audit_params' => [ 'plugin' => $new ] ]
25
+ );
26
+ }
27
+ $this->slugs = $current;
28
+ }
29
+
30
  /**
31
  * @param string $plugin
32
  */
src/lib/src/Modules/AuditTrail/Auditors/Themes.php CHANGED
@@ -6,11 +6,26 @@ use FernleafSystems\Wordpress\Services\Services;
6
 
7
  class Themes extends Base {
8
 
 
 
9
  protected function run() {
 
 
10
  add_action( 'switch_theme', [ $this, 'auditSwitchTheme' ] );
11
  add_action( 'wp_ajax_edit-theme-plugin-file', [ $this, 'auditEditedFile' ], -1 ); // they hook on 1
12
  }
13
 
 
 
 
 
 
 
 
 
 
 
 
14
  /**
15
  * @param string $themeName
16
  */
6
 
7
  class Themes extends Base {
8
 
9
+ private $slugs;
10
+
11
  protected function run() {
12
+ $this->slugs = Services::WpThemes()->getInstalledStylesheets();
13
+ add_action( 'upgrader_process_complete', [ $this, 'auditInstall' ], 10, 0 );
14
  add_action( 'switch_theme', [ $this, 'auditSwitchTheme' ] );
15
  add_action( 'wp_ajax_edit-theme-plugin-file', [ $this, 'auditEditedFile' ], -1 ); // they hook on 1
16
  }
17
 
18
+ public function auditInstall() {
19
+ $current = Services::WpThemes()->getInstalledStylesheets();
20
+ foreach ( array_diff( $current, $this->slugs ) as $new ) {
21
+ $this->getCon()->fireEvent(
22
+ 'theme_installed',
23
+ [ 'audit_params' => [ 'theme' => $new ] ]
24
+ );
25
+ }
26
+ $this->slugs = $current;
27
+ }
28
+
29
  /**
30
  * @param string $themeName
31
  */
src/lib/src/Modules/AuditTrail/Auditors/Users.php CHANGED
@@ -15,6 +15,21 @@ class Users extends Base {
15
 
16
  add_action( 'user_register', [ $this, 'auditNewUserRegistered' ] );
17
  add_action( 'delete_user', [ $this, 'auditDeleteUser' ], 30, 2 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  }
19
 
20
  protected function captureLogin( \WP_User $user ) {
@@ -79,4 +94,32 @@ class Users extends Base {
79
  );
80
  }
81
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  }
15
 
16
  add_action( 'user_register', [ $this, 'auditNewUserRegistered' ] );
17
  add_action( 'delete_user', [ $this, 'auditDeleteUser' ], 30, 2 );
18
+
19
+ if ( Services::WpGeneral()->getWordpressIsAtLeastVersion( '5.6' ) ) {
20
+ add_action( 'application_password_failed_authentication', function ( $wpError ) {
21
+ /** @var \WP_Error $wpError */
22
+ if ( is_wp_error( $wpError ) && $wpError->has_errors() ) {
23
+ $this->auditFailedAppPassword( $wpError );
24
+ }
25
+ } );
26
+ add_action( 'application_password_did_authenticate', function ( $user ) {
27
+ /** @var \WP_Error $wpError */
28
+ if ( $user instanceof \WP_User ) {
29
+ $this->auditSuccessAppPassword( $user );
30
+ }
31
+ } );
32
+ }
33
  }
34
 
35
  protected function captureLogin( \WP_User $user ) {
94
  );
95
  }
96
  }
97
+
98
+ private function auditSuccessAppPassword( \WP_User $user ) {
99
+ $this->getCon()->fireEvent(
100
+ 'user_login_app',
101
+ [
102
+ 'audit_params' => [
103
+ 'user_login' => $user->user_login,
104
+ ]
105
+ ]
106
+ );
107
+ }
108
+
109
+ private function auditFailedAppPassword( \WP_Error $error ) {
110
+
111
+ $wpErrorToEventMap = [
112
+ 'invalid_email' => 'app_invalid_email',
113
+ 'invalid_username' => 'app_invalid_username',
114
+ 'incorrect_password' => 'app_incorrect_password',
115
+ 'application_passwords_disabled' => 'app_passwords_disabled',
116
+ 'application_passwords_disabled_for_user' => 'app_passwords_disabled_user',
117
+ ];
118
+
119
+ foreach ( $error->get_error_codes() as $code ) {
120
+ if ( isset( $wpErrorToEventMap[ $code ] ) ) {
121
+ $this->getCon()->fireEvent( $wpErrorToEventMap[ $code ] );
122
+ }
123
+ }
124
+ }
125
  }
src/lib/src/Modules/AuditTrail/DB/LoadLogs.php CHANGED
@@ -2,23 +2,32 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\DB;
4
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\ModCon;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Components\IpAddressConsumer;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
8
  use FernleafSystems\Wordpress\Services\Services;
9
 
10
- class LoadLogs {
 
 
 
 
 
 
 
11
 
12
- const DEFAULT_LIMIT = 10000;
13
  use ModConsumer;
14
  use IpAddressConsumer;
15
 
16
- private $limit = null;
17
 
18
  /**
19
  * @return LogRecord[]
20
  */
21
- public function run() :array {
 
 
22
  /** @var ModCon $mod */
23
  $mod = $this->getMod();
24
  $stdKeys = array_flip( array_unique( array_merge(
@@ -66,34 +75,71 @@ class LoadLogs {
66
  /** @var ModCon $mod */
67
  $mod = $this->getMod();
68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  return Services::WpDb()->selectCustom(
70
- sprintf( 'SELECT log.id, log.site_id, log.event_slug, log.created_at,
71
- ips.ip,
72
- meta.meta_key, meta.meta_value,
73
- req.req_id as rid
74
- FROM `%s` as log
75
- INNER JOIN `%s` as req
76
- ON log.req_ref = req.id
77
- INNER JOIN `%s` as ips
78
- ON ips.id = req.ip_ref
79
- %s
80
- LEFT JOIN `%s` as `meta`
81
- ON log.id = `meta`.log_ref
82
- ORDER BY log.updated_at DESC
83
- %s
84
- ',
 
 
 
 
 
 
85
  $mod->getDbH_Logs()->getTableSchema()->table,
86
  $this->getCon()->getModule_Data()->getDbH_ReqLogs()->getTableSchema()->table,
87
  $this->getCon()->getModule_Data()->getDbH_IPs()->getTableSchema()->table,
88
  empty( $this->getIP() ) ? '' : sprintf( "AND ips.ip=INET6_ATON('%s')", $this->getIP() ),
89
- $mod->getDbH_Meta()->getTableSchema()->table,
90
- ( $this->limit === 0 ) ? '' : sprintf( 'LIMIT %s', is_null( $this->limit ) ? self::DEFAULT_LIMIT : $this->limit )
 
 
 
91
  )
92
  );
93
  }
94
 
95
- public function setLimit( int $limit ) {
96
- $this->limit = $limit;
97
- return $this;
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  }
99
  }
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\DB;
4
 
5
+ use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\ModCon;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Components\IpAddressConsumer;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
9
  use FernleafSystems\Wordpress\Services\Services;
10
 
11
+ /**
12
+ * @property int $limit
13
+ * @property int $offset
14
+ * @property string[] $wheres
15
+ * @property string $order_by
16
+ * @property string $order_dir
17
+ */
18
+ class LoadLogs extends DynPropertiesClass {
19
 
 
20
  use ModConsumer;
21
  use IpAddressConsumer;
22
 
23
+ private $includeMeta = true;
24
 
25
  /**
26
  * @return LogRecord[]
27
  */
28
+ public function run( bool $includeMeta = true ) :array {
29
+ $this->includeMeta = $includeMeta;
30
+
31
  /** @var ModCon $mod */
32
  $mod = $this->getMod();
33
  $stdKeys = array_flip( array_unique( array_merge(
75
  /** @var ModCon $mod */
76
  $mod = $this->getMod();
77
 
78
+ $selectFields = [
79
+ 'log.id',
80
+ 'log.site_id',
81
+ 'log.event_slug',
82
+ 'log.created_at',
83
+ 'ips.ip',
84
+ 'req.req_id as rid',
85
+ ];
86
+ if ( $this->includeMeta ) {
87
+ $selectFields = array_merge( $selectFields, [
88
+ 'meta.meta_key',
89
+ 'meta.meta_value',
90
+ ] );
91
+ }
92
+
93
  return Services::WpDb()->selectCustom(
94
+ sprintf( $this->getRawQuery( $this->includeMeta ),
95
+ implode( ', ', $selectFields ),
96
+ $mod->getDbH_Logs()->getTableSchema()->table,
97
+ $this->getCon()->getModule_Data()->getDbH_ReqLogs()->getTableSchema()->table,
98
+ $this->getCon()->getModule_Data()->getDbH_IPs()->getTableSchema()->table,
99
+ empty( $this->getIP() ) ? '' : sprintf( "AND ips.ip=INET6_ATON('%s')", $this->getIP() ),
100
+ $this->includeMeta ? $mod->getDbH_Meta()->getTableSchema()->table : '',
101
+ empty( $this->wheres ) ? '' : 'WHERE '.implode( ' AND ', $this->wheres ),
102
+ sprintf( 'ORDER BY log.updated_at %s', $this->order_dir ?? 'DESC' ),
103
+ isset( $this->limit ) ? sprintf( 'LIMIT %s', $this->limit ) : '',
104
+ isset( $this->offset ) ? sprintf( 'OFFSET %s', $this->offset ) : ''
105
+ )
106
+ );
107
+ }
108
+
109
+ public function countAll() :int {
110
+ /** @var ModCon $mod */
111
+ $mod = $this->getMod();
112
+ return (int)Services::WpDb()->getVar(
113
+ sprintf( $this->getRawQuery( false ),
114
+ 'COUNT(*)',
115
  $mod->getDbH_Logs()->getTableSchema()->table,
116
  $this->getCon()->getModule_Data()->getDbH_ReqLogs()->getTableSchema()->table,
117
  $this->getCon()->getModule_Data()->getDbH_IPs()->getTableSchema()->table,
118
  empty( $this->getIP() ) ? '' : sprintf( "AND ips.ip=INET6_ATON('%s')", $this->getIP() ),
119
+ '',
120
+ empty( $this->wheres ) ? '' : 'WHERE '.implode( ' AND ', $this->wheres ),
121
+ '',
122
+ '',
123
+ ''
124
  )
125
  );
126
  }
127
 
128
+ private function getRawQuery( bool $includeMeta = true ) :string {
129
+ return sprintf( 'SELECT %%s
130
+ FROM `%%s` as log
131
+ INNER JOIN `%%s` as req
132
+ ON log.req_ref = req.id
133
+ INNER JOIN `%%s` as ips
134
+ ON ips.id = req.ip_ref
135
+ %%s
136
+ %s
137
+ %%s
138
+ %%s
139
+ %%s
140
+ %%s
141
+ ',
142
+ $includeMeta ? 'LEFT JOIN `%s` as `meta` ON log.id = `meta`.log_ref' : '%s'
143
+ );
144
  }
145
  }
src/lib/src/Modules/AuditTrail/Lib/LogTable/BuildAuditTableData.php ADDED
@@ -0,0 +1,195 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\Lib\LogTable;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\DB\LoadLogs;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\DB\LogRecord;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\Lib\AuditMessageBuilder;
8
+ use FernleafSystems\Wordpress\Plugin\Shield\Tables\DataTables\Build\AuditTrail\ForAuditTrail;
9
+ use FernleafSystems\Wordpress\Plugin\Shield\Tables\DataTables\LoadData\BaseBuildTableData;
10
+ use FernleafSystems\Wordpress\Services\Services;
11
+
12
+ class BuildAuditTableData extends BaseBuildTableData {
13
+
14
+ /**
15
+ * @var LogRecord
16
+ */
17
+ private $log;
18
+
19
+ protected function getSearchPanesData() :array {
20
+ return ( new BuildSearchPanesData() )
21
+ ->setMod( $this->getMod() )
22
+ ->build();
23
+ }
24
+
25
+ /**
26
+ * @param LogRecord[] $records
27
+ */
28
+ protected function buildTableRowsFromRawLogs( array $records ) :array {
29
+ return array_values( array_map(
30
+ function ( $log ) {
31
+ $this->log = $log;
32
+ $data = $this->log->getRawData();
33
+ $data[ 'ip' ] = $this->log->ip;
34
+ $data[ 'rid' ] = $this->log->rid ?? __( 'Unknown', 'wp-simple-firewall' );
35
+ $data[ 'ip_linked' ] = $this->getColumnContent_RequestDetails();
36
+ $data[ 'event' ] = $this->getCon()->loadEventsService()->getEventName( $this->log->event_slug );
37
+ $data[ 'created_since' ] = $this->getColumnContent_Date( $this->log->created_at );
38
+ $data[ 'message' ] = $this->getColumnContent_Message();
39
+ $data[ 'user' ] = $this->getColumnContent_User();
40
+ $data[ 'user_id' ] = $this->getColumnContent_UserID();
41
+ $data[ 'level' ] = $this->getColumnContent_Level();
42
+ $data[ 'severity' ] = $this->getColumnContent_SeverityIcon();
43
+ $data[ 'meta' ] = $this->getColumnContent_Meta();
44
+ return $data;
45
+ },
46
+ $records
47
+ ) );
48
+ }
49
+
50
+ /**
51
+ * The Wheres need to align with the structure of the Query called from getRecords()
52
+ */
53
+ protected function buildWheresFromSearchPanes() :array {
54
+ $wheres = [];
55
+ if ( !empty( $this->table_data[ 'searchPanes' ] ) ) {
56
+ foreach ( array_filter( $this->table_data[ 'searchPanes' ] ) as $column => $selected ) {
57
+ switch ( $column ) {
58
+ case 'event':
59
+ if ( count( $selected ) > 1 ) {
60
+ $wheres[] = sprintf( 'log.event_slug IN (`%s`)', implode( '`,`', $selected ) );
61
+ }
62
+ else {
63
+ $wheres[] = sprintf( "log.event_slug='%s'", array_pop( $selected ) );
64
+ }
65
+ break;
66
+ case 'ip':
67
+ $wheres[] = sprintf( "ips.ip=INET6_ATON('%s')", array_pop( $selected ) );
68
+ break;
69
+ default:
70
+ break;
71
+ }
72
+ }
73
+ }
74
+ return $wheres;
75
+ }
76
+
77
+ protected function countTotalRecords() :int {
78
+ return $this->getRecordsLoader()->countAll();
79
+ }
80
+
81
+ protected function countTotalRecordsFiltered() :int {
82
+ $loader = $this->getRecordsLoader();
83
+ $loader->wheres = $this->buildWheresFromSearchPanes();
84
+ return $loader->countAll();
85
+ }
86
+
87
+ protected function getSearchableColumns() :array {
88
+ // Use the DataTables definition builder to locate searchable columns
89
+ return array_filter( array_map(
90
+ function ( $column ) {
91
+ return ( $column[ 'searchable' ] ?? false ) ? $column[ 'data' ] : '';
92
+ },
93
+ ( new ForAuditTrail() )
94
+ ->setMod( $this->getMod() )
95
+ ->buildRaw()[ 'columns' ]
96
+ ) );
97
+ }
98
+
99
+ /**
100
+ * @return LogRecord[]
101
+ */
102
+ protected function getRecords( array $wheres = [], int $offset = 0, int $limit = 0 ) :array {
103
+ $loader = $this->getRecordsLoader();
104
+ $loader->wheres = $wheres;
105
+ $loader->limit = $limit;
106
+ $loader->offset = $offset;
107
+ $loader->order_dir = $this->getOrderDirection();
108
+ return array_filter(
109
+ $loader->run( true ),
110
+ function ( $logRecord ) {
111
+ return $this->getCon()->loadEventsService()->eventExists( $logRecord->event_slug );
112
+ }
113
+ );
114
+ }
115
+
116
+ protected function getRecordsLoader() :LoadLogs {
117
+ return ( new LoadLogs() )->setMod( $this->getMod() );
118
+ }
119
+
120
+ private function getColumnContent_RequestDetails() :string {
121
+ return sprintf( '<h6>%s</h6>', $this->getIpAnalysisLink( (string)$this->log->ip ) );
122
+ }
123
+
124
+ private function getColumnContent_UserID() :string {
125
+ return $this->log->meta_data[ 'uid' ] ?? '-';
126
+ }
127
+
128
+ private function getColumnContent_User() :string {
129
+ $content = '-';
130
+ $uid = $this->log->meta_data[ 'uid' ] ?? '';
131
+ if ( !empty( $uid ) ) {
132
+ if ( is_numeric( $uid ) ) {
133
+ $user = Services::WpUsers()->getUserById( $uid );
134
+ if ( !empty( $user ) ) {
135
+ $content = sprintf( '<a href="%s" target="_blank">%s</a>',
136
+ Services::WpUsers()->getAdminUrl_ProfileEdit( $user ),
137
+ $user->user_login );
138
+ }
139
+ else {
140
+ $content = sprintf( 'Unavailable (ID:%s)', $uid );
141
+ }
142
+ }
143
+ else {
144
+ $content = $uid === 'cron' ? 'WP Cron' : 'WP-CLI';
145
+ }
146
+ }
147
+ return $content;
148
+ }
149
+
150
+ private function getColumnContent_Message() :string {
151
+ $msg = AuditMessageBuilder::BuildFromLogRecord( $this->log );
152
+ return sprintf( '<span class="message-header">%s</span><textarea readonly rows="%s">%s</textarea>',
153
+ $this->getCon()->loadEventsService()->getEventName( $this->log->event_slug ),
154
+ count( $msg ) + 1, sanitize_textarea_field( implode( "\n", $msg ) ) );
155
+ }
156
+
157
+ private function getColumnContent_Meta() :string {
158
+ return sprintf(
159
+ '<button type="button" class="btn btn-link"'.
160
+ ' data-toggle="popover"'.
161
+ ' data-rid="%s">%s</button>', $this->log->rid,
162
+ sprintf( '<span class="meta-icon">%s</span>',
163
+ $this->getCon()->svgs->raw( 'bootstrap/tags.svg' )
164
+ )
165
+ );
166
+ }
167
+
168
+ private function getColumnContent_Level() :string {
169
+ return $this->getCon()->loadEventsService()->getEventDef( $this->log->event_slug )[ 'level' ];
170
+ }
171
+
172
+ private function getColumnContent_SeverityIcon() :string {
173
+ $level = $this->getColumnContent_Level();
174
+ $levelDetails = [
175
+ 'alert' => [
176
+ 'icon' => 'x-octagon',
177
+ ],
178
+ 'warning' => [
179
+ 'icon' => 'exclamation-triangle',
180
+ ],
181
+ 'notice' => [
182
+ 'icon' => 'info-square',
183
+ ],
184
+ 'info' => [
185
+ 'icon' => 'info-circle',
186
+ ],
187
+ 'debug' => [
188
+ 'icon' => 'question-diamond',
189
+ ],
190
+ ][ $level ];
191
+ return sprintf( '<span class="severity-%s severity-icon">%s</span>', $level,
192
+ $this->getCon()->svgs->raw( sprintf( 'bootstrap/%s.svg', $levelDetails[ 'icon' ] ) )
193
+ );
194
+ }
195
+ }
src/lib/src/Modules/AuditTrail/Lib/LogTable/BuildSearchPanesData.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\Lib\LogTable;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\ModCon;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
+ use FernleafSystems\Wordpress\Services\Services;
8
+
9
+ class BuildSearchPanesData {
10
+
11
+ use ModConsumer;
12
+
13
+ public function build() :array {
14
+ return [
15
+ 'options' => [
16
+ 'ip' => $this->buildForIPs(),
17
+ 'event' => $this->buildForEvents(),
18
+ ]
19
+ ];
20
+ }
21
+
22
+ private function buildForIPs() :array {
23
+ $results = $this->runQuery( 'INET6_NTOA(ips.ip) as ip' );
24
+ return array_filter( array_map(
25
+ function ( $result ) {
26
+ $ip = $result[ 'ip' ] ?? null;
27
+ if ( !empty( $ip ) ) {
28
+ $ip = [
29
+ 'label' => $ip,
30
+ 'value' => $ip,
31
+ ];
32
+ }
33
+ return $ip;
34
+ },
35
+ $results
36
+ ) );
37
+ }
38
+
39
+ private function buildForEvents() :array {
40
+ $results = $this->runQuery( '`log`.event_slug as event' );
41
+ return array_filter( array_map(
42
+ function ( $result ) {
43
+ $evt = $result[ 'event' ] ?? null;
44
+ if ( !empty( $evt ) ) {
45
+ $evt = [
46
+ 'label' => $this->getCon()->service_events->getEventName( $evt ),
47
+ 'value' => $evt,
48
+ ];
49
+ }
50
+ return $evt;
51
+ },
52
+ $results
53
+ ) );
54
+ }
55
+
56
+ private function runQuery( string $select ) :array {
57
+ /** @var ModCon $mod */
58
+ $mod = $this->getMod();
59
+ $results = Services::WpDb()->selectCustom(
60
+ sprintf( 'SELECT DISTINCT %s
61
+ FROM `%s` as `log`
62
+ INNER JOIN `%s` as req
63
+ ON `log`.req_ref = req.id
64
+ INNER JOIN `%s` as ips
65
+ ON ips.id = req.ip_ref
66
+ ',
67
+ $select,
68
+ $mod->getDbH_Logs()->getTableSchema()->table,
69
+ $this->getCon()->getModule_Data()->getDbH_ReqLogs()->getTableSchema()->table,
70
+ $this->getCon()->getModule_Data()->getDbH_IPs()->getTableSchema()->table
71
+ )
72
+ );
73
+ return is_array( $results ) ? $results : [];
74
+ }
75
+ }
src/lib/src/Modules/AuditTrail/Lib/LogTable/DelegateAjaxHandler.php CHANGED
@@ -10,7 +10,6 @@ class DelegateAjaxHandler {
10
  use Shield\Modules\ModConsumer;
11
 
12
  /**
13
- * @return array
14
  * @throws \Exception
15
  */
16
  public function processAjaxAction() :array {
@@ -32,17 +31,14 @@ class DelegateAjaxHandler {
32
  }
33
 
34
  /**
35
- * @return array
36
  * @throws \Exception
37
  */
38
  private function retrieveTableData() :array {
 
 
39
  return [
40
- 'success' => true,
41
- 'vars' => [
42
- 'data' => ( new LoadRawTableData() )
43
- ->setMod( $this->getMod() )
44
- ->loadForLogs()
45
- ],
46
  ];
47
  }
48
 
10
  use Shield\Modules\ModConsumer;
11
 
12
  /**
 
13
  * @throws \Exception
14
  */
15
  public function processAjaxAction() :array {
31
  }
32
 
33
  /**
 
34
  * @throws \Exception
35
  */
36
  private function retrieveTableData() :array {
37
+ $builder = ( new BuildAuditTableData() )->setMod( $this->getMod() );
38
+ $builder->table_data = (array)Services::Request()->post( 'table_data', [] );
39
  return [
40
+ 'success' => true,
41
+ 'datatable_data' => $builder->build(),
 
 
 
 
42
  ];
43
  }
44
 
src/lib/src/Modules/AuditTrail/Lib/LogTable/LoadRawTableData.php CHANGED
@@ -5,6 +5,7 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\Lib\LogTabl
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\DB\LoadLogs;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\DB\LogRecord;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\Lib\AuditMessageBuilder;
 
8
  use FernleafSystems\Wordpress\Plugin\Shield\Tables\DataTables\LoadData\BaseLoadTableData;
9
  use FernleafSystems\Wordpress\Services\Services;
10
 
@@ -15,18 +16,18 @@ class LoadRawTableData extends BaseLoadTableData {
15
  */
16
  private $log;
17
 
18
- public function loadForLogs() :array {
19
- $srvEvents = $this->getCon()->loadEventsService();
 
 
20
  return array_values( array_map(
21
- function ( $log ) use ( $srvEvents ) {
22
  $this->log = $log;
23
-
24
- $data = $log->getRawData();
25
-
26
  $data[ 'ip' ] = $this->log->ip;
27
  $data[ 'rid' ] = $this->log->rid ?? __( 'Unknown', 'wp-simple-firewall' );
28
  $data[ 'ip_linked' ] = $this->getColumnContent_RequestDetails();
29
- $data[ 'event' ] = $srvEvents->getEventName( $log->event_slug );
30
  $data[ 'created_since' ] = $this->getColumnContent_Date( $this->log->created_at );
31
  $data[ 'message' ] = $this->getColumnContent_Message();
32
  $data[ 'user' ] = $this->getColumnContent_User();
@@ -36,19 +37,32 @@ class LoadRawTableData extends BaseLoadTableData {
36
  $data[ 'meta' ] = $this->getColumnContent_Meta();
37
  return $data;
38
  },
39
- $this->getLogRecords()
 
 
 
 
 
 
 
 
 
 
 
 
40
  ) );
41
  }
42
 
43
  /**
44
  * @return LogRecord[]
45
  */
46
- private function getLogRecords() :array {
 
 
 
 
47
  return array_filter(
48
- ( new LoadLogs() )
49
- ->setMod( $this->getCon()->getModule_AuditTrail() )
50
- ->setLimit( (int)Services::Request()->post( 'record_limit', 10000 ) )
51
- ->run(),
52
  function ( $logRecord ) {
53
  return $this->getCon()->loadEventsService()->eventExists( $logRecord->event_slug );
54
  }
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\DB\LoadLogs;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\DB\LogRecord;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\Lib\AuditMessageBuilder;
8
+ use FernleafSystems\Wordpress\Plugin\Shield\Tables\DataTables\Build\AuditTrail\ForAuditTrail;
9
  use FernleafSystems\Wordpress\Plugin\Shield\Tables\DataTables\LoadData\BaseLoadTableData;
10
  use FernleafSystems\Wordpress\Services\Services;
11
 
16
  */
17
  private $log;
18
 
19
+ /**
20
+ * @param LogRecord[] $records
21
+ */
22
+ protected function buildTableRowsFromRawLogs( array $records ) :array {
23
  return array_values( array_map(
24
+ function ( $log ) {
25
  $this->log = $log;
26
+ $data = $this->log->getRawData();
 
 
27
  $data[ 'ip' ] = $this->log->ip;
28
  $data[ 'rid' ] = $this->log->rid ?? __( 'Unknown', 'wp-simple-firewall' );
29
  $data[ 'ip_linked' ] = $this->getColumnContent_RequestDetails();
30
+ $data[ 'event' ] = $this->getCon()->loadEventsService()->getEventName( $this->log->event_slug );
31
  $data[ 'created_since' ] = $this->getColumnContent_Date( $this->log->created_at );
32
  $data[ 'message' ] = $this->getColumnContent_Message();
33
  $data[ 'user' ] = $this->getColumnContent_User();
37
  $data[ 'meta' ] = $this->getColumnContent_Meta();
38
  return $data;
39
  },
40
+ $records
41
+ ) );
42
+ }
43
+
44
+ protected function getSearchableColumns() :array {
45
+ // Use the DataTables definition builder to locate searchable columns
46
+ return array_filter( array_map(
47
+ function ( $column ) {
48
+ return ( $column[ 'searchable' ] ?? false ) ? $column[ 'data' ] : '';
49
+ },
50
+ ( new ForAuditTrail() )
51
+ ->setMod( $this->getMod() )
52
+ ->buildRaw()[ 'columns' ]
53
  ) );
54
  }
55
 
56
  /**
57
  * @return LogRecord[]
58
  */
59
+ protected function getRecords( int $offset = 0, int $limit = 0 ) :array {
60
+ $loader = ( new LoadLogs() )->setMod( $this->getCon()->getModule_AuditTrail() );
61
+ $loader->limit = $limit;
62
+ $loader->offset = $offset;
63
+ $loader->order_dir = $this->getOrderDirection();
64
  return array_filter(
65
+ $loader->run(),
 
 
 
66
  function ( $logRecord ) {
67
  return $this->getCon()->loadEventsService()->eventExists( $logRecord->event_slug );
68
  }
src/lib/src/Modules/AuditTrail/ModCon.php CHANGED
@@ -78,7 +78,7 @@ class ModCon extends BaseShield\ModCon {
78
  ];
79
  },
80
  array_filter( // Get all logs entries pertaining to this user:
81
- ( new Shield\Modules\AuditTrail\Lib\LogTable\LoadRawTableData() )
82
  ->setMod( $this )
83
  ->loadForLogs(),
84
  function ( $log ) use ( $user ) {
78
  ];
79
  },
80
  array_filter( // Get all logs entries pertaining to this user:
81
+ ( new Shield\Modules\AuditTrail\Lib\LogTable\BuildAuditTableData() )
82
  ->setMod( $this )
83
  ->loadForLogs(),
84
  function ( $log ) use ( $user ) {
src/lib/src/Modules/AuditTrail/Processor.php CHANGED
@@ -1,9 +1,8 @@
1
- <?php
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Databases;
6
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\Auditors\Base;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
8
 
9
  class Processor extends BaseShield\Processor {
@@ -17,23 +16,22 @@ class Processor extends BaseShield\Processor {
17
  /** @var ModCon $mod */
18
  $mod = $this->getMod();
19
  $mod->getAuditLogger()->setIfCommit( true );
20
- foreach ( $this->getAuditors() as $auditor ) {
 
 
21
  $auditor->setMod( $this->getMod() )->execute();
22
  }
23
  }
24
 
25
- /**
26
- * @return Base[]
27
- */
28
  private function getAuditors() :array {
29
  return [
30
- new Auditors\Users(),
31
- new Auditors\Plugins(),
32
- new Auditors\Themes(),
33
- new Auditors\Wordpress(),
34
- new Auditors\Posts(),
35
- new Auditors\Emails(),
36
- new Auditors\Upgrades(),
37
  ];
38
  }
39
 
1
+ <?php declare( strict_types=1 );
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Databases;
 
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
7
 
8
  class Processor extends BaseShield\Processor {
16
  /** @var ModCon $mod */
17
  $mod = $this->getMod();
18
  $mod->getAuditLogger()->setIfCommit( true );
19
+ foreach ( $this->getAuditors() as $auditorClass ) {
20
+ /** @var Auditors\Base $auditor */
21
+ $auditor = new $auditorClass();
22
  $auditor->setMod( $this->getMod() )->execute();
23
  }
24
  }
25
 
 
 
 
26
  private function getAuditors() :array {
27
  return [
28
+ Auditors\Users::class,
29
+ Auditors\Plugins::class,
30
+ Auditors\Themes::class,
31
+ Auditors\Wordpress::class,
32
+ Auditors\Posts::class,
33
+ Auditors\Emails::class,
34
+ Auditors\Upgrades::class
35
  ];
36
  }
37
 
src/lib/src/Modules/AuditTrail/Strings.php CHANGED
@@ -11,134 +11,140 @@ class Strings extends Base\Strings {
11
  */
12
  public function getEventStrings() :array {
13
  return [
14
- 'plugin_activated' => [
15
  'name' => __( 'Plugin Activated', 'wp-simple-firewall' ),
16
  'audit' => [
17
  __( 'Plugin "{{plugin}}" was activated.', 'wp-simple-firewall' )
18
  ],
19
  ],
20
- 'plugin_deactivated' => [
 
 
 
 
 
 
21
  'name' => __( 'Plugin Deactivated', 'wp-simple-firewall' ),
22
  'audit' => [
23
  __( 'Plugin "{{plugin}}" was deactivated.', 'wp-simple-firewall' )
24
  ],
25
  ],
26
- 'plugin_upgraded' => [
27
  'name' => __( 'Plugin Upgraded', 'wp-simple-firewall' ),
28
  'audit' => [
29
  __( 'Plugin "{{plugin}}" was upgraded from version {{from}} to version {{to}}.', 'wp-simple-firewall' )
30
  ],
31
  ],
32
- 'plugin_file_edited' => [
33
  'name' => __( 'Plugin File Edited', 'wp-simple-firewall' ),
34
  'audit' => [
35
  __( 'An attempt was made to edit the plugin file "{{file}}" directly through the WordPress editor.', 'wp-simple-firewall' )
36
  ],
37
  ],
38
- 'theme_activated' => [
39
  'name' => __( 'Theme Activated', 'wp-simple-firewall' ),
40
  'audit' => [
41
  __( 'Theme "{{theme}}" was activated.', 'wp-simple-firewall' ),
42
  ],
43
  ],
44
- 'theme_file_edited' => [
 
 
 
 
 
 
45
  'name' => __( 'Theme File Edited', 'wp-simple-firewall' ),
46
  'audit' => [
47
  __( 'An attempt was made to edit the theme file "{{file}}" directly through the WordPress editor.', 'wp-simple-firewall' ),
48
  ],
49
  ],
50
- 'theme_upgraded' => [
51
  'name' => __( 'Theme Upgraded', 'wp-simple-firewall' ),
52
  'audit' => [
53
  __( 'Theme "{{theme}}" was upgraded from version {{from}} to version {{to}}.', 'wp-simple-firewall' ),
54
  ],
55
  ],
56
- 'core_updated' => [
57
  'name' => __( 'WP Core Updated', 'wp-simple-firewall' ),
58
  'audit' => [
59
  __( 'WordPress Core was updated from "{{from}}" to "{{to}}".', 'wp-simple-firewall' ),
60
  ],
61
  ],
62
- 'permalinks_structure' => [
63
  'name' => __( 'Permalinks Updated', 'wp-simple-firewall' ),
64
  'audit' => [
65
  __( 'WordPress Permalinks Structure was updated from "{{from}}" to "{{to}}".', 'wp-simple-firewall' ),
66
  ],
67
  ],
68
- 'post_deleted' => [
69
  'name' => __( 'Post Deleted', 'wp-simple-firewall' ),
70
  'audit' => [
71
  __( 'WordPress Post entitled "{{title}}" was permanently deleted from trash.', 'wp-simple-firewall' )
72
  ],
73
  ],
74
- 'post_trashed' => [
75
  'name' => __( 'Post Trashed', 'wp-simple-firewall' ),
76
  'audit' => [
77
  __( 'Post entitled "{{title}}" was trashed.', 'wp-simple-firewall' ),
78
  __( 'Post Type: {{type}}' ),
79
  ],
80
  ],
81
- 'post_recovered' => [
82
  'name' => __( 'Post Recovered', 'wp-simple-firewall' ),
83
  'audit' => [
84
  __( 'Post entitled "{{title}}" was recovered from trash.', 'wp-simple-firewall' ),
85
  __( 'Post Type: {{type}}' ),
86
  ],
87
  ],
88
- 'post_updated' => [
89
  'name' => __( 'Post Updated', 'wp-simple-firewall' ),
90
  'audit' => [
91
  __( 'Post entitled "{{title}}" was updated.', 'wp-simple-firewall' ),
92
  __( 'Post Type: {{type}}' ),
93
  ],
94
  ],
95
- 'post_published' => [
96
  'name' => __( 'Post Published', 'wp-simple-firewall' ),
97
  'audit' => [
98
  __( 'Post entitled "{{title}}" was published.', 'wp-simple-firewall' ),
99
  __( 'Post Type: {{type}}' ),
100
  ],
101
  ],
102
- 'post_unpublished' => [
103
  'name' => __( 'Post Unpublished', 'wp-simple-firewall' ),
104
  'audit' => [
105
  __( 'Post entitled "{{title}}" was unpublished.', 'wp-simple-firewall' ),
106
  __( 'Post Type: {{type}}' ),
107
  ],
108
  ],
109
- 'user_login' => [
110
  'name' => __( 'User Login', 'wp-simple-firewall' ),
111
  'audit' => [
112
  __( 'Attempted user login by "{{user_login}}" was successful.', 'wp-simple-firewall' ),
113
  ],
114
  ],
115
- 'user_login_app' => [
116
- 'name' => __( 'User Login By App Password', 'wp-simple-firewall' ),
117
- 'audit' => [
118
- __( 'Attempted login by "{{user_login}}" using application password was successful.', 'wp-simple-firewall' ),
119
- ],
120
- ],
121
- 'user_registered' => [
122
  'name' => __( 'User Registered', 'wp-simple-firewall' ),
123
  'audit' => [
124
  __( 'New WordPress user registered.', 'wp-simple-firewall' ),
125
  __( 'New username is "{{user_login}}" with email address "{{email}}".', 'wp-simple-firewall' ),
126
  ],
127
  ],
128
- 'user_deleted' => [
129
  'name' => __( 'User Deleted', 'wp-simple-firewall' ),
130
  'audit' => [
131
  __( 'WordPress user deleted.', 'wp-simple-firewall' ),
132
  __( 'Username was "{{user_login}}" with email address "{{email}}".', 'wp-simple-firewall' ),
133
  ],
134
  ],
135
- 'user_deleted_reassigned' => [
136
  'name' => __( 'User Deleted And Reassigned', 'wp-simple-firewall' ),
137
  'audit' => [
138
  __( 'Deleted user posts were reassigned to user "{{user_login}}".', 'wp-simple-firewall' )
139
  ],
140
  ],
141
- 'email_attempt_send' => [
142
  'name' => __( 'Email Sent', 'wp-simple-firewall' ),
143
  'audit' => [
144
  __( 'There was an attempt to send an email using the "wp_mail" function.', 'wp-simple-firewall' ),
@@ -148,6 +154,42 @@ class Strings extends Base\Strings {
148
  __( 'The "wp_mail" function was called from the file "{{bt_file}}" on line {{bt_line}}.', 'wp-simple-firewall' )
149
  ],
150
  ],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  ];
152
  }
153
 
11
  */
12
  public function getEventStrings() :array {
13
  return [
14
+ 'plugin_activated' => [
15
  'name' => __( 'Plugin Activated', 'wp-simple-firewall' ),
16
  'audit' => [
17
  __( 'Plugin "{{plugin}}" was activated.', 'wp-simple-firewall' )
18
  ],
19
  ],
20
+ 'plugin_installed' => [
21
+ 'name' => __( 'Plugin Installed', 'wp-simple-firewall' ),
22
+ 'audit' => [
23
+ __( 'Plugin "{{plugin}}" was installed.', 'wp-simple-firewall' )
24
+ ],
25
+ ],
26
+ 'plugin_deactivated' => [
27
  'name' => __( 'Plugin Deactivated', 'wp-simple-firewall' ),
28
  'audit' => [
29
  __( 'Plugin "{{plugin}}" was deactivated.', 'wp-simple-firewall' )
30
  ],
31
  ],
32
+ 'plugin_upgraded' => [
33
  'name' => __( 'Plugin Upgraded', 'wp-simple-firewall' ),
34
  'audit' => [
35
  __( 'Plugin "{{plugin}}" was upgraded from version {{from}} to version {{to}}.', 'wp-simple-firewall' )
36
  ],
37
  ],
38
+ 'plugin_file_edited' => [
39
  'name' => __( 'Plugin File Edited', 'wp-simple-firewall' ),
40
  'audit' => [
41
  __( 'An attempt was made to edit the plugin file "{{file}}" directly through the WordPress editor.', 'wp-simple-firewall' )
42
  ],
43
  ],
44
+ 'theme_activated' => [
45
  'name' => __( 'Theme Activated', 'wp-simple-firewall' ),
46
  'audit' => [
47
  __( 'Theme "{{theme}}" was activated.', 'wp-simple-firewall' ),
48
  ],
49
  ],
50
+ 'theme_installed' => [
51
+ 'name' => __( 'Theme Installed', 'wp-simple-firewall' ),
52
+ 'audit' => [
53
+ __( 'Theme "{{theme}}" was installed.', 'wp-simple-firewall' )
54
+ ],
55
+ ],
56
+ 'theme_file_edited' => [
57
  'name' => __( 'Theme File Edited', 'wp-simple-firewall' ),
58
  'audit' => [
59
  __( 'An attempt was made to edit the theme file "{{file}}" directly through the WordPress editor.', 'wp-simple-firewall' ),
60
  ],
61
  ],
62
+ 'theme_upgraded' => [
63
  'name' => __( 'Theme Upgraded', 'wp-simple-firewall' ),
64
  'audit' => [
65
  __( 'Theme "{{theme}}" was upgraded from version {{from}} to version {{to}}.', 'wp-simple-firewall' ),
66
  ],
67
  ],
68
+ 'core_updated' => [
69
  'name' => __( 'WP Core Updated', 'wp-simple-firewall' ),
70
  'audit' => [
71
  __( 'WordPress Core was updated from "{{from}}" to "{{to}}".', 'wp-simple-firewall' ),
72
  ],
73
  ],
74
+ 'permalinks_structure' => [
75
  'name' => __( 'Permalinks Updated', 'wp-simple-firewall' ),
76
  'audit' => [
77
  __( 'WordPress Permalinks Structure was updated from "{{from}}" to "{{to}}".', 'wp-simple-firewall' ),
78
  ],
79
  ],
80
+ 'post_deleted' => [
81
  'name' => __( 'Post Deleted', 'wp-simple-firewall' ),
82
  'audit' => [
83
  __( 'WordPress Post entitled "{{title}}" was permanently deleted from trash.', 'wp-simple-firewall' )
84
  ],
85
  ],
86
+ 'post_trashed' => [
87
  'name' => __( 'Post Trashed', 'wp-simple-firewall' ),
88
  'audit' => [
89
  __( 'Post entitled "{{title}}" was trashed.', 'wp-simple-firewall' ),
90
  __( 'Post Type: {{type}}' ),
91
  ],
92
  ],
93
+ 'post_recovered' => [
94
  'name' => __( 'Post Recovered', 'wp-simple-firewall' ),
95
  'audit' => [
96
  __( 'Post entitled "{{title}}" was recovered from trash.', 'wp-simple-firewall' ),
97
  __( 'Post Type: {{type}}' ),
98
  ],
99
  ],
100
+ 'post_updated' => [
101
  'name' => __( 'Post Updated', 'wp-simple-firewall' ),
102
  'audit' => [
103
  __( 'Post entitled "{{title}}" was updated.', 'wp-simple-firewall' ),
104
  __( 'Post Type: {{type}}' ),
105
  ],
106
  ],
107
+ 'post_published' => [
108
  'name' => __( 'Post Published', 'wp-simple-firewall' ),
109
  'audit' => [
110
  __( 'Post entitled "{{title}}" was published.', 'wp-simple-firewall' ),
111
  __( 'Post Type: {{type}}' ),
112
  ],
113
  ],
114
+ 'post_unpublished' => [
115
  'name' => __( 'Post Unpublished', 'wp-simple-firewall' ),
116
  'audit' => [
117
  __( 'Post entitled "{{title}}" was unpublished.', 'wp-simple-firewall' ),
118
  __( 'Post Type: {{type}}' ),
119
  ],
120
  ],
121
+ 'user_login' => [
122
  'name' => __( 'User Login', 'wp-simple-firewall' ),
123
  'audit' => [
124
  __( 'Attempted user login by "{{user_login}}" was successful.', 'wp-simple-firewall' ),
125
  ],
126
  ],
127
+ 'user_registered' => [
 
 
 
 
 
 
128
  'name' => __( 'User Registered', 'wp-simple-firewall' ),
129
  'audit' => [
130
  __( 'New WordPress user registered.', 'wp-simple-firewall' ),
131
  __( 'New username is "{{user_login}}" with email address "{{email}}".', 'wp-simple-firewall' ),
132
  ],
133
  ],
134
+ 'user_deleted' => [
135
  'name' => __( 'User Deleted', 'wp-simple-firewall' ),
136
  'audit' => [
137
  __( 'WordPress user deleted.', 'wp-simple-firewall' ),
138
  __( 'Username was "{{user_login}}" with email address "{{email}}".', 'wp-simple-firewall' ),
139
  ],
140
  ],
141
+ 'user_deleted_reassigned' => [
142
  'name' => __( 'User Deleted And Reassigned', 'wp-simple-firewall' ),
143
  'audit' => [
144
  __( 'Deleted user posts were reassigned to user "{{user_login}}".', 'wp-simple-firewall' )
145
  ],
146
  ],
147
+ 'email_attempt_send' => [
148
  'name' => __( 'Email Sent', 'wp-simple-firewall' ),
149
  'audit' => [
150
  __( 'There was an attempt to send an email using the "wp_mail" function.', 'wp-simple-firewall' ),
154
  __( 'The "wp_mail" function was called from the file "{{bt_file}}" on line {{bt_line}}.', 'wp-simple-firewall' )
155
  ],
156
  ],
157
+ 'user_login_app' => [
158
+ 'name' => __( 'User Login By App Password', 'wp-simple-firewall' ),
159
+ 'audit' => [
160
+ __( 'Attempted login by "{{user_login}}" using application password was successful.', 'wp-simple-firewall' ),
161
+ ],
162
+ ],
163
+ 'app_invalid_email' => [
164
+ 'name' => __( 'APP Password Auth - Invalid Email', 'wp-simple-firewall' ),
165
+ 'audit' => [
166
+ __( 'Attempt to authenticate App Password with invalid email.', 'wp-simple-firewall' ),
167
+ ],
168
+ ],
169
+ 'app_invalid_username' => [
170
+ 'name' => __( 'APP Password Auth - Invalid Username', 'wp-simple-firewall' ),
171
+ 'audit' => [
172
+ __( 'Attempt to authenticate App Password with invalid username.', 'wp-simple-firewall' ),
173
+ ],
174
+ ],
175
+ 'app_incorrect_password' => [
176
+ 'name' => __( 'Incorrect APP Password', 'wp-simple-firewall' ),
177
+ 'audit' => [
178
+ __( 'Attempt to authenticate with incorrect App Password.', 'wp-simple-firewall' ),
179
+ ],
180
+ ],
181
+ 'app_passwords_disabled' => [
182
+ 'name' => __( 'App Passwords Disabled', 'wp-simple-firewall' ),
183
+ 'audit' => [
184
+ __( "Attempt to authenticate with App Password when they're disabled.", 'wp-simple-firewall' ),
185
+ ],
186
+ ],
187
+ 'app_passwords_disabled_user' => [
188
+ 'name' => __( 'App Passwords Disabled For User', 'wp-simple-firewall' ),
189
+ 'audit' => [
190
+ __( "Attempt to authenticate with App Password when they're disabled for the user.", 'wp-simple-firewall' ),
191
+ ],
192
+ ],
193
  ];
194
  }
195
 
src/lib/src/Modules/Base/AdminNotices.php CHANGED
@@ -35,7 +35,7 @@ class AdminNotices {
35
  $this->setNoticeDismissed( $notice );
36
  $ajaxResponse = [
37
  'success' => true,
38
- 'message' => 'Admin notice dismissed', //not currently seen
39
  'notice_id' => $notice->id,
40
  ];
41
  break;
35
  $this->setNoticeDismissed( $notice );
36
  $ajaxResponse = [
37
  'success' => true,
38
+ 'message' => 'Admin notice dismissed', //not currently rendered
39
  'notice_id' => $notice->id,
40
  ];
41
  break;
src/lib/src/Modules/Base/Lib/Rest/Request/Process.php DELETED
@@ -1,138 +0,0 @@
1
- <?php declare( strict_types=1 );
2
-
3
- namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Rest\Request;
4
-
5
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
6
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Rest;
7
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
8
- use FernleafSystems\Wordpress\Services\Services;
9
- use FernleafSystems\Wordpress\Services\Utilities\File\Cache;
10
-
11
- abstract class Process {
12
-
13
- use ModConsumer;
14
- use Rest\Route\RestRouteConsumer;
15
-
16
- /**
17
- * @var RequestVO
18
- */
19
- private $reqVO;
20
-
21
- /**
22
- * @var \WP_REST_Request
23
- */
24
- protected $wpRestRequest;
25
-
26
- /**
27
- * @param Rest\Route\RouteBase|mixed $route
28
- */
29
- public function __construct( $route, \WP_REST_Request $restRequest ) {
30
- $this->setRestRoute( $route );
31
- $this->wpRestRequest = $restRequest;
32
- }
33
-
34
- public function run() :array {
35
- $route = $this->getRestRoute();
36
-
37
- $apiResponse = [
38
- 'meta' => [
39
- 'ts' => Services::Request()->ts(),
40
- 'api_version' => $this->getCon()->getVersion(),
41
- 'from_cache' => false
42
- ],
43
- ];
44
-
45
- $locked = false;
46
- try {
47
- if ( $route->bypass_lock !== true ) {
48
- $locker = ( new Base\Lib\Rest\Utility\RestLocker() )->setRestRoute( $route );
49
- $locked = $locker->start();
50
- }
51
-
52
- // Ensure only valid parameters are supplied
53
- $permittedParams = array_keys( $this->wpRestRequest->get_attributes()[ 'args' ] );
54
- if ( count( array_diff_key(
55
- $this->wpRestRequest->get_params(),
56
- array_flip( $permittedParams )
57
- ) ) > 0 ) {
58
- throw new \Exception(
59
- sprintf( 'Please only supply parameters that are permitted: %s',
60
- implode( ', ', $permittedParams ) ), 500 );
61
- }
62
-
63
- // Is the site ready?
64
- ( new Base\Lib\Rest\Utility\PreChecks() )
65
- ->setMod( $this->getMod() )
66
- ->run();
67
-
68
- // Begin processing.
69
-
70
- $cacher = $route->getCacheHandler();
71
- $cacher->request_file = $this->getCacheFileFragment();
72
- $cacheDef = $cacher->getCacheDefinition();
73
- if ( $cacher->can_cache ) {
74
- ( new Cache\LoadFromCache() )
75
- ->setCacheDef( $cacheDef )
76
- ->load();
77
- if ( is_array( $cacheDef->data ) ) {
78
- $apiResponse[ 'meta' ][ 'from_cache' ] = true;
79
- }
80
- }
81
-
82
- if ( !is_array( $cacheDef->data ) ) {
83
- $cacheDef->data = $this->process();
84
- if ( $cacher->can_cache ) {
85
- ( new Cache\StoreToCache() )
86
- ->setCacheDef( $cacheDef )
87
- ->store();
88
- }
89
- }
90
-
91
- $apiResponse[ 'error' ] = false;
92
- $apiResponse[ $this->getResponseResultsDataKey() ] = $cacheDef->data;
93
- }
94
- catch ( \Exception $e ) {
95
- $apiResponse[ 'error' ] = true;
96
- $apiResponse[ 'code' ] = $e->getCode();
97
- $apiResponse[ 'message' ] = $e->getMessage();
98
- $apiResponse[ $this->getResponseResultsDataKey() ] = [];
99
- }
100
-
101
- if ( $locked && !empty( $locker ) ) {
102
- $locker->end();
103
- }
104
-
105
- return $apiResponse;
106
- }
107
-
108
- /**
109
- * @throws \Exception
110
- */
111
- abstract protected function process() :array;
112
-
113
- protected function getResponseResultsDataKey() :string {
114
- return $this->getMod()->getModSlug( false );
115
- }
116
-
117
- protected function getWpRestRequest() :\WP_REST_Request {
118
- return $this->wpRestRequest;
119
- }
120
-
121
- /**
122
- * @return RequestVO|mixed
123
- */
124
- protected function getRequestVO() {
125
- if ( !isset( $this->reqVO ) ) {
126
- $this->reqVO = $this->getRestRoute()
127
- ->getNewReqVO()
128
- ->applyFromArray( $this->wpRestRequest->get_params() );
129
- }
130
- return $this->reqVO;
131
- }
132
-
133
- protected function getCacheFileFragment() :string {
134
- $d = $this->getWpRestRequest()->get_params();
135
- ksort( $d );
136
- return md5( serialize( $d ) );
137
- }
138
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/src/Modules/Base/Lib/Rest/Request/RequestVO.php DELETED
@@ -1,16 +0,0 @@
1
- <?php declare( strict_types=1 );
2
-
3
- namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Rest\Request;
4
-
5
- /**
6
- * @property string $action
7
- * @property string $type
8
- */
9
- class RequestVO extends \FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass {
10
-
11
- public function getCacheFileSlug() :string {
12
- $aD = $this->getRawData();
13
- ksort( $aD );
14
- return md5( serialize( $aD ) );
15
- }
16
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/src/Modules/Base/Lib/Rest/Route/RouteBase.php DELETED
@@ -1,254 +0,0 @@
1
- <?php declare( strict_types=1 );
2
-
3
- namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Rest\Route;
4
-
5
- use FernleafSystems\Utilities\Data\Adapter\DynProperties;
6
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
7
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
8
- use FernleafSystems\Wordpress\Services\Services;
9
-
10
- /**
11
- * @property bool $bypass_lock
12
- */
13
- abstract class RouteBase extends \WP_REST_Controller {
14
-
15
- use ModConsumer;
16
- use DynProperties;
17
-
18
- /**
19
- * @var bool
20
- */
21
- private $registered;
22
-
23
- /**
24
- * https://developer.wordpress.org/rest-api/extending-the-rest-api/adding-custom-endpoints/#examples
25
- */
26
- public function register_routes() {
27
- if ( empty( $this->registered ) ) {
28
- $this->registered = true;
29
- if ( $this->isReady() ) {
30
- register_rest_route( $this->getNamespace(),
31
- $this->getRoutePath(),
32
- [ $this->buildRouteDefs() ]
33
- );
34
- }
35
- }
36
- }
37
-
38
- /**
39
- * @return Base\Lib\Rest\Request\RequestVO
40
- */
41
- public function getNewReqVO() {
42
- return new Base\Lib\Rest\Request\RequestVO();
43
- }
44
-
45
- /**
46
- * @param array[] $aArgs
47
- * @return array[]
48
- */
49
- protected function applyArgsDefaults( $aArgs ) {
50
- return array_map(
51
- function ( $args ) {
52
-
53
- $args[ 'validate_callback' ] = function ( $value, $wpRequest, $reqArgKey ) {
54
- return $this->validateRequestArg( $value, $wpRequest, $reqArgKey );
55
- };
56
-
57
- $args[ 'sanitize_callback' ] = function ( $value, $wpRequest, $reqArgKey ) {
58
- return $this->sanitizeRequestArg( $value, $wpRequest, $reqArgKey );
59
- };
60
-
61
- return $args;
62
- },
63
- $aArgs
64
- );
65
- }
66
-
67
- public function buildRouteDefs() :array {
68
- return [
69
- 'methods' => $this->getArgMethods(),
70
- 'callback' => function ( \WP_REST_Request $req ) {
71
- return $this->executeApiRequest( $req );
72
- },
73
- 'permission_callback' => function ( \WP_REST_Request $req ) {
74
- return $this->verifyPermission( $req );
75
- },
76
- 'args' => $this->applyArgsDefaults( $this->getRouteArgs() ),
77
- ];
78
- }
79
-
80
- public function getCacheHandler() :RouteCache {
81
- return new RouteCache( $this );
82
- }
83
-
84
- protected function getNamespace() :string {
85
- $version = $this->getMod()
86
- ->getOptions()
87
- ->getDef( 'rest_version' );
88
- return sprintf( '%s/v%s',
89
- $this->getCon()->prefix(),
90
- is_numeric( $version ) ? $version : '1'
91
- );
92
- }
93
-
94
- abstract public function getRoutePath() :string;
95
-
96
- /**
97
- * @return array[]
98
- */
99
- protected function getRouteArgs() :array {
100
- return array_merge( $this->getRouteArgsDefaults(), $this->getRouteArgsCustom() );
101
- }
102
-
103
- /**
104
- * @return array[]
105
- */
106
- protected function getRouteArgsCustom() :array {
107
- return [];
108
- }
109
-
110
- /**
111
- * @return array[][]
112
- */
113
- protected function getRouteArgsDefaults() :array {
114
- return [];
115
- }
116
-
117
- protected function getRouteSlug() :string {
118
- try {
119
- return strtolower( ( new \ReflectionClass( $this ) )->getShortName() );
120
- }
121
- catch ( \ReflectionException $e ) {
122
- return substr( md5( get_class( $this ) ), 0, 6 );
123
- }
124
- }
125
-
126
- public function getArgMethods() :array {
127
- return [ \WP_REST_Server::READABLE ];
128
- }
129
-
130
- /**
131
- * @return string
132
- * @throws \Exception
133
- */
134
- public function getWorkingDir() :string {
135
- $base = $this->getMod()->getRestHandler()->getWorkingDir();
136
- if ( !empty( $base ) ) {
137
- $dir = path_join( $base, 'r-'.$this->getRouteSlug() );
138
- Services::WpFs()->mkdir( $dir );
139
- if ( !empty( realpath( $dir ) ) ) {
140
- return $dir;
141
- }
142
- }
143
- throw new \Exception( 'Working directory not available' );
144
- }
145
-
146
- protected function isReady() :bool {
147
- try {
148
- $ready = $this->getWorkingDir() !== false;
149
- }
150
- catch ( \Exception $e ) {
151
- $ready = false;
152
- }
153
- return $ready;
154
- }
155
-
156
- /**
157
- * @param \WP_REST_Request $wpReq
158
- * @return \WP_REST_Response
159
- */
160
- protected function executeApiRequest( \WP_REST_Request $wpReq ) :\WP_REST_Response {
161
-
162
- $apiResponse = $this->processRequest( $wpReq );
163
- $apiResponse[ 'meta' ][ 'params' ] = $wpReq->get_params();
164
- $apiResponse = $this->adjustApiResponse( $apiResponse, $wpReq );
165
-
166
- $response = new \WP_REST_Response();
167
- $response->set_data( $apiResponse );
168
-
169
- if ( $apiResponse[ 'error' ] ) {
170
- $response->set_status( empty( $apiResponse[ 'code' ] ) ? 500 : $apiResponse[ 'code' ] );
171
- $response->header( 'Cache-Control', 'no-cache, must-revalidate' );
172
- }
173
- else {
174
- $response->header( 'Cache-Control', 'public, max-age='.$this->getCacheHandler()->expiration );
175
- $response->set_status( 200 );
176
- }
177
-
178
- return $response;
179
- }
180
-
181
- protected function adjustApiResponse( array $response, \WP_REST_Request $wpReq ) :array {
182
- return $response;
183
- }
184
-
185
- abstract protected function processRequest( \WP_REST_Request $wpReq ) :array;
186
-
187
- /**
188
- * @param string|mixed $value
189
- * @param \WP_REST_Request $wpRequest
190
- * @param string $reqArgKey
191
- * @return \WP_Error|mixed
192
- */
193
- public function sanitizeRequestArg( $value, \WP_REST_Request $wpRequest, string $reqArgKey ) {
194
- try {
195
- $value = rest_sanitize_request_arg( $value, $wpRequest, $reqArgKey );
196
- if ( !is_wp_error( $value ) ) {
197
- $value = $this->customSanitizeRequestArg( $value, $wpRequest, $reqArgKey );
198
- }
199
- }
200
- catch ( \Exception $e ) {
201
- $value = new \WP_Error( 400, $e->getMessage() );
202
- }
203
- return $value;
204
- }
205
-
206
- /**
207
- * @param string|mixed $value
208
- * @param \WP_REST_Request $wpRequest
209
- * @param string $reqArgKey
210
- * @return \WP_Error|bool
211
- */
212
- public function validateRequestArg( $value, \WP_REST_Request $wpRequest, string $reqArgKey ) {
213
- try {
214
- $valid = rest_validate_request_arg( $value, $wpRequest, $reqArgKey );
215
- if ( $valid === true ) { // retain WP_ERROR info
216
- $valid = $this->customValidateRequestArg( $value, $wpRequest, $reqArgKey );
217
- }
218
- }
219
- catch ( \Exception $e ) {
220
- $valid = new \WP_Error( 400, $e->getMessage() );
221
- }
222
- return $valid;
223
- }
224
-
225
- /**
226
- * @param mixed $value
227
- * @param \WP_REST_Request $wpRequest
228
- * @param string $reqArgKey
229
- * @return \WP_Error|mixed
230
- * @throws \Exception
231
- */
232
- protected function customSanitizeRequestArg( $value, \WP_REST_Request $wpRequest, string $reqArgKey ) {
233
- return $value;
234
- }
235
-
236
- /**
237
- * @param string|mixed $value
238
- * @param \WP_REST_Request $wpRequest
239
- * @param string $reqArgKey
240
- * @return true
241
- * @throws \Exception
242
- */
243
- protected function customValidateRequestArg( $value, $wpRequest, $reqArgKey ) :bool {
244
- return true;
245
- }
246
-
247
- /**
248
- * @param \WP_REST_Request $req
249
- * @return \WP_Error|true
250
- */
251
- protected function verifyPermission( \WP_REST_Request $req ) {
252
- return true;
253
- }
254
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/src/Modules/Base/Lib/Rest/Route/RouteCache.php DELETED
@@ -1,45 +0,0 @@
1
- <?php declare( strict_types=1 );
2
-
3
- namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Rest\Route;
4
-
5
- use FernleafSystems\Utilities\Data\Adapter\DynProperties;
6
- use FernleafSystems\Wordpress\Services\Services;
7
- use FernleafSystems\Wordpress\Services\Utilities\File\Cache\CacheDefVO;
8
-
9
- /**
10
- * @property bool $can_cache
11
- * @property string $request_file
12
- * @property bool $is_touch
13
- * @property int $expiration
14
- * @property RouteBase|mixed $oRoute
15
- */
16
- class RouteCache {
17
-
18
- use DynProperties;
19
- use RestRouteConsumer;
20
-
21
- /**
22
- * RouteCache constructor.
23
- * @param RouteBase|mixed $route
24
- */
25
- public function __construct( $route ) {
26
- $this->setRestRoute( $route );
27
- }
28
-
29
- public function getCacheDefinition() :CacheDefVO {
30
- $def = new CacheDefVO();
31
- try {
32
- $def->dir = path_join( $this->oRoute->getWorkingDir(), 'cache' );
33
- $def->expiration = (int)$this->expiration;
34
- $def->touch_on_load = (bool)$this->is_touch;
35
- if ( !empty( $this->request_file ) ) {
36
- $def->file_fragment = Services::Data()->addExtensionToFilePath(
37
- $this->request_file, 'json'
38
- );
39
- }
40
- }
41
- catch ( \Exception $e ) {
42
- }
43
- return $def;
44
- }
45
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/src/Modules/Base/Lib/Rest/Utility/PreChecks.php DELETED
@@ -1,33 +0,0 @@
1
- <?php declare( strict_types=1 );
2
-
3
- namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Rest\Utility;
4
-
5
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
-
7
- class PreChecks {
8
-
9
- use ModConsumer;
10
-
11
- /**
12
- * @throws \Exception
13
- */
14
- public function run() {
15
- try {
16
- $this->testFileSystem();
17
- }
18
- catch ( \Exception $e ) {
19
- throw new \Exception( 'Service is temporarily unavailable. Report Code: '.$e->getCode() );
20
- }
21
- }
22
-
23
- /**
24
- * @throws \Exception
25
- */
26
- private function testFileSystem() {
27
- $dir = $this->getMod()->getWorkingDir();
28
- $space = disk_free_space( $dir );
29
- if ( $space === false || $space < 2000000 ) {
30
- throw new \Exception( 'Not enough disk space: '.$space, 402 );
31
- }
32
- }
33
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/src/Modules/Base/Lib/Rest/Utility/RestLocker.php DELETED
@@ -1,64 +0,0 @@
1
- <?php declare( strict_types=1 );
2
-
3
- namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Rest\Utility;
4
-
5
- use FernleafSystems\Wordpress\Plugin\Shield\Modules;
6
- use FernleafSystems\Wordpress\Services\Services;
7
-
8
- class RestLocker {
9
-
10
- use Modules\Base\Lib\Rest\Route\RestRouteConsumer;
11
-
12
- /**
13
- * @return bool
14
- * @throws \Exception
15
- */
16
- public function start() :bool {
17
- $count = 0;
18
- $max = 20;
19
- while ( $this->isLocked() ) {
20
- if ( $count++ > $max ) {
21
- throw new \Exception( 'Could not get a lock - there are too many requests processing. Please try again a bit later.', 403 );
22
- }
23
- usleep( 50000 );
24
- }
25
- return $this->writeLock();
26
- }
27
-
28
- /**
29
- * @return bool
30
- * @throws \Exception
31
- */
32
- private function isLocked() :bool {
33
- clearstatcache();
34
- $FS = Services::WpFs();
35
- $file = $this->getLockFile();
36
- return !empty( $file ) &&
37
- $FS->exists( $file ) && ( Services::Request()->ts() - (int)$FS->getModifiedTime( $file ) < 10 );
38
- }
39
-
40
- private function writeLock() :bool {
41
- return (bool)Services::WpFs()->touch( $this->getLockFile() );
42
- }
43
-
44
- public function end() {
45
- $FS = Services::WpFs();
46
- $file = $this->getLockFile();
47
- if ( $FS->exists( $file ) ) {
48
- Services::WpFs()->deleteFile( $file );
49
- }
50
- }
51
-
52
- /**
53
- * @return string|bool
54
- */
55
- private function getLockFile() {
56
- try {
57
- $file = path_join( $this->getRestRoute()->getWorkingDir(), 'rest_process.lock' );
58
- }
59
- catch ( \Exception $e ) {
60
- $file = false;
61
- }
62
- return $file;
63
- }
64
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/src/Modules/Base/ModCon.php CHANGED
@@ -124,16 +124,6 @@ abstract class ModCon {
124
  $this->loadAdminNotices();
125
  }
126
 
127
- if ( $this->getOptions()->getDef( 'rest_api' ) ) {
128
- add_action( 'rest_api_init', function () {
129
- try {
130
- $this->getRestHandler()->init();
131
- }
132
- catch ( \Exception $e ) {
133
- }
134
- } );
135
- }
136
-
137
  // if ( $this->isAdminOptionsPage() ) {
138
  // add_action( 'current_screen', array( $this, 'onSetCurrentScreen' ) );
139
  // }
@@ -268,7 +258,6 @@ abstract class ModCon {
268
  }
269
 
270
  /**
271
- * @return bool
272
  * @throws \Exception
273
  */
274
  protected function isReadyToExecute() :bool {
@@ -283,6 +272,27 @@ abstract class ModCon {
283
  if ( is_admin() || is_network_admin() ) {
284
  $this->getAdminPage()->execute();
285
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
286
  }
287
 
288
  public function onWpInit() {
@@ -350,7 +360,7 @@ abstract class ModCon {
350
  protected function loadProcessor() {
351
  if ( !isset( $this->oProcessor ) ) {
352
  try {
353
- $class = $this->findElementClass( 'Processor', true );
354
  }
355
  catch ( \Exception $e ) {
356
  return null;
@@ -665,11 +675,11 @@ abstract class ModCon {
665
  }
666
 
667
  public function getTextOpt( string $key ) :string {
668
- $sValue = $this->getOptions()->getOpt( $key, 'default' );
669
- if ( $sValue == 'default' ) {
670
- $sValue = $this->getTextOptDefault( $key );
671
  }
672
- return __( $sValue, 'wp-simple-firewall' );
673
  }
674
 
675
  public function getTextOptDefault( string $key ) :string {
@@ -693,13 +703,6 @@ abstract class ModCon {
693
  return $this;
694
  }
695
 
696
- public function setOptions( array $options ) {
697
- $opts = $this->getOptions();
698
- foreach ( $options as $key => $value ) {
699
- $opts->setOpt( $key, $value );
700
- }
701
- }
702
-
703
  public function isModuleRequest() :bool {
704
  return $this->getModSlug() === Services::Request()->request( 'mod_slug' );
705
  }
@@ -713,12 +716,8 @@ abstract class ModCon {
713
  return $asJson ? json_encode( (object)$data ) : $data;
714
  }
715
 
716
- /**
717
- * @param string $action
718
- * @return array
719
- */
720
- public function getNonceActionData( $action = '' ) {
721
- $data = $this->getCon()->getNonceActionData( (string)$action );
722
  $data[ 'mod_slug' ] = $this->getModSlug();
723
  return $data;
724
  }
@@ -762,12 +761,11 @@ abstract class ModCon {
762
  }
763
 
764
  /**
765
- * @param bool $bPreProcessOptions
766
  * @return $this
767
  */
768
- public function saveModOptions( $bPreProcessOptions = false ) {
769
 
770
- if ( $bPreProcessOptions ) {
771
  $this->preProcessOptions();
772
  }
773
 
@@ -1260,7 +1258,8 @@ abstract class ModCon {
1260
  }
1261
 
1262
  /**
1263
- * @return RestHandler|mixed
 
1264
  */
1265
  public function getRestHandler() {
1266
  return $this->loadModElement( 'RestHandler' );
@@ -1341,7 +1340,7 @@ abstract class ModCon {
1341
  /**
1342
  * @return Shield\Modules\Base\Databases|mixed
1343
  */
1344
- protected function getDbHandler() {
1345
  if ( empty( $this->dbHandler ) ) {
1346
  $this->dbHandler = $this->loadModElement( 'Databases' );
1347
  }
@@ -1356,7 +1355,6 @@ abstract class ModCon {
1356
  }
1357
 
1358
  /**
1359
- * @param string $class
1360
  * @return false|Shield\Modules\ModConsumer
1361
  */
1362
  private function loadModElement( string $class ) {
124
  $this->loadAdminNotices();
125
  }
126
 
 
 
 
 
 
 
 
 
 
 
127
  // if ( $this->isAdminOptionsPage() ) {
128
  // add_action( 'current_screen', array( $this, 'onSetCurrentScreen' ) );
129
  // }
258
  }
259
 
260
  /**
 
261
  * @throws \Exception
262
  */
263
  protected function isReadyToExecute() :bool {
272
  if ( is_admin() || is_network_admin() ) {
273
  $this->getAdminPage()->execute();
274
  }
275
+ if ( $this->getCon()->is_rest_enabled ) {
276
+ $this->initRestApi();
277
+ }
278
+ }
279
+
280
+ protected function initRestApi() {
281
+ $cfg = $this->getOptions()->getDef( 'rest_api' );
282
+ if ( !empty( $cfg[ 'publish' ] ) ) {
283
+ add_action( 'rest_api_init', function () use ( $cfg ) {
284
+ try {
285
+ $restClass = $this->findElementClass( 'Rest' );
286
+ /** @var Shield\Modules\Base\Rest $rest */
287
+ if ( @class_exists( $restClass ) ) {
288
+ $rest = new $restClass( $cfg );
289
+ $rest->setMod( $this )->init();
290
+ }
291
+ }
292
+ catch ( \Exception $e ) {
293
+ }
294
+ } );
295
+ }
296
  }
297
 
298
  public function onWpInit() {
360
  protected function loadProcessor() {
361
  if ( !isset( $this->oProcessor ) ) {
362
  try {
363
+ $class = $this->findElementClass( 'Processor' );
364
  }
365
  catch ( \Exception $e ) {
366
  return null;
675
  }
676
 
677
  public function getTextOpt( string $key ) :string {
678
+ $txt = $this->getOptions()->getOpt( $key, 'default' );
679
+ if ( $txt == 'default' ) {
680
+ $txt = $this->getTextOptDefault( $key );
681
  }
682
+ return __( $txt, 'wp-simple-firewall' );
683
  }
684
 
685
  public function getTextOptDefault( string $key ) :string {
703
  return $this;
704
  }
705
 
 
 
 
 
 
 
 
706
  public function isModuleRequest() :bool {
707
  return $this->getModSlug() === Services::Request()->request( 'mod_slug' );
708
  }
716
  return $asJson ? json_encode( (object)$data ) : $data;
717
  }
718
 
719
+ public function getNonceActionData( string $action = '' ) :array {
720
+ $data = $this->getCon()->getNonceActionData( $action );
 
 
 
 
721
  $data[ 'mod_slug' ] = $this->getModSlug();
722
  return $data;
723
  }
761
  }
762
 
763
  /**
 
764
  * @return $this
765
  */
766
+ public function saveModOptions( bool $preProcessOptions = false ) {
767
 
768
+ if ( $preProcessOptions ) {
769
  $this->preProcessOptions();
770
  }
771
 
1258
  }
1259
 
1260
  /**
1261
+ * @return Rest|mixed
1262
+ * @deprecated 14.1
1263
  */
1264
  public function getRestHandler() {
1265
  return $this->loadModElement( 'RestHandler' );
1340
  /**
1341
  * @return Shield\Modules\Base\Databases|mixed
1342
  */
1343
+ public function getDbHandler() {
1344
  if ( empty( $this->dbHandler ) ) {
1345
  $this->dbHandler = $this->loadModElement( 'Databases' );
1346
  }
1355
  }
1356
 
1357
  /**
 
1358
  * @return false|Shield\Modules\ModConsumer
1359
  */
1360
  private function loadModElement( string $class ) {
src/lib/src/Modules/Base/Options.php CHANGED
@@ -159,19 +159,6 @@ class Options {
159
  return ( $this->getRawData_FullFeatureConfig()[ 'properties' ] ?? [] )[ $property ] ?? null;
160
  }
161
 
162
- /**
163
- * @deprecated 14.0
164
- */
165
- public function getWpCliCfg() :array {
166
- return array_merge(
167
- [
168
- 'enabled' => true,
169
- 'root' => $this->getSlug(),
170
- ],
171
- $this->getRawData_FullFeatureConfig()[ 'wpcli' ] ?? []
172
- );
173
- }
174
-
175
  /**
176
  * @return mixed|null
177
  */
@@ -527,11 +514,10 @@ class Options {
527
  }
528
 
529
  /**
530
- * @param string $key
531
- * @param mixed $newValue
532
  * @return $this
533
  */
534
- public function setOpt( $key, $newValue ) :self {
535
 
536
  // NOTE: can't use getOpt() for current value as it'll create infinite loop
537
  $mCurrent = $this->getAllOptionsValues()[ $key ] ?? null;
@@ -716,7 +702,6 @@ class Options {
716
  }
717
 
718
  /**
719
- * @param $values
720
  * @return $this
721
  */
722
  public function setOptionsValues( array $values = [] ) {
159
  return ( $this->getRawData_FullFeatureConfig()[ 'properties' ] ?? [] )[ $property ] ?? null;
160
  }
161
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  /**
163
  * @return mixed|null
164
  */
514
  }
515
 
516
  /**
517
+ * @param mixed $newValue
 
518
  * @return $this
519
  */
520
+ public function setOpt( string $key, $newValue ) :self {
521
 
522
  // NOTE: can't use getOpt() for current value as it'll create infinite loop
523
  $mCurrent = $this->getAllOptionsValues()[ $key ] ?? null;
702
  }
703
 
704
  /**
 
705
  * @return $this
706
  */
707
  public function setOptionsValues( array $values = [] ) {
src/lib/src/Modules/Base/Options/OptValueSanitize.php CHANGED
@@ -10,12 +10,11 @@ class OptValueSanitize {
10
  use ModConsumer;
11
 
12
  /**
13
- * @param string $key
14
- * @param mixed $value
15
  * @return mixed
16
  * @throws \Exception
17
  */
18
- public function run( $key, $value ) {
19
  $opts = $this->getOptions();
20
  if ( !in_array( $key, $opts->getOptionsKeys() ) ) {
21
  throw new \Exception( sprintf( 'Not a valid option key for module: %s', $key ) );
10
  use ModConsumer;
11
 
12
  /**
13
+ * @param mixed $value
 
14
  * @return mixed
15
  * @throws \Exception
16
  */
17
+ public function run( string $key, $value ) {
18
  $opts = $this->getOptions();
19
  if ( !in_array( $key, $opts->getOptionsKeys() ) ) {
20
  throw new \Exception( sprintf( 'Not a valid option key for module: %s', $key ) );
src/lib/src/Modules/Base/Options/Storage.php CHANGED
@@ -21,7 +21,6 @@ class Storage {
21
  }
22
 
23
  /**
24
- * @return array
25
  * @throws \Exception
26
  */
27
  public function loadOptions() :array {
@@ -32,7 +31,6 @@ class Storage {
32
  }
33
 
34
  /**
35
- * @return array
36
  * @throws \Exception
37
  */
38
  private function loadFromWP() :array {
21
  }
22
 
23
  /**
 
24
  * @throws \Exception
25
  */
26
  public function loadOptions() :array {
31
  }
32
 
33
  /**
 
34
  * @throws \Exception
35
  */
36
  private function loadFromWP() :array {
src/lib/src/Modules/Base/Processor.php CHANGED
@@ -18,6 +18,7 @@ abstract class Processor {
18
  $this->setMod( $mod );
19
  add_action( 'init', [ $this, 'onWpInit' ], $this->getWpHookPriority( 'init' ) );
20
  add_action( 'wp_loaded', [ $this, 'onWpLoaded' ], $this->getWpHookPriority( 'wp_loaded' ) );
 
21
  $this->setupCronHooks();
22
  }
23
 
@@ -27,7 +28,12 @@ abstract class Processor {
27
  public function onWpLoaded() {
28
  }
29
 
30
- public function onModuleShutdown() {
 
 
 
 
 
31
  }
32
 
33
  protected function getWpHookPriority( string $hook ) :int {
18
  $this->setMod( $mod );
19
  add_action( 'init', [ $this, 'onWpInit' ], $this->getWpHookPriority( 'init' ) );
20
  add_action( 'wp_loaded', [ $this, 'onWpLoaded' ], $this->getWpHookPriority( 'wp_loaded' ) );
21
+ add_action( 'admin_init', [ $this, 'onWpAdminInit' ], $this->getWpHookPriority( 'wp_loaded' ) );
22
  $this->setupCronHooks();
23
  }
24
 
28
  public function onWpLoaded() {
29
  }
30
 
31
+ public function onWpAdminInit() {
32
+ add_filter( $this->getCon()->prefix( 'admin_bar_menu_groups' ), [ $this, 'addAdminBarMenuGroup' ] );
33
+ }
34
+
35
+ public function addAdminBarMenuGroup( array $groups ) :array {
36
+ return $groups;
37
  }
38
 
39
  protected function getWpHookPriority( string $hook ) :int {
src/lib/src/Modules/Base/Reporting.php CHANGED
@@ -38,12 +38,12 @@ abstract class Reporting {
38
  }
39
 
40
  /**
41
- * @param Reports\BaseReporter[] $aReporters
42
  * @return array
43
  */
44
- protected function assignMod( array $aReporters ) :array {
45
  return array_map( function ( $reporter ) {
46
  return $reporter->setMod( $this->getMod() );
47
- }, $aReporters );
48
  }
49
  }
38
  }
39
 
40
  /**
41
+ * @param Reports\BaseReporter[] $reporters
42
  * @return array
43
  */
44
+ protected function assignMod( array $reporters ) :array {
45
  return array_map( function ( $reporter ) {
46
  return $reporter->setMod( $this->getMod() );
47
+ }, $reporters );
48
  }
49
  }
src/lib/src/Modules/Base/Rest.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
+
7
+ /**
8
+ * @property bool $enabled
9
+ * @property bool $pro_only
10
+ */
11
+ class Rest extends \FernleafSystems\Wordpress\Plugin\Core\Rest\RestHandler {
12
+
13
+ use ModConsumer;
14
+
15
+ /**
16
+ * @return Rest\Route\RouteBase[]
17
+ */
18
+ public function buildRoutes() :array {
19
+ /** @var Rest\Route\RouteBase[] $routes */
20
+ $routes = parent::buildRoutes();
21
+ return array_map(
22
+ function ( $route ) {
23
+ return $route->setMod( $this->getMod() );
24
+ },
25
+ $routes
26
+ );
27
+ }
28
+
29
+ /**
30
+ * REST API is a pro-only feature. So, routes are only published if the plugin is pro,
31
+ * or the particular module is set to be not pro only.
32
+ */
33
+ protected function isPublishRoutes() :bool {
34
+ return parent::isPublishRoutes()
35
+ && ( $this->getCon()->isPremiumActive() || !( $this->pro_only ?? true ) );
36
+ }
37
+ }
src/lib/src/Modules/Base/Rest/Request/Process.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Rest\Request;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
+
7
+ abstract class Process extends \FernleafSystems\Wordpress\Plugin\Core\Rest\Request\Process {
8
+
9
+ use ModConsumer;
10
+
11
+ /**
12
+ * @return RequestVO|mixed
13
+ */
14
+ protected function getRequestVO() {
15
+ /** @var RequestVO $req */
16
+ $req = parent::getRequestVO();
17
+ return $req->setMod( $this->getMod() );
18
+ }
19
+
20
+ /**
21
+ * @return RequestVO
22
+ */
23
+ protected function newReqVO() {
24
+ return new RequestVO();
25
+ }
26
+ }
src/lib/src/Modules/Base/Rest/Request/RequestVO.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Rest\Request;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
+
7
+ /**
8
+ * @property string[] $filter_fields
9
+ */
10
+ class RequestVO extends \FernleafSystems\Wordpress\Plugin\Core\Rest\Request\RequestVO {
11
+
12
+ use ModConsumer;
13
+
14
+ public function __get( string $key ) {
15
+ $value = parent::__get( $key );
16
+
17
+ switch ( $key ) {
18
+
19
+ case 'filter_fields':
20
+ $value = (array)$value;
21
+ if ( in_array( 'all', $value ) ) {
22
+ $value = [];
23
+ }
24
+ else {
25
+ $value = array_merge( $this->getDefaultFilterFields(), $value );
26
+ }
27
+
28
+ $value = array_flip( array_filter( $value ) );
29
+ break;
30
+ }
31
+
32
+ return $value;
33
+ }
34
+
35
+ protected function getDefaultFilterFields() :array {
36
+ return [];
37
+ }
38
+ }
src/lib/src/Modules/Base/{Lib/Rest → Rest}/RequestVoConsumer.php RENAMED
@@ -1,8 +1,8 @@
1
  <?php declare( strict_types=1 );
2
 
3
- namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Rest;
4
 
5
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Rest\Request\RequestVO;
6
 
7
  trait RequestVoConsumer {
8
 
1
  <?php declare( strict_types=1 );
2
 
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Rest;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Rest\Request\RequestVO;
6
 
7
  trait RequestVoConsumer {
8
 
src/lib/src/Modules/Base/Rest/Route/RouteBase.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Rest\Route;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Rest\Request\Process;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
+
8
+ abstract class RouteBase extends \FernleafSystems\Wordpress\Plugin\Core\Rest\Route\RouteBase {
9
+
10
+ use ModConsumer;
11
+
12
+ protected function getNamespace() :string {
13
+ return 'shield';
14
+ }
15
+
16
+ protected function getRequestProcessor() {
17
+ /** @var Process $proc */
18
+ $proc = parent::getRequestProcessor();
19
+ return $proc->setMod( $this->getMod() );
20
+ }
21
+
22
+ protected function verifyPermission( \WP_REST_Request $req ) {
23
+ return apply_filters( 'shield/rest_api_verify_permission', parent::verifyPermission( $req ), $req );
24
+ }
25
+
26
+ protected function getConfigDefaults() :array {
27
+ $cfg = parent::getConfigDefaults();
28
+ $cfg[ 'authorization' ][ 'user_cap' ] = 'manage_options';
29
+ return $cfg;
30
+ }
31
+ }
src/lib/src/Modules/Base/Rest/Route/RouteCache.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Rest\Route;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
+
7
+ class RouteCache extends \FernleafSystems\Wordpress\Plugin\Core\Rest\Route\RouteCache {
8
+
9
+ use ModConsumer;
10
+ }
src/lib/src/Modules/Base/RestHandler.php DELETED
@@ -1,66 +0,0 @@
1
- <?php declare( strict_types=1 );
2
-
3
- namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
4
-
5
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
- use FernleafSystems\Wordpress\Services\Services;
7
-
8
- abstract class RestHandler {
9
-
10
- use ModConsumer;
11
-
12
- /**
13
- * @var Lib\Rest\Route\RouteBase[]
14
- */
15
- private $routes;
16
-
17
- public function init() {
18
- if ( $this->getIfPublishRoutes() ) {
19
- foreach ( $this->getRoutes() as $route ) {
20
- $route->register_routes();
21
- }
22
- }
23
- }
24
-
25
- /**
26
- * @return Lib\Rest\Route\RouteBase[]
27
- */
28
- protected function enumRoutes() :array {
29
- return [];
30
- }
31
-
32
- protected function getIfPublishRoutes() :bool {
33
- return true;
34
- }
35
-
36
- /**
37
- * @return Lib\Rest\Route\RouteBase[]
38
- */
39
- public function getRoutes() :array {
40
- if ( !isset( $this->routes ) ) {
41
- $this->routes = array_map(
42
- function ( $route ) {
43
- return $route->setMod( $this->getMod() );
44
- },
45
- $this->enumRoutes()
46
- );
47
- }
48
- return $this->routes;
49
- }
50
-
51
- /**
52
- * @return string
53
- * @throws \Exception
54
- */
55
- public function getWorkingDir() :string {
56
- $base = $this->getMod()->getWorkingDir();
57
- if ( !empty( $base ) ) {
58
- $dir = path_join( $base, 'api' );
59
- Services::WpFs()->mkdir( $dir );
60
- if ( !empty( realpath( $dir ) ) ) {
61
- return $dir;
62
- }
63
- }
64
- throw new \Exception( 'Working directory not available' );
65
- }
66
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/src/Modules/Base/Strings.php CHANGED
@@ -177,8 +177,6 @@ class Strings {
177
  }
178
 
179
  /**
180
- * @param string $section
181
- * @return array
182
  * @throws \Exception
183
  */
184
  public function getSectionStrings( string $section ) :array {
177
  }
178
 
179
  /**
 
 
180
  * @throws \Exception
181
  */
182
  public function getSectionStrings( string $section ) :array {
src/lib/src/Modules/Data/DB/IPs/IPRecords.php CHANGED
@@ -24,7 +24,8 @@ class IPRecords {
24
  $select = $dbh->getQuerySelector();
25
  $record = $select->filterByIPHuman( $ip )->first();
26
 
27
- if ( empty( $record ) && $autoCreate && $this->addIP( $ip ) ) {
 
28
  $record = $this->loadIP( $ip, false );
29
  }
30
 
@@ -38,7 +39,7 @@ class IPRecords {
38
  return $record;
39
  }
40
 
41
- public function addIP( string $ip ) :bool {
42
  /** @var ModCon $mod */
43
  $mod = $this->getMod();
44
  $dbh = $mod->getDbH_IPs();
@@ -47,6 +48,6 @@ class IPRecords {
47
  /** @var Ops\Record $record */
48
  $record = $dbh->getRecord();
49
  $record->ip = $ip;
50
- return $insert->insert( $record );
51
  }
52
  }
24
  $select = $dbh->getQuerySelector();
25
  $record = $select->filterByIPHuman( $ip )->first();
26
 
27
+ if ( empty( $record ) && $autoCreate ) {
28
+ $this->addIP( $ip );
29
  $record = $this->loadIP( $ip, false );
30
  }
31
 
39
  return $record;
40
  }
41
 
42
+ public function addIP( string $ip ) {
43
  /** @var ModCon $mod */
44
  $mod = $this->getMod();
45
  $dbh = $mod->getDbH_IPs();
48
  /** @var Ops\Record $record */
49
  $record = $dbh->getRecord();
50
  $record->ip = $ip;
51
+ $insert->insert( $record );
52
  }
53
  }
src/lib/src/Modules/Data/DB/IPs/Ops/Insert.php CHANGED
@@ -12,7 +12,7 @@ class Insert extends Base\Insert {
12
  */
13
  public function insert( $record ) :bool {
14
  return (bool)Services::WpDb()->doSql( sprintf(
15
- "INSERT INTO `%s` (`%s`,`created_at`) VALUES (INET6_ATON('%s'), %s)",
16
  $this->getDbH()->getTableSchema()->table,
17
  'ip',
18
  $record->ip,
12
  */
13
  public function insert( $record ) :bool {
14
  return (bool)Services::WpDb()->doSql( sprintf(
15
+ "INSERT IGNORE INTO `%s` (`%s`,`created_at`) VALUES (INET6_ATON('%s'), %s)",
16
  $this->getDbH()->getTableSchema()->table,
17
  'ip',
18
  $record->ip,
src/lib/src/Modules/Data/DB/ReqLogs/GetRequestMeta.php CHANGED
@@ -4,6 +4,7 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\DB\ReqLogs;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\{
6
  DB\ReqLogs\Ops,
 
7
  ModCon
8
  };
9
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
@@ -24,6 +25,12 @@ class GetRequestMeta {
24
  return sprintf( '<code>%s</code>', $metaDatum );
25
  },
26
  ],
 
 
 
 
 
 
27
  'uid' => [
28
  'name' => __( 'User ID', 'wp-simple-firewall' ),
29
  ],
@@ -39,6 +46,9 @@ class GetRequestMeta {
39
  'path' => [
40
  'name' => __( 'Path', 'wp-simple-firewall' ),
41
  ],
 
 
 
42
  'ua' => [
43
  'name' => __( 'User Agent', 'wp-simple-firewall' ),
44
  ],
@@ -68,6 +78,7 @@ class GetRequestMeta {
68
  $mod = $this->getMod();
69
  /** @var Ops\Select $selector */
70
  $selector = $mod->getDbH_ReqLogs()->getQuerySelector();
71
- return $selector->filterByReqID( $this->reqID )->first()->meta;
 
72
  }
73
  }
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\{
6
  DB\ReqLogs\Ops,
7
+ DB\ReqLogs\Ops\Handler,
8
  ModCon
9
  };
10
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
25
  return sprintf( '<code>%s</code>', $metaDatum );
26
  },
27
  ],
28
+ 'type' => [
29
+ 'name' => __( 'Request Type', 'wp-simple-firewall' ),
30
+ 'formatter' => function ( $metaDatum ) {
31
+ return Handler::GetTypeName( $metaDatum );
32
+ }
33
+ ],
34
  'uid' => [
35
  'name' => __( 'User ID', 'wp-simple-firewall' ),
36
  ],
46
  'path' => [
47
  'name' => __( 'Path', 'wp-simple-firewall' ),
48
  ],
49
+ 'code' => [
50
+ 'name' => __( 'Response Code', 'wp-simple-firewall' ),
51
+ ],
52
  'ua' => [
53
  'name' => __( 'User Agent', 'wp-simple-firewall' ),
54
  ],
78
  $mod = $this->getMod();
79
  /** @var Ops\Select $selector */
80
  $selector = $mod->getDbH_ReqLogs()->getQuerySelector();
81
+ $record = $selector->filterByReqID( $this->reqID )->first();
82
+ return array_merge( $record->meta, $record->getRawData() );
83
  }
84
  }
src/lib/src/Modules/Data/DB/ReqLogs/LoadLogs.php CHANGED
@@ -7,6 +7,12 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Components\IpAddressCons
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
8
  use FernleafSystems\Wordpress\Services\Services;
9
 
 
 
 
 
 
 
10
  class LoadLogs {
11
 
12
  use ModConsumer;
@@ -24,26 +30,74 @@ class LoadLogs {
24
  return $results;
25
  }
26
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  /**
28
  * @return array[]
29
  */
30
  private function selectRaw() :array {
31
  /** @var ModCon $mod */
32
  $mod = $this->getMod();
33
- $ip = $this->getIP();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  return Services::WpDb()->selectCustom(
35
- sprintf( 'SELECT req.id, req.req_id as rid, req.meta, req.created_at,
36
- ips.ip as ip
37
- FROM `%s` as `req`
38
- %s
39
- INNER JOIN `%s` as `ips`
40
- ON req.ip_ref = ips.id
41
- ORDER BY `req`.created_at DESC
42
- LIMIT 1000;',
43
  $mod->getDbH_ReqLogs()->getTableSchema()->table,
44
- empty( $ip ) ? '' : sprintf( "WHERE `ips`.ip=INET6_ATON('%s')", $ip ),
45
- $this->getCon()->getModule_Data()->getDbH_IPs()->getTableSchema()->table
 
 
 
46
  )
47
  );
48
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  }
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
8
  use FernleafSystems\Wordpress\Services\Services;
9
 
10
+ /**
11
+ * @property int $limit
12
+ * @property int $offset
13
+ * @property string[] $wheres
14
+ * @property string $order_dir
15
+ */
16
  class LoadLogs {
17
 
18
  use ModConsumer;
30
  return $results;
31
  }
32
 
33
+ public function countAll() :int {
34
+ /** @var ModCon $mod */
35
+ $mod = $this->getMod();
36
+ $wheres = $this->buildWheres();
37
+ return (int)Services::WpDb()->getVar(
38
+ sprintf( $this->getRawQuery(),
39
+ 'COUNT(*)',
40
+ $mod->getDbH_ReqLogs()->getTableSchema()->table,
41
+ $this->getCon()->getModule_Data()->getDbH_IPs()->getTableSchema()->table,
42
+ empty( $wheres ) ? '' : 'WHERE '.implode( ' AND ', $wheres ),
43
+ '',
44
+ '',
45
+ ''
46
+ )
47
+ );
48
+ }
49
+
50
  /**
51
  * @return array[]
52
  */
53
  private function selectRaw() :array {
54
  /** @var ModCon $mod */
55
  $mod = $this->getMod();
56
+
57
+ $selectFields = [
58
+ 'req.id',
59
+ 'req.req_id as rid',
60
+ 'req.type',
61
+ 'req.path',
62
+ 'req.code',
63
+ 'req.verb',
64
+ 'req.meta',
65
+ 'req.offense',
66
+ 'req.created_at',
67
+ 'ips.ip as ip',
68
+ ];
69
+
70
+ $wheres = $this->buildWheres();
71
+
72
  return Services::WpDb()->selectCustom(
73
+ sprintf( $this->getRawQuery(),
74
+ implode( ', ', $selectFields ),
 
 
 
 
 
 
75
  $mod->getDbH_ReqLogs()->getTableSchema()->table,
76
+ $mod->getDbH_IPs()->getTableSchema()->table,
77
+ empty( $wheres ) ? '' : 'WHERE '.implode( ' AND ', $wheres ),
78
+ sprintf( 'ORDER BY `req`.created_at %s', $this->order_dir ?? 'DESC' ),
79
+ isset( $this->limit ) ? sprintf( 'LIMIT %s', $this->limit ) : '',
80
+ isset( $this->offset ) ? sprintf( 'OFFSET %s', $this->offset ) : ''
81
  )
82
  );
83
  }
84
+
85
+ protected function buildWheres() :array {
86
+ $wheres = is_array( $this->wheres ) ? $this->wheres : [];
87
+ if ( !empty( $this->getIP() ) ) {
88
+ $wheres[] = sprintf( "`ips`.ip=INET6_ATON('%s')", $this->getIP() );
89
+ }
90
+ return $wheres;
91
+ }
92
+
93
+ private function getRawQuery() :string {
94
+ return 'SELECT %s
95
+ FROM `%s` as `req`
96
+ INNER JOIN `%s` as `ips`
97
+ ON req.ip_ref = ips.id
98
+ %s
99
+ %s
100
+ %s
101
+ %s;';
102
+ }
103
  }
src/lib/src/Modules/Data/DB/ReqLogs/LogRecord.php CHANGED
@@ -2,12 +2,10 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\DB\ReqLogs;
4
 
5
- use FernleafSystems\Wordpress\Plugin\Core\Databases\Base\Record;
6
-
7
  /**
8
  * @property string $ip
9
  * @property string $rid
10
  */
11
- class LogRecord extends Record {
12
 
13
  }
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\DB\ReqLogs;
4
 
 
 
5
  /**
6
  * @property string $ip
7
  * @property string $rid
8
  */
9
+ class LogRecord extends Ops\Record {
10
 
11
  }
src/lib/src/Modules/Data/DB/ReqLogs/Ops/Handler.php CHANGED
@@ -6,4 +6,30 @@ use FernleafSystems\Wordpress\Plugin\Core\Databases\Base;
6
 
7
  class Handler extends Base\Handler {
8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  }
6
 
7
  class Handler extends Base\Handler {
8
 
9
+ const TYPE_AJAX = 'AJAX';
10
+ const TYPE_CRON = 'CRON';
11
+ const TYPE_HTTP = 'HTTP';
12
+ const TYPE_REST = 'REST';
13
+ const TYPE_WPCLI = 'WPCLI';
14
+ const TYPE_XMLRPC = 'XML';
15
+
16
+ public static function GetTypeName( string $type ) :string {
17
+ switch ( $type ) {
18
+ case Handler::TYPE_REST:
19
+ $type = 'REST API';
20
+ break;
21
+ case Handler::TYPE_XMLRPC:
22
+ $type = 'XML-RPC';
23
+ break;
24
+ case Handler::TYPE_WPCLI:
25
+ $type = 'WP-CLI';
26
+ break;
27
+ case Handler::TYPE_HTTP:
28
+ case Handler::TYPE_AJAX:
29
+ case Handler::TYPE_CRON:
30
+ default:
31
+ break;
32
+ }
33
+ return $type;
34
+ }
35
  }
src/lib/src/Modules/Data/DB/ReqLogs/Ops/Record.php CHANGED
@@ -5,7 +5,28 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\DB\ReqLogs\Ops;
5
  /**
6
  * @property string $req_id
7
  * @property int $ip_ref
 
 
 
 
 
8
  */
9
  class Record extends \FernleafSystems\Wordpress\Plugin\Core\Databases\Base\Record {
10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  }
5
  /**
6
  * @property string $req_id
7
  * @property int $ip_ref
8
+ * @property string $type
9
+ * @property string $path
10
+ * @property string $verb
11
+ * @property int $code
12
+ * @property bool $offense
13
  */
14
  class Record extends \FernleafSystems\Wordpress\Plugin\Core\Databases\Base\Record {
15
 
16
+ public function __get( string $key ) {
17
+
18
+ $value = parent::__get( $key );
19
+
20
+ switch ( $key ) {
21
+
22
+ case 'offense':
23
+ $value = (bool)$value;
24
+ break;
25
+
26
+ default:
27
+ break;
28
+ }
29
+
30
+ return $value;
31
+ }
32
  }
src/lib/src/Modules/Data/Lib/UpgradeReqLogsTable.php ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\Lib;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\DB\ReqLogs\Ops\Handler;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\DB\ReqLogs\Ops\Record;
8
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\DB\ReqLogs\Ops\Select;
9
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\ModCon;
10
+
11
+ class UpgradeReqLogsTable extends ExecOnceModConsumer {
12
+
13
+ protected function run() {
14
+ /** @var ModCon $mod */
15
+ $mod = $this->getMod();
16
+ /** @var Select $select */
17
+ $select = $mod->getDbH_ReqLogs()->getQuerySelector();
18
+
19
+ $page = 1;
20
+ $pageSize = 100;
21
+ do {
22
+ /** @var Record[] $records */
23
+ $records = $select->setLimit( $pageSize )
24
+ ->setPage( $page )
25
+ ->addWhere( 'type', '' )
26
+ ->queryWithResult();
27
+ foreach ( $records as $record ) {
28
+ try {
29
+ $this->upgradeLogEntry( $record );
30
+ }
31
+ catch ( \Exception $e ) {
32
+ break( 2 );
33
+ }
34
+ }
35
+
36
+ $page++;
37
+ } while ( !empty( $records ) );
38
+ }
39
+
40
+ /**
41
+ * @throws \Exception
42
+ */
43
+ private function upgradeLogEntry( Record $record ) {
44
+ /** @var ModCon $mod */
45
+ $mod = $this->getMod();
46
+
47
+ $upgradeData = [
48
+ 'type' => Handler::TYPE_HTTP,
49
+ 'path' => $record->path,
50
+ ];
51
+
52
+ $meta = $record->meta;
53
+
54
+ if ( $meta[ 'ua' ] === 'wpcli' ) {
55
+ $isWpCli = true;
56
+ $upgradeData[ 'type' ] = 'WPCLI';
57
+ unset( $meta[ 'ua' ] );
58
+ }
59
+ else {
60
+ $isWpCli = false;
61
+ }
62
+
63
+ if ( isset( $meta[ 'code' ] ) && is_numeric( $meta[ 'code' ] ) ) {
64
+ $upgradeData[ 'code' ] = (int)$meta[ 'code' ];
65
+ unset( $meta[ 'code' ] );
66
+ }
67
+
68
+ if ( isset( $meta[ 'offense' ] ) ) {
69
+ $upgradeData[ 'offense' ] = true;
70
+ unset( $meta[ 'offense' ] );
71
+ }
72
+
73
+ if ( !empty( $meta[ 'path' ] ) ) {
74
+ $parts = explode( $isWpCli ? ' ' : '?', (string)$meta[ 'path' ], 2 );
75
+ $upgradeData[ 'path' ] = $parts[ 0 ];
76
+ $meta[ 'query' ] = $parts[ 1 ];
77
+ unset( $meta[ 'path' ] );
78
+ }
79
+
80
+ if ( !empty( $meta[ 'verb' ] ) ) {
81
+ $upgradeData[ 'verb' ] = strtoupper( (string)$meta[ 'verb' ] );
82
+ unset( $meta[ 'verb' ] );
83
+ }
84
+
85
+ if ( ( $meta[ 'ua' ] ?? '' ) === 'wpcli' ) {
86
+ $upgradeData[ 'type' ] = 'WPCLI';
87
+ unset( $meta[ 'ua' ] );
88
+ }
89
+ elseif ( wp_parse_url( admin_url( 'admin-ajax.php' ), PHP_URL_PATH ) === $upgradeData[ 'path' ] ) {
90
+ $upgradeData[ 'type' ] = 'AJAX';
91
+ }
92
+ elseif ( wp_parse_url( home_url( 'wp-cron.php' ), PHP_URL_PATH ) === $upgradeData[ 'path' ] ) {
93
+ $upgradeData[ 'type' ] = 'CRON';
94
+ }
95
+ elseif ( wp_parse_url( home_url( 'xmlrpc.php' ), PHP_URL_PATH ) === $upgradeData[ 'path' ] ) {
96
+ $upgradeData[ 'type' ] = 'XML';
97
+ }
98
+
99
+ $record->meta = $meta;
100
+ $upgradeData[ 'meta' ] = $record->getRawData()[ 'meta' ];
101
+
102
+ $success = $mod->getDbH_ReqLogs()
103
+ ->getQueryUpdater()
104
+ ->updateById( $record->id, $upgradeData );
105
+ if ( !$success ) {
106
+ throw new \Exception( 'failed to update' );
107
+ }
108
+ }
109
+ }
src/lib/src/Modules/Data/Upgrade.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Data;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\Lib\UpgradeReqLogsTable;
7
+
8
+ class Upgrade extends Base\Upgrade {
9
+
10
+ protected function upgrade_1410() {
11
+ ( new UpgradeReqLogsTable() )
12
+ ->setMod( $this->getMod() )
13
+ ->execute();
14
+ }
15
+ }
src/lib/src/Modules/Firewall/Lib/Scan/Checks/Standard.php CHANGED
@@ -7,7 +7,6 @@ class Standard extends Base {
7
  private $params;
8
 
9
  /**
10
- * @param array $params
11
  * @return false|\WP_Error
12
  */
13
  public function run( array $params ) {
@@ -32,7 +31,7 @@ class Standard extends Base {
32
  $found = false;
33
  foreach ( $this->getFirewallPatterns_Regex() as $term ) {
34
  foreach ( $this->params as $param => $value ) {
35
- if ( preg_match( $term, $value ) ) {
36
  $found = new \WP_Error( 'shield-firewall', '', [
37
  'param' => $param,
38
  'value' => $value,
7
  private $params;
8
 
9
  /**
 
10
  * @return false|\WP_Error
11
  */
12
  public function run( array $params ) {
31
  $found = false;
32
  foreach ( $this->getFirewallPatterns_Regex() as $term ) {
33
  foreach ( $this->params as $param => $value ) {
34
+ if ( preg_match( sprintf( '/%s/i', $term ), $value ) ) {
35
  $found = new \WP_Error( 'shield-firewall', '', [
36
  'param' => $param,
37
  'value' => $value,
src/lib/src/Modules/Firewall/Lib/Scan/Handlers/Base.php CHANGED
@@ -16,7 +16,7 @@ abstract class Base {
16
 
17
  if ( !empty( $this->getFirewallPatterns() ) ) {
18
  $checkResult = $this->testSimplePatterns();
19
- if ( !is_wp_error( $checkResult ) ) {
20
  $checkResult = $this->testRegexPatterns();
21
  }
22
  }
@@ -50,7 +50,7 @@ abstract class Base {
50
  }
51
 
52
  protected function testRegexPatterns() :\WP_Error {
53
- $found = new \WP_Error;
54
  foreach ( $this->getFirewallPatterns_Regex() as $term ) {
55
  foreach ( $this->getItemsToScan() as $param => $value ) {
56
  if ( preg_match( $term, $value ) ) {
@@ -70,7 +70,7 @@ abstract class Base {
70
  }
71
 
72
  protected function testSimplePatterns() :\WP_Error {
73
- $found = new \WP_Error;
74
  foreach ( $this->getFirewallPatterns_Simple() as $term ) {
75
  foreach ( $this->getItemsToScan() as $param => $value ) {
76
  if ( stripos( $value, $term ) !== false ) {
16
 
17
  if ( !empty( $this->getFirewallPatterns() ) ) {
18
  $checkResult = $this->testSimplePatterns();
19
+ if ( empty( $checkResult->get_error_codes() ) ) {
20
  $checkResult = $this->testRegexPatterns();
21
  }
22
  }
50
  }
51
 
52
  protected function testRegexPatterns() :\WP_Error {
53
+ $found = new \WP_Error();
54
  foreach ( $this->getFirewallPatterns_Regex() as $term ) {
55
  foreach ( $this->getItemsToScan() as $param => $value ) {
56
  if ( preg_match( $term, $value ) ) {
70
  }
71
 
72
  protected function testSimplePatterns() :\WP_Error {
73
+ $found = new \WP_Error();
74
  foreach ( $this->getFirewallPatterns_Simple() as $term ) {
75
  foreach ( $this->getItemsToScan() as $param => $value ) {
76
  if ( stripos( $value, $term ) !== false ) {
src/lib/src/Modules/HackGuard/Lib/Snapshots/StoreAction/BaseBulk.php DELETED
@@ -1,13 +0,0 @@
1
- <?php declare( strict_types=1 );
2
-
3
- namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\Snapshots\StoreAction;
4
-
5
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
-
7
- /**
8
- * @deprecated 14.0
9
- */
10
- class BaseBulk {
11
-
12
- use ModConsumer;
13
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/src/Modules/HackGuard/Lib/Snapshots/StoreAction/CleanAll.php DELETED
@@ -1,29 +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\ModCon;
6
- use FernleafSystems\Wordpress\Plugin\Shield\Scans\Helpers\StandardDirectoryIterator;
7
- use FernleafSystems\Wordpress\Services\Services;
8
-
9
- class CleanAll extends BaseBulk {
10
-
11
- public function run() {
12
- /** @var ModCon $mod */
13
- $mod = $this->getMod();
14
- try {
15
- $boundary = Services::Request()
16
- ->carbon()
17
- ->subDay()->timestamp;
18
- $IT = StandardDirectoryIterator::create( $mod->getPtgSnapsBaseDir() );
19
- foreach ( $IT as $file ) {
20
- /** @var \SplFileInfo $file */
21
- if ( $boundary > $file->getMTime() ) {
22
- Services::WpFs()->deleteFile( $file->getPathname() );
23
- }
24
- }
25
- }
26
- catch ( \Exception $e ) {
27
- }
28
- }
29
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/src/Modules/HackGuard/Lib/Snapshots/StoreAction/ScheduleBuildAll.php CHANGED
@@ -26,10 +26,7 @@ class ScheduleBuildAll extends Base {
26
  }
27
  }
28
 
29
- /**
30
- * @deprecated 14.0 - make this private
31
- */
32
- public function build() {
33
  foreach ( $this->getAssetsThatNeedBuilt() as $asset ) {
34
  try {
35
  ( new Build() )
26
  }
27
  }
28
 
29
+ private function build() {
 
 
 
30
  foreach ( $this->getAssetsThatNeedBuilt() as $asset ) {
31
  try {
32
  ( new Build() )
src/lib/src/Modules/HackGuard/ModCon.php CHANGED
@@ -210,13 +210,6 @@ class ModCon extends BaseShield\ModCon {
210
  $opts->setOpt( 'ufc_exclusions', array_unique( $excl ) );
211
  }
212
 
213
- /**
214
- * @deprecated 14.0
215
- */
216
- public function getPtgSnapsBaseDir() :string {
217
- return $this->getCon()->cache_dir_handler->buildSubDir( 'ptguard' );
218
- }
219
-
220
  public function hasWizard() :bool {
221
  return false;
222
  }
210
  $opts->setOpt( 'ufc_exclusions', array_unique( $excl ) );
211
  }
212
 
 
 
 
 
 
 
 
213
  public function hasWizard() :bool {
214
  return false;
215
  }
src/lib/src/Modules/HackGuard/Processor.php CHANGED
@@ -18,4 +18,30 @@ class Processor extends BaseShield\Processor {
18
  $mod->getFileLocker()->execute();
19
  }
20
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  }
18
  $mod->getFileLocker()->execute();
19
  }
20
  }
21
+
22
+ public function addAdminBarMenuGroup( array $groups ) :array {
23
+ /** @var ModCon $mod */
24
+ $mod = $this->getMod();
25
+ $thisGroup = [
26
+ 'href' => $this->getCon()->getModule_Insights()->getUrl_ScansResults(),
27
+ 'items' => [],
28
+ ];
29
+ foreach ( $mod->getScansCon()->getAllScanCons() as $scanCon ) {
30
+ if ( $scanCon->isEnabled() ) {
31
+ $thisGroup[ 'items' ] = array_merge( $thisGroup[ 'items' ], $scanCon->getAdminMenuItems() );
32
+ }
33
+ }
34
+
35
+ if ( !empty( $thisGroup[ 'items' ] ) ) {
36
+ $totalWarnings = 0;
37
+ foreach ( $thisGroup[ 'items' ] as $item ) {
38
+ $totalWarnings += $item[ 'warnings' ];
39
+ }
40
+ $thisGroup[ 'title' ] = sprintf( '%s %s', __( 'Scan Results', 'wp-simple-firewall' ),
41
+ sprintf( '<div class="wp-core-ui wp-ui-notification shield-counter"><span aria-hidden="true">%s</span></div>', $totalWarnings ) );
42
+ $groups[] = $thisGroup;
43
+ }
44
+
45
+ return $groups;
46
+ }
47
  }
src/lib/src/Modules/HackGuard/Rest.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Rest\Route\{
6
+ Results\GetAll,
7
+ Scans\Start,
8
+ Scans\Status
9
+ };
10
+
11
+ class Rest extends \FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Rest {
12
+
13
+ protected function enumRoutes() :array {
14
+ return [
15
+ 'scan_status' => Status::class,
16
+ 'scan_start' => Start::class,
17
+ 'scan_results' => GetAll::class,
18
+ ];
19
+ }
20
+ }
src/lib/src/Modules/HackGuard/Rest/Request/Base.php ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Rest\Request;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Rest\Request\Process;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\ModCon;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Scan\Init\ScansStatus;
8
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Strings;
9
+
10
+ abstract class Base extends Process {
11
+
12
+ protected function newReqVO() {
13
+ return new RequestVO();
14
+ }
15
+
16
+ protected function getScansStatus() :array {
17
+ /** @var ModCon $mod */
18
+ $mod = $this->getMod();
19
+ /** @var Strings $strings */
20
+ $strings = $mod->getStrings();
21
+
22
+ $statusChecker = ( new ScansStatus() )->setMod( $mod );
23
+ $queueCon = $mod->getScanQueueController();
24
+
25
+ $current = $statusChecker->current();
26
+ $hasCurrent = !empty( $current );
27
+ if ( $hasCurrent ) {
28
+ $currentScan = $strings->getScanName( $current );
29
+ }
30
+ else {
31
+ $currentScan = __( 'No scan running.', 'wp-simple-firewall' );
32
+ }
33
+
34
+ $enqueued = $statusChecker->enqueued();
35
+
36
+ return [
37
+ 'enqueued_count' => count( $enqueued ),
38
+ 'enqueued_status' => $queueCon->getScansRunningStates(),
39
+ 'current_slug' => $current,
40
+ 'current_name' => $currentScan,
41
+ 'progress' => $queueCon->getScanJobProgress(),
42
+ ];
43
+ }
44
+ }
src/lib/src/Modules/HackGuard/Rest/Request/RequestVO.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Rest\Request;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Options;
6
+
7
+ /**
8
+ * @property string[] $scan_slugs
9
+ */
10
+ class RequestVO extends \FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Rest\Request\RequestVO {
11
+
12
+ public function __get( string $key ) {
13
+ /** @var Options $opts */
14
+ $opts = $this->getOptions();
15
+
16
+ $value = parent::__get( $key );
17
+
18
+ switch ( $key ) {
19
+
20
+ case 'scan_slugs':
21
+ $value = (array)$value;
22
+ if ( empty( $value ) ) {
23
+ $value = $opts->getScanSlugs();
24
+ }
25
+ break;
26
+ }
27
+
28
+ return $value;
29
+ }
30
+ }
src/lib/src/Modules/HackGuard/Rest/Request/Results/GetAll.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Rest\Request\Results;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\ModCon;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Rest\Request\Base;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Rest\Request\RequestVO;
8
+
9
+ class GetAll extends Base {
10
+
11
+ protected function process() :array {
12
+ /** @var ModCon $mod */
13
+ $mod = $this->getMod();
14
+ /** @var RequestVO $req */
15
+ $req = $this->getRequestVO();
16
+
17
+ if ( $this->getScansStatus()[ 'enqueued_count' ] > 0 ) {
18
+ throw new \Exception( 'Results are unavailable while scans are currently running.' );
19
+ }
20
+
21
+ $statesToInclude = [];
22
+ if ( !empty( $req->filter_item_state ) ) {
23
+ $statesToInclude = array_filter( explode( ',', $req->filter_item_state ) );
24
+ }
25
+
26
+ $results = [];
27
+ foreach ( $req->scan_slugs as $scanSlug ) {
28
+ $RS = $mod->getScanCon( $scanSlug )->getAllResults();
29
+ $thisResults = [];
30
+ foreach ( $RS->getAllItems() as $item ) {
31
+ $item = array_merge(
32
+ $item->getRawData(),
33
+ array_intersect_key(
34
+ $item->VO->getRawData(),
35
+ array_flip( [
36
+ 'ignored_at',
37
+ 'notified_at',
38
+ 'attempt_repair_at',
39
+ 'item_repaired_at',
40
+ 'item_deleted_at',
41
+ 'scanresult_id'
42
+ ] )
43
+ )
44
+ );
45
+
46
+ // TODO: we ought to filter some of these at the DB query stage
47
+ if ( empty( $statesToInclude ) ) {
48
+ $include = true;
49
+ }
50
+ else {
51
+ $include = false;
52
+ foreach ( $statesToInclude as $itemState ) {
53
+ if ( !empty( $item[ $itemState ] ) ) {
54
+ $include = true;
55
+ break;
56
+ }
57
+ }
58
+ }
59
+
60
+ if ( $include ) {
61
+ ksort( $item );
62
+ $thisResults[] = $item;
63
+ }
64
+ }
65
+
66
+ $results[ $scanSlug ] = [
67
+ 'total' => count( $thisResults ),
68
+ 'items' => $thisResults,
69
+ ];
70
+ }
71
+
72
+ ksort( $results );
73
+ return $results;
74
+ }
75
+ }
src/lib/src/Modules/HackGuard/Rest/Request/Scans/Base.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Rest\Request\Scans;
4
+
5
+ abstract class Base extends \FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Rest\Request\Base {
6
+
7
+ }
src/lib/src/Modules/HackGuard/Rest/Request/Scans/Start.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Rest\Request\Scans;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\ModCon;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Rest\Request\RequestVO;
7
+
8
+ class Start extends Base {
9
+
10
+ protected function process() :array {
11
+ /** @var ModCon $mod */
12
+ $mod = $this->getMod();
13
+ /** @var RequestVO $req */
14
+ $req = $this->getRequestVO();
15
+
16
+ if ( $this->getScansStatus()[ 'enqueued_count' ] > 0 ) {
17
+ throw new \Exception( 'Scans are already running.' );
18
+ }
19
+ $mod->getScansCon()->startNewScans( $req->scan_slugs );
20
+
21
+ return $this->getScansStatus();
22
+ }
23
+ }
src/lib/src/Modules/HackGuard/Rest/Request/Scans/Status.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Rest\Request\Scans;
4
+
5
+ class Status extends Base {
6
+
7
+ protected function process() :array {
8
+ return $this->getScansStatus();
9
+ }
10
+ }
src/lib/src/Modules/HackGuard/Rest/Route/Base.php ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Rest\Route;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Rest\Route\RouteBase;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Options;
7
+
8
+ abstract class Base extends RouteBase {
9
+
10
+ public function getRoutePathPrefix() :string {
11
+ return '/';
12
+ }
13
+
14
+ protected function getRouteArgSchema( string $key ) :array {
15
+ switch ( $key ) {
16
+ case 'scan_slugs':
17
+ /** @var Options $opts */
18
+ $opts = $this->getOptions();
19
+ $possible = $opts->getScanSlugs();
20
+ $sch = [
21
+ 'title' => 'Scan Slugs',
22
+ 'description' => sprintf( 'Comma-separated scan slugs to include (allowed: %s).', implode( ', ', $possible ) ),
23
+ 'type' => 'array',
24
+ 'required' => false,
25
+ ];
26
+ break;
27
+
28
+ default:
29
+ $sch = parent::getRouteArgSchema( $key );
30
+ break;
31
+ }
32
+ return $sch;
33
+ }
34
+
35
+ protected function customSanitizeRequestArg( $value, \WP_REST_Request $request, string $reqArgKey ) {
36
+
37
+ switch ( $reqArgKey ) {
38
+
39
+ case 'scan_slugs':
40
+ /** @var Options $opts */
41
+ $opts = $this->getOptions();
42
+ $possible = $opts->getScanSlugs();
43
+ $value = array_intersect( $possible, $value );
44
+ if ( empty( $value ) ) {
45
+ $value = $possible;
46
+ }
47
+ break;
48
+
49
+ default:
50
+ return parent::customSanitizeRequestArg( $value, $request, $reqArgKey );
51
+ }
52
+
53
+ return $value;
54
+ }
55
+
56
+ protected function customValidateRequestArg( $value, \WP_REST_Request $request, string $reqArgKey ) {
57
+
58
+ switch ( $reqArgKey ) {
59
+
60
+ case 'scan_slugs':
61
+ /** @var Options $opts */
62
+ $opts = $this->getOptions();
63
+ $possible = $opts->getScanSlugs();
64
+ $slugsSent = array_filter( is_array( $value ) ? $value : explode( ',', $value ) );
65
+ if ( !empty( $slugsSent ) && count( array_diff( $slugsSent, $possible ) ) > 0 ) {
66
+ throw new \Exception( sprintf( 'Invalid scan slugs provided. Please only supply: %s', implode( ', ', $possible ) ) );
67
+ }
68
+ break;
69
+
70
+ default:
71
+ return parent::customValidateRequestArg( $value, $request, $reqArgKey );
72
+ }
73
+
74
+ return $value;
75
+ }
76
+ }
src/lib/src/Modules/HackGuard/Rest/Route/Results/GetAll.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Rest\Route\Results;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Rest\Request\Results;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Rest\Route\Base;
7
+
8
+ class GetAll extends Base {
9
+
10
+ protected function getRouteArgsCustom() :array {
11
+ return [
12
+ 'scan_slugs' => $this->getRouteArgSchema( 'scan_slugs' ),
13
+ 'filter_item_state' => [
14
+ 'description' => '[Filter] Comma-separated scan item states to include.',
15
+ 'type' => 'string',
16
+ 'required' => false,
17
+ 'pattern' => sprintf( '^((%s),?)+$', implode( '|', [
18
+ 'is_checksumfail',
19
+ 'is_unrecognised',
20
+ 'is_mal',
21
+ 'is_missing',
22
+ 'is_abandoned',
23
+ 'is_vulnerable',
24
+ ] ) ),
25
+ ],
26
+ ];
27
+ }
28
+
29
+ public function getRoutePath() :string {
30
+ return '/scan_results';
31
+ }
32
+
33
+ protected function getRequestProcessorClass() :string {
34
+ return Results\GetAll::class;
35
+ }
36
+ }
src/lib/src/Modules/HackGuard/Rest/Route/Scans/ScansBase.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Rest\Route\Scans;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Rest\Route\Base;
6
+
7
+ abstract class ScansBase extends Base {
8
+
9
+ public function getRoutePath() :string {
10
+ return '/scans';
11
+ }
12
+ }
src/lib/src/Modules/HackGuard/Rest/Route/Scans/Start.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Rest\Route\Scans;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Rest\Request\Scans;
6
+
7
+ class Start extends ScansBase {
8
+
9
+ const ROUTE_METHOD = \WP_REST_Server::CREATABLE;
10
+
11
+ protected function getRequestProcessorClass() :string {
12
+ return Scans\Start::class;
13
+ }
14
+
15
+ protected function getRouteArgsCustom() :array {
16
+ return [
17
+ 'scan_slugs' => $this->getRouteArgSchema( 'scan_slugs' ),
18
+ ];
19
+ }
20
+ }
src/lib/src/Modules/HackGuard/Rest/Route/Scans/Status.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Rest\Route\Scans;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Rest\Request\Scans;
6
+
7
+ class Status extends ScansBase {
8
+
9
+ protected function getRequestProcessorClass() :string {
10
+ return Scans\Status::class;
11
+ }
12
+ }
src/lib/src/Modules/HackGuard/Scan/Controller/Afs.php CHANGED
@@ -29,13 +29,13 @@ class Afs extends BaseForFiles {
29
  add_action( 'wp_loaded', [ $this, 'onWpLoaded' ] );
30
  }
31
 
32
- public function addAdminMenuBarItem( array $items ) :array {
 
33
  $status = $this->getScansController()->getScanResultsCount();
34
 
35
  $template = [
36
  'id' => $this->getCon()->prefix( 'problems-'.$this->getSlug() ),
37
  'title' => '<div class="wp-core-ui wp-ui-notification shield-counter"><span aria-hidden="true">%s</span></div>',
38
- 'href' => $this->getCon()->getModule_Insights()->getUrl_ScansResults(),
39
  ];
40
 
41
  $count = $status->countMalware();
@@ -77,6 +77,13 @@ class Afs extends BaseForFiles {
77
  return $items;
78
  }
79
 
 
 
 
 
 
 
 
80
  public function onWpLoaded() {
81
  ( new Lib\Snapshots\StoreAction\ScheduleBuildAll() )
82
  ->setMod( $this->getMod() )
29
  add_action( 'wp_loaded', [ $this, 'onWpLoaded' ] );
30
  }
31
 
32
+ public function getAdminMenuItems() :array {
33
+ $items = [];
34
  $status = $this->getScansController()->getScanResultsCount();
35
 
36
  $template = [
37
  'id' => $this->getCon()->prefix( 'problems-'.$this->getSlug() ),
38
  'title' => '<div class="wp-core-ui wp-ui-notification shield-counter"><span aria-hidden="true">%s</span></div>',
 
39
  ];
40
 
41
  $count = $status->countMalware();
77
  return $items;
78
  }
79
 
80
+ /**
81
+ * @deprecated 14.1
82
+ */
83
+ public function addAdminMenuBarItem( array $items ) :array {
84
+ return $items;
85
+ }
86
+
87
  public function onWpLoaded() {
88
  ( new Lib\Snapshots\StoreAction\ScheduleBuildAll() )
89
  ->setMod( $this->getMod() )
src/lib/src/Modules/HackGuard/Scan/Controller/Apc.php CHANGED
@@ -9,11 +9,12 @@ class Apc extends BaseForAssets {
9
 
10
  const SCAN_SLUG = 'apc';
11
 
12
- public function addAdminMenuBarItem( array $items ) :array {
 
 
13
  $template = [
14
  'id' => $this->getCon()->prefix( 'problems-'.$this->getSlug() ),
15
  'title' => '<div class="wp-core-ui wp-ui-notification shield-counter"><span aria-hidden="true">%s</span></div>',
16
- 'href' => $this->getCon()->getModule_Insights()->getUrl_ScansResults(),
17
  ];
18
 
19
  $count = $this->getScansController()->getScanResultsCount()->countAbandoned();
@@ -52,4 +53,11 @@ class Apc extends BaseForAssets {
52
  ->build()
53
  ->getScanActionVO();
54
  }
 
 
 
 
 
 
 
55
  }
9
 
10
  const SCAN_SLUG = 'apc';
11
 
12
+ public function getAdminMenuItems() :array {
13
+ $items = [];
14
+
15
  $template = [
16
  'id' => $this->getCon()->prefix( 'problems-'.$this->getSlug() ),
17
  'title' => '<div class="wp-core-ui wp-ui-notification shield-counter"><span aria-hidden="true">%s</span></div>',
 
18
  ];
19
 
20
  $count = $this->getScansController()->getScanResultsCount()->countAbandoned();
53
  ->build()
54
  ->getScanActionVO();
55
  }
56
+
57
+ /**
58
+ * @deprecated 14.1
59
+ */
60
+ public function addAdminMenuBarItem( array $items ) :array {
61
+ return $items;
62
+ }
63
  }
src/lib/src/Modules/HackGuard/Scan/Controller/Base.php CHANGED
@@ -11,9 +11,9 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Scan\Results\{
11
  Update
12
  };
13
  use FernleafSystems\Wordpress\Plugin\Shield\Scans;
 
14
  use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\ResultItem;
15
  use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\ResultsSet;
16
- use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\BaseScanActionVO;
17
  use FernleafSystems\Wordpress\Services\Services;
18
 
19
  abstract class Base extends ExecOnceModConsumer {
@@ -45,13 +45,19 @@ abstract class Base extends ExecOnceModConsumer {
45
  $mod->getScansCon()->startNewScans( [ $this->getSlug() ] );
46
  }
47
  );
48
- add_filter( $this->getCon()->prefix( 'admin_bar_menu_items' ), [ $this, 'addAdminMenuBarItem' ], 100 );
49
  }
50
 
 
 
 
51
  public function addAdminMenuBarItem( array $items ) :array {
52
  return [];
53
  }
54
 
 
 
 
 
55
  public function cleanStalesResults() {
56
  foreach ( $this->getAllResults()->getItems() as $item ) {
57
  $this->cleanStaleResultItem( $item );
11
  Update
12
  };
13
  use FernleafSystems\Wordpress\Plugin\Shield\Scans;
14
+ use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\BaseScanActionVO;
15
  use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\ResultItem;
16
  use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\ResultsSet;
 
17
  use FernleafSystems\Wordpress\Services\Services;
18
 
19
  abstract class Base extends ExecOnceModConsumer {
45
  $mod->getScansCon()->startNewScans( [ $this->getSlug() ] );
46
  }
47
  );
 
48
  }
49
 
50
+ /**
51
+ * @deprecated 14.1
52
+ */
53
  public function addAdminMenuBarItem( array $items ) :array {
54
  return [];
55
  }
56
 
57
+ public function getAdminMenuItems() :array {
58
+ return [];
59
+ }
60
+
61
  public function cleanStalesResults() {
62
  foreach ( $this->getAllResults()->getItems() as $item ) {
63
  $this->cleanStaleResultItem( $item );
src/lib/src/Modules/HackGuard/Scan/Controller/Wpv.php CHANGED
@@ -33,13 +33,20 @@ class Wpv extends BaseForAssets {
33
  }
34
  }
35
 
 
 
 
36
  public function addAdminMenuBarItem( array $items ) :array {
 
 
 
 
 
37
  $status = $this->getScansController()->getScanResultsCount();
38
 
39
  $template = [
40
  'id' => $this->getCon()->prefix( 'problems-'.$this->getSlug() ),
41
  'title' => '<div class="wp-core-ui wp-ui-notification shield-counter"><span aria-hidden="true">%s</span></div>',
42
- 'href' => $this->getCon()->getModule_Insights()->getUrl_ScansResults(),
43
  ];
44
 
45
  $count = $status->countVulnerableAssets();
33
  }
34
  }
35
 
36
+ /**
37
+ * @deprecated 14.1
38
+ */
39
  public function addAdminMenuBarItem( array $items ) :array {
40
+ return $items;
41
+ }
42
+
43
+ public function getAdminMenuItems() :array {
44
+ $items = [];
45
  $status = $this->getScansController()->getScanResultsCount();
46
 
47
  $template = [
48
  'id' => $this->getCon()->prefix( 'problems-'.$this->getSlug() ),
49
  'title' => '<div class="wp-core-ui wp-ui-notification shield-counter"><span aria-hidden="true">%s</span></div>',
 
50
  ];
51
 
52
  $count = $status->countVulnerableAssets();
src/lib/src/Modules/HackGuard/Scan/ScansController.php CHANGED
@@ -143,6 +143,12 @@ class ScansController extends ExecOnceModConsumer {
143
  return $reasons;
144
  }
145
 
 
 
 
 
 
 
146
  public function startNewScans( array $scans, bool $resetIgnored = false ) :bool {
147
  /** @var ModCon $mod */
148
  $mod = $this->getMod();
143
  return $reasons;
144
  }
145
 
146
+ public function startAllScans() {
147
+ /** @var Options $opts */
148
+ $opts = $this->getOptions();
149
+ $this->startNewScans( $opts->getScanSlugs() );
150
+ }
151
+
152
  public function startNewScans( array $scans, bool $resetIgnored = false ) :bool {
153
  /** @var ModCon $mod */
154
  $mod = $this->getMod();
src/lib/src/Modules/IPs/Components/QueryIpBlock.php CHANGED
@@ -15,8 +15,8 @@ class QueryIpBlock {
15
  public function run() :bool {
16
  $isBlocked = false;
17
 
18
- $oIP = $this->getBlockedIpRecord();
19
- if ( $oIP instanceof Databases\IPs\EntryVO ) {
20
 
21
  $isBlocked = true;
22
 
@@ -24,7 +24,7 @@ class QueryIpBlock {
24
  $mod = $this->getMod();
25
  /** @var Databases\IPs\Update $upd */
26
  $upd = $mod->getDbHandler_IPs()->getQueryUpdater();
27
- $upd->updateLastAccessAt( $oIP );
28
  }
29
  return $isBlocked;
30
  }
15
  public function run() :bool {
16
  $isBlocked = false;
17
 
18
+ $IP = $this->getBlockedIpRecord();
19
+ if ( $IP instanceof Databases\IPs\EntryVO ) {
20
 
21
  $isBlocked = true;
22
 
24
  $mod = $this->getMod();
25
  /** @var Databases\IPs\Update $upd */
26
  $upd = $mod->getDbHandler_IPs()->getQueryUpdater();
27
+ $upd->updateLastAccessAt( $IP );
28
  }
29
  return $isBlocked;
30
  }
src/lib/src/Modules/IPs/Lib/Bots/NotBot/InsertNotBotJs.php CHANGED
@@ -36,27 +36,17 @@ class InsertNotBotJs extends ExecOnceModConsumer {
36
  'wp-hummingbird.php',
37
  'sg-cachepress.php',
38
  'autoptimize.php',
 
39
  ]
40
  ) ) > 0
41
  );
42
  }
43
 
44
  protected function run() {
45
- $this->sendNonceCookie();
46
  $this->enqueueJS();
47
  $this->nonceJs();
48
  }
49
 
50
- protected function sendNonceCookie() {
51
- if ( $this->isForcedForOptimisationPlugins() ) {
52
- Services::Response()->cookieSet(
53
- 'shield-notbot-nonce',
54
- $this->getMod()->getAjaxActionData( 'not_bot' )[ 'exec_nonce' ],
55
- 15
56
- );
57
- }
58
- }
59
-
60
  protected function enqueueJS() {
61
  add_filter( 'shield/custom_enqueues', function ( array $enqueues ) {
62
  $enqueues[ Enqueue::JS ][] = 'shield/notbot';
36
  'wp-hummingbird.php',
37
  'sg-cachepress.php',
38
  'autoptimize.php',
39
+ 'wp-optimize.php',
40
  ]
41
  ) ) > 0
42
  );
43
  }
44
 
45
  protected function run() {
 
46
  $this->enqueueJS();
47
  $this->nonceJs();
48
  }
49
 
 
 
 
 
 
 
 
 
 
 
50
  protected function enqueueJS() {
51
  add_filter( 'shield/custom_enqueues', function ( array $enqueues ) {
52
  $enqueues[ Enqueue::JS ][] = 'shield/notbot';
src/lib/src/Modules/IPs/Lib/Bots/NotBot/NotBotHandler.php CHANGED
@@ -25,10 +25,19 @@ class NotBotHandler extends ExecOnceModConsumer {
25
  ( new InsertNotBotJs() )
26
  ->setMod( $this->getMod() )
27
  ->execute();
 
28
  $this->registerFrontPageLoad();
29
  $this->registerLoginPageLoad();
30
  }
31
 
 
 
 
 
 
 
 
 
32
  private function registerFrontPageLoad() {
33
  add_action( $this->getCon()->prefix( 'pre_plugin_shutdown' ), function () {
34
  $req = Services::Request();
25
  ( new InsertNotBotJs() )
26
  ->setMod( $this->getMod() )
27
  ->execute();
28
+ $this->sendNotBotNonceCookie();
29
  $this->registerFrontPageLoad();
30
  $this->registerLoginPageLoad();
31
  }
32
 
33
+ protected function sendNotBotNonceCookie() {
34
+ Services::Response()->cookieSet(
35
+ 'shield-notbot-nonce',
36
+ $this->getMod()->getAjaxActionData( 'not_bot' )[ 'exec_nonce' ],
37
+ 15
38
+ );
39
+ }
40
+
41
  private function registerFrontPageLoad() {
42
  add_action( $this->getCon()->prefix( 'pre_plugin_shutdown' ), function () {
43
  $req = Services::Request();
src/lib/src/Modules/IPs/Lib/IpAnalyse/BuildDisplay.php CHANGED
@@ -6,6 +6,8 @@ use FernleafSystems\Wordpress\Plugin\Shield\Databases;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\DB\LoadLogs;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\DB\Logs;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\Lib\AuditMessageBuilder;
 
 
9
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\Lib\GeoIP\Lookup;
10
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Components\IpAddressConsumer;
11
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Bots\BotSignalsRecord;
@@ -15,8 +17,6 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Ops\LookupIpOnList;
15
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\ModCon;
16
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Strings;
17
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
18
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\DB\IPs\IPRecords;
19
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\DB\ReqLogs;
20
  use FernleafSystems\Wordpress\Plugin\Shield\ShieldNetApi\Reputation\GetIPReputation;
21
  use FernleafSystems\Wordpress\Services\Services;
22
  use FernleafSystems\Wordpress\Services\Utilities\Net\IpID;
@@ -181,7 +181,7 @@ class BuildDisplay {
181
  'status' => [
182
  'is_you' => Services::IP()->checkIp( $ip, Services::IP()->getRequestIp() ),
183
  'offenses' => !empty( $blockIP ) ? $blockIP->transgressions : 0,
184
- 'is_blocked' => !empty( $blockIP ) ? $blockIP->blocked_at > 0 : false,
185
  'is_bypass' => !empty( $bypassIP ),
186
  'ip_reputation_score' => $botScore,
187
  'snapi_reputation_score' => is_numeric( $shieldNetScore ) ? $shieldNetScore : 'Unavailable',
@@ -210,6 +210,7 @@ class BuildDisplay {
210
  }
211
 
212
  private function renderForSessions() :string {
 
213
  /** @var Databases\Session\Select $sel */
214
  $sel = $this->getCon()
215
  ->getModule_Sessions()
@@ -221,8 +222,10 @@ class BuildDisplay {
221
 
222
  foreach ( $sessions as $key => $session ) {
223
  $asArray = $session->getRawData();
224
- $asArray[ 'logged_in_at' ] = $this->formatTimestampField( (int)$session->logged_in_at );
225
- $asArray[ 'last_activity_at' ] = $this->formatTimestampField( (int)$session->last_activity_at );
 
 
226
  $asArray[ 'is_sec_admin' ] = $session->secadmin_at > 0;
227
  $sessions[ $key ] = $asArray;
228
  }
@@ -248,6 +251,7 @@ class BuildDisplay {
248
  }
249
 
250
  private function renderForTraffic() :string {
 
251
  try {
252
  $ip = ( new IPRecords() )
253
  ->setMod( $this->getCon()->getModule_Data() )
@@ -266,11 +270,12 @@ class BuildDisplay {
266
 
267
  foreach ( $requests as $key => $req ) {
268
  $asArray = $req->getRawData();
269
- $asArray[ 'created_at' ] = $this->formatTimestampField( (int)$req->created_at );
 
270
 
271
  $asArray = array_merge(
272
  [
273
- 'path' => '',
274
  'code' => '-',
275
  'verb' => '-',
276
  'query' => '',
@@ -279,11 +284,11 @@ class BuildDisplay {
279
  $asArray,
280
  $req->meta
281
  );
282
- if ( strpos( $asArray[ 'path' ], '?' ) === false ) {
283
- $asArray[ 'path' ] .= '?';
284
- }
285
 
286
- list( $asArray[ 'path' ], $asArray[ 'query' ] ) = array_map( 'esc_js', explode( '?', $asArray[ 'path' ], 2 ) );
 
 
 
287
  $asArray[ 'trans' ] = (bool)$asArray[ 'offense' ];
288
 
289
  if ( empty( $asArray[ 'path' ] ) ) {
@@ -389,6 +394,7 @@ class BuildDisplay {
389
  }
390
 
391
  private function renderForAuditTrail() :string {
 
392
  // TODO: IP Filtering at the SQL query level
393
  $logRecords = ( new LoadLogs() )
394
  ->setMod( $this->getCon()->getModule_AuditTrail() )
@@ -402,7 +408,8 @@ class BuildDisplay {
402
  $asArray = $record->getRawData();
403
 
404
  $asArray[ 'event' ] = implode( ' ', AuditMessageBuilder::BuildFromLogRecord( $record ) );
405
- $asArray[ 'created_at' ] = $this->formatTimestampField( $record->created_at );
 
406
 
407
  $user = empty( $record->meta_data[ 'uid' ] ) ? null
408
  : Services::WpUsers()->getUserById( $record->meta_data[ 'uid' ] );
@@ -431,17 +438,10 @@ class BuildDisplay {
431
  );
432
  }
433
 
434
- /**
435
- * copied from Table Builder
436
- * @param int $nTimestamp
437
- * @return string
438
- */
439
- protected function formatTimestampField( int $nTimestamp ) {
440
  return Services::Request()
441
  ->carbon()
442
- ->setTimestamp( $nTimestamp )
443
- ->diffForHumans()
444
- .'<br/><span class="timestamp-small">'
445
- .Services::WpGeneral()->getTimeStringForDisplay( $nTimestamp ).'</span>';
446
  }
447
  }
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\DB\LoadLogs;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\DB\Logs;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\Lib\AuditMessageBuilder;
9
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\DB\IPs\IPRecords;
10
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\DB\ReqLogs;
11
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\Lib\GeoIP\Lookup;
12
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Components\IpAddressConsumer;
13
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Bots\BotSignalsRecord;
17
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\ModCon;
18
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Strings;
19
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
 
 
20
  use FernleafSystems\Wordpress\Plugin\Shield\ShieldNetApi\Reputation\GetIPReputation;
21
  use FernleafSystems\Wordpress\Services\Services;
22
  use FernleafSystems\Wordpress\Services\Utilities\Net\IpID;
181
  'status' => [
182
  'is_you' => Services::IP()->checkIp( $ip, Services::IP()->getRequestIp() ),
183
  'offenses' => !empty( $blockIP ) ? $blockIP->transgressions : 0,
184
+ 'is_blocked' => !empty( $blockIP ) && $blockIP->blocked_at > 0,
185
  'is_bypass' => !empty( $bypassIP ),
186
  'ip_reputation_score' => $botScore,
187
  'snapi_reputation_score' => is_numeric( $shieldNetScore ) ? $shieldNetScore : 'Unavailable',
210
  }
211
 
212
  private function renderForSessions() :string {
213
+ $WP = Services::WpGeneral();
214
  /** @var Databases\Session\Select $sel */
215
  $sel = $this->getCon()
216
  ->getModule_Sessions()
222
 
223
  foreach ( $sessions as $key => $session ) {
224
  $asArray = $session->getRawData();
225
+ $asArray[ 'logged_in_at' ] = $WP->getTimeStringForDisplay( $session->logged_in_at );
226
+ $asArray[ 'logged_in_at_ago' ] = $this->getTimeAgo( $session->logged_in_at );
227
+ $asArray[ 'last_activity_at' ] = $WP->getTimeStringForDisplay( $session->last_activity_at );
228
+ $asArray[ 'last_activity_at_ago' ] = $this->getTimeAgo( $session->last_activity_at );
229
  $asArray[ 'is_sec_admin' ] = $session->secadmin_at > 0;
230
  $sessions[ $key ] = $asArray;
231
  }
251
  }
252
 
253
  private function renderForTraffic() :string {
254
+ $WP = Services::WpGeneral();
255
  try {
256
  $ip = ( new IPRecords() )
257
  ->setMod( $this->getCon()->getModule_Data() )
270
 
271
  foreach ( $requests as $key => $req ) {
272
  $asArray = $req->getRawData();
273
+ $asArray[ 'created_at' ] = $WP->getTimeStringForDisplay( $req->created_at );
274
+ $asArray[ 'created_at_ago' ] = $this->getTimeAgo( $req->created_at );
275
 
276
  $asArray = array_merge(
277
  [
278
+ 'path' => $req->path,
279
  'code' => '-',
280
  'verb' => '-',
281
  'query' => '',
284
  $asArray,
285
  $req->meta
286
  );
 
 
 
287
 
288
+ if ( empty( $asArray[ 'code' ] ) ) {
289
+ $asArray[ 'code' ] = '-';
290
+ }
291
+ $asArray[ 'query' ] = esc_js( $asArray[ 'query' ] );
292
  $asArray[ 'trans' ] = (bool)$asArray[ 'offense' ];
293
 
294
  if ( empty( $asArray[ 'path' ] ) ) {
394
  }
395
 
396
  private function renderForAuditTrail() :string {
397
+ $WP = Services::WpGeneral();
398
  // TODO: IP Filtering at the SQL query level
399
  $logRecords = ( new LoadLogs() )
400
  ->setMod( $this->getCon()->getModule_AuditTrail() )
408
  $asArray = $record->getRawData();
409
 
410
  $asArray[ 'event' ] = implode( ' ', AuditMessageBuilder::BuildFromLogRecord( $record ) );
411
+ $asArray[ 'created_at' ] = $WP->getTimeStringForDisplay( $record->created_at );
412
+ $asArray[ 'created_at_ago' ] = $this->getTimeAgo( $record->created_at );
413
 
414
  $user = empty( $record->meta_data[ 'uid' ] ) ? null
415
  : Services::WpUsers()->getUserById( $record->meta_data[ 'uid' ] );
438
  );
439
  }
440
 
441
+ protected function getTimeAgo( int $ts ) :string {
 
 
 
 
 
442
  return Services::Request()
443
  ->carbon()
444
+ ->setTimestamp( $ts )
445
+ ->diffForHumans();
 
 
446
  }
447
  }
src/lib/src/Modules/IPs/Lib/Ops/RetrieveIpsForLists.php CHANGED
@@ -1,9 +1,10 @@
1
- <?php
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Ops;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base\HandlerConsumer;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\IPs;
 
7
  use FernleafSystems\Wordpress\Plugin\Shield\Utilities\Tool\IpListSort;
8
 
9
  class RetrieveIpsForLists {
@@ -13,56 +14,55 @@ class RetrieveIpsForLists {
13
  /**
14
  * @return string[]
15
  */
16
- public function all() {
17
- return $this->forLists( [] );
18
  }
19
 
20
  /**
21
  * @return string[]
22
  */
23
- public function white() {
24
- return $this->forLists( [ 'MW' ] );
25
  }
26
 
27
  /**
28
  * @return string[]
29
  */
30
- public function black() {
31
- return $this->forLists( [ 'AB', 'MB' ] );
32
  }
33
 
34
  /**
35
  * @return string[]
36
  */
37
- public function blackAuto() {
38
- return $this->forLists( [ 'AB' ] );
39
  }
40
 
41
  /**
42
  * @return string[]
43
  */
44
- public function blackManual() {
45
- return $this->forLists( [ 'MB' ] );
46
  }
47
 
48
  /**
49
- * @param string[] $aLists
50
  * @return string[]
51
  */
52
- private function forLists( $aLists ) {
53
- $aResult = [];
54
- /** @var IPs\Select $oSel */
55
- $oSel = $this->getDbHandler()
56
- ->getQuerySelector()
57
- ->addColumnToSelect( 'ip' )
58
- ->setIsDistinct( true );
59
- if ( !empty( $aLists ) ) {
60
- $oSel->filterByLists( $aLists );
61
  }
62
- $aDistinct = $oSel->query();
63
- if ( is_array( $aDistinct ) ) {
64
- $aResult = IpListSort::Sort( $aDistinct );
65
  }
66
- return $aResult;
67
  }
68
  }
1
+ <?php declare( strict_types=1 );
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Ops;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base\HandlerConsumer;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\IPs;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\ModCon;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Utilities\Tool\IpListSort;
9
 
10
  class RetrieveIpsForLists {
14
  /**
15
  * @return string[]
16
  */
17
+ public function all() :array {
18
+ return $this->forLists();
19
  }
20
 
21
  /**
22
  * @return string[]
23
  */
24
+ public function white() :array {
25
+ return $this->forLists( [ ModCon::LIST_MANUAL_WHITE ] );
26
  }
27
 
28
  /**
29
  * @return string[]
30
  */
31
+ public function black() :array {
32
+ return $this->forLists( [ ModCon::LIST_AUTO_BLACK, ModCon::LIST_MANUAL_BLACK ] );
33
  }
34
 
35
  /**
36
  * @return string[]
37
  */
38
+ public function blackAuto() :array {
39
+ return $this->forLists( [ ModCon::LIST_AUTO_BLACK ] );
40
  }
41
 
42
  /**
43
  * @return string[]
44
  */
45
+ public function blackManual() :array {
46
+ return $this->forLists( [ ModCon::LIST_MANUAL_BLACK ] );
47
  }
48
 
49
  /**
 
50
  * @return string[]
51
  */
52
+ private function forLists( array $lists = [] ) :array {
53
+ $result = [];
54
+ /** @var IPs\Select $selector */
55
+ $selector = $this->getDbHandler()
56
+ ->getQuerySelector()
57
+ ->addColumnToSelect( 'ip' )
58
+ ->setIsDistinct( true );
59
+ if ( !empty( $lists ) ) {
60
+ $selector->filterByLists( $lists );
61
  }
62
+ $distinct = $selector->query();
63
+ if ( is_array( $distinct ) ) {
64
+ $result = IpListSort::Sort( $distinct );
65
  }
66
+ return $result;
67
  }
68
  }
src/lib/src/Modules/IPs/Processor.php CHANGED
@@ -2,6 +2,10 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
4
 
 
 
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
6
 
7
  class Processor extends BaseShield\Processor {
@@ -12,4 +16,53 @@ class Processor extends BaseShield\Processor {
12
  $mod->getBlacklistHandler()->execute();
13
  $mod->getBotSignalsController()->execute();
14
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  }
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Databases\IPs\{
6
+ EntryVO,
7
+ Select
8
+ };
9
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
10
 
11
  class Processor extends BaseShield\Processor {
16
  $mod->getBlacklistHandler()->execute();
17
  $mod->getBotSignalsController()->execute();
18
  }
19
+
20
+ public function addAdminBarMenuGroup( array $groups ) :array {
21
+ /** @var ModCon $mod */
22
+ $mod = $this->getMod();
23
+ $modInsights = $this->getCon()->getModule_Insights();
24
+ /** @var Select $sel */
25
+ $sel = $mod->getDbHandler_IPs()->getQuerySelector();
26
+ /** @var EntryVO[] $IPs */
27
+ $IPs = $sel->filterByBlocked( true )
28
+ ->setOrderBy( 'blocked_at' )
29
+ ->setLimit( 10 )
30
+ ->query();
31
+
32
+ if ( !empty( $IPs ) ) {
33
+ $groups[] = [
34
+ 'title' => __( 'Recently Blocked IPs', 'wp-simple-firewall' ),
35
+ 'href' => $modInsights->getUrl_IPs(),
36
+ 'items' => array_map( function ( $ip ) {
37
+ return [
38
+ 'id' => $this->getCon()->prefix( 'ip-'.$ip->id ),
39
+ 'title' => $ip->ip,
40
+ 'href' => $this->getCon()->getModule_Insights()->getUrl_IpAnalysis( $ip->ip ),
41
+ ];
42
+ }, $IPs ),
43
+ ];
44
+ }
45
+
46
+ /** @var EntryVO[] $IPs */
47
+ $IPs = $sel->filterByBlocked( false )
48
+ ->filterByList( ModCon::LIST_AUTO_BLACK )
49
+ ->setOrderBy( 'last_access_at' )
50
+ ->setLimit( 10 )
51
+ ->query();
52
+ if ( !empty( $IPs ) ) {
53
+ $groups[] = [
54
+ 'title' => __( 'Recent Offenses', 'wp-simple-firewall' ),
55
+ 'href' => $modInsights->getUrl_IPs(),
56
+ 'items' => array_map( function ( $ip ) {
57
+ return [
58
+ 'id' => $this->getCon()->prefix( 'ip-'.$ip->id ),
59
+ 'title' => $ip->ip,
60
+ 'href' => $this->getCon()->getModule_Insights()->getUrl_IpAnalysis( $ip->ip ),
61
+ ];
62
+ }, $IPs ),
63
+ ];
64
+ }
65
+
66
+ return $groups;
67
+ }
68
  }
src/lib/src/Modules/IPs/Rest.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Rest\Route\IPs\GetIP;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Rest\Route\Lists\{
7
+ AddIP,
8
+ GetList,
9
+ GetListIP
10
+ };
11
+
12
+ class Rest extends \FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Rest {
13
+
14
+ protected function enumRoutes() :array {
15
+ return [
16
+ 'ips_get' => GetIP::class,
17
+ 'lists_get' => GetList::class,
18
+ 'lists_getip' => GetListIP::class,
19
+ 'lists_addip' => AddIP::class,
20
+ ];
21
+ }
22
+ }
src/lib/src/Modules/IPs/Rest/Exceptions/NotIpAddressException.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Rest\Exceptions;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Core\Rest\Exceptions\InvalidRequestParametersException;
6
+
7
+ class NotIpAddressException extends InvalidRequestParametersException {
8
+
9
+ }
src/lib/src/Modules/IPs/Rest/Request/IPs/Base.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Rest\Request\IPs;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Rest\Request\Process;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Ops\LookupIpOnList;
7
+
8
+ abstract class Base extends Process {
9
+
10
+ protected function getIpData( string $ip, string $list ) :array {
11
+ /** @var \FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\ModCon $mod */
12
+ $mod = $this->getMod();
13
+
14
+ $retriever = ( new LookupIpOnList() )
15
+ ->setDbHandler( $mod->getDbHandler_IPs() )
16
+ ->setIP( $ip );
17
+ if ( $list === 'block' ) {
18
+ $retriever->setListTypeBlock();
19
+ }
20
+ else {
21
+ $retriever->setListTypeBypass();
22
+ }
23
+
24
+ $IP = $retriever->lookup( true );
25
+
26
+ if ( empty( $IP ) ) {
27
+ throw new \Exception( 'IP address not found on list' );
28
+ }
29
+
30
+ return array_intersect_key(
31
+ $IP->getRawData(),
32
+ array_flip( [
33
+ 'ip',
34
+ 'label',
35
+ 'list',
36
+ 'transgressions',
37
+ 'blocked_at',
38
+ ] )
39
+ );
40
+ }
41
+ }
src/lib/src/Modules/IPs/Rest/Request/IPs/GetIP.php ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Rest\Request\IPs;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Bots\BotSignalsRecord;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Bots\Calculator\CalculateVisitorBotScores;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Ops\LookupIpOnList;
8
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\ModCon;
9
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Strings;
10
+ use FernleafSystems\Wordpress\Plugin\Shield\ShieldNetApi\Reputation\GetIPReputation;
11
+ use FernleafSystems\Wordpress\Services\Services;
12
+
13
+ class GetIP extends Base {
14
+
15
+ protected function process() :array {
16
+ return [
17
+ 'ip_list' => $this->getIpListInfo(),
18
+ 'not_bot' => $this->getNotBotInfo(),
19
+ ];
20
+ }
21
+
22
+ private function getNotBotInfo() :array {
23
+ /** @var RequestVO $req */
24
+ $req = $this->getRequestVO();
25
+ /** @var Strings $strings */
26
+ $strings = $this->getMod()->getStrings();
27
+ $names = $strings->getBotSignalNames();
28
+
29
+ $signals = [];
30
+ $scoreCalc = ( new CalculateVisitorBotScores() )
31
+ ->setMod( $this->getMod() )
32
+ ->setIP( $req->ip );
33
+ $scores = $scoreCalc->scores();
34
+ try {
35
+ $record = ( new BotSignalsRecord() )
36
+ ->setMod( $this->getMod() )
37
+ ->setIP( $req->ip )
38
+ ->retrieve();
39
+ }
40
+ catch ( \Exception $e ) {
41
+ $record = null;
42
+ $signals = [];
43
+ }
44
+
45
+ foreach ( $scores as $scoreKey => $scoreValue ) {
46
+ $column = $scoreKey.'_at';
47
+ if ( $scoreValue !== 0 ) {
48
+ if ( empty( $record ) || empty( $record->{$column} ) ) {
49
+ if ( in_array( $scoreKey, [ 'known', 'created' ] ) ) {
50
+ $signals[ $scoreKey ] = __( 'N/A', 'wp-simple-firewall' );
51
+ }
52
+ else {
53
+ $signals[ $scoreKey ] = __( 'Never Recorded', 'wp-simple-firewall' );
54
+ }
55
+ }
56
+ else {
57
+ $signals[ $scoreKey ] = Services::Request()
58
+ ->carbon()
59
+ ->setTimestamp( $record->{$column} )->diffForHumans();
60
+ }
61
+ }
62
+ }
63
+
64
+ $signalsAsHuman = [];
65
+ foreach ( $signals as $signal => $signalTime ) {
66
+ $signalsAsHuman[ $names[ $signal ] ] = $signalTime;
67
+ }
68
+ ksort( $signalsAsHuman );
69
+
70
+ return [
71
+ 'human_probability' => $scoreCalc->probability(),
72
+ 'score_local' => $scoreCalc->total(),
73
+ 'score_shieldnet' => ( new GetIPReputation() )
74
+ ->setMod( $this->getCon()->getModule_Plugin() )
75
+ ->setIP( $req->ip )
76
+ ->retrieve()[ 'reputation_score' ] ?? '-',
77
+ 'signals' => $signalsAsHuman,
78
+ ];
79
+ }
80
+
81
+ private function getIpListInfo() :array {
82
+ /** @var ModCon $mod */
83
+ $mod = $this->getMod();
84
+ /** @var RequestVO $req */
85
+ $req = $this->getRequestVO();
86
+
87
+ $ip = ( new LookupIpOnList() )
88
+ ->setDbHandler( $mod->getDbHandler_IPs() )
89
+ ->setIP( $req->ip )
90
+ ->lookup();
91
+
92
+ $info = [];
93
+ if ( !empty( $ip ) ) {
94
+ $info = [
95
+ 'list' => $ip->list === 'AB' ? 'auto-block' :
96
+ ( $ip->list === 'MB' ? 'manual-block' : 'bypass' ),
97
+ 'offenses' => (int)$ip->transgressions,
98
+ 'label' => $ip->label,
99
+ 'blocked_at' => $ip->blocked_at,
100
+ 'last_access_at' => $ip->blocked_at,
101
+ ];
102
+ }
103
+
104
+ return $info;
105
+ }
106
+ }
src/lib/src/Modules/IPs/Rest/Request/IPs/RequestVO.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Rest\Request\IPs;
4
+
5
+ /**
6
+ * @property string $ip
7
+ */
8
+ class RequestVO extends \FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Rest\Request\RequestVO {
9
+
10
+ }
src/lib/src/Modules/IPs/Rest/Request/Lists/AddIP.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Rest\Request\Lists;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\ModCon;
7
+
8
+ class AddIP extends Base {
9
+
10
+ protected function process() :array {
11
+ /** @var ModCon $mod */
12
+ $mod = $this->getMod();
13
+ $req = $this->getRequestVO();
14
+
15
+ $adder = ( new Lib\Ops\AddIp() )
16
+ ->setMod( $mod )
17
+ ->setIP( $req->ip );
18
+ if ( $req->list === 'block' ) {
19
+ $IP = $adder->toManualBlacklist( $req->label );
20
+ }
21
+ elseif ( $req->list === 'bypass' ) {
22
+ $IP = $adder->toManualWhitelist( $req->label );
23
+ }
24
+
25
+ if ( empty( $IP ) ) {
26
+ throw new \Exception( 'There was an error adding IP address to list.' );
27
+ }
28
+
29
+ return [
30
+ 'ip' => $this->getIpData( $req->ip, $req->list )
31
+ ];
32
+ }
33
+ }
src/lib/src/Modules/IPs/Rest/Request/Lists/Base.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Rest\Request\Lists;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Rest\Request\Process;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Ops\LookupIpOnList;
7
+
8
+ abstract class Base extends Process {
9
+
10
+ protected function getIpData( string $ip, string $list ) :array {
11
+ /** @var \FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\ModCon $mod */
12
+ $mod = $this->getMod();
13
+
14
+ $retriever = ( new LookupIpOnList() )
15
+ ->setDbHandler( $mod->getDbHandler_IPs() )
16
+ ->setIP( $ip );
17
+ if ( $list === 'block' ) {
18
+ $retriever->setListTypeBlock();
19
+ }
20
+ else {
21
+ $retriever->setListTypeBypass();
22
+ }
23
+
24
+ $IP = $retriever->lookup( true );
25
+
26
+ if ( empty( $IP ) ) {
27
+ throw new \Exception( 'IP address not found on list' );
28
+ }
29
+
30
+ return array_intersect_key(
31
+ $IP->getRawData(),
32
+ array_flip( [
33
+ 'ip',
34
+ 'label',
35
+ 'list',
36
+ 'transgressions',
37
+ 'blocked_at',
38
+ ] )
39
+ );
40
+ }
41
+ }
src/lib/src/Modules/IPs/Rest/Request/Lists/GetList.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Rest\Request\Lists;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Ops\RetrieveIpsForLists;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\ModCon;
7
+
8
+ class GetList extends Base {
9
+
10
+ protected function process() :array {
11
+ /** @var ModCon $mod */
12
+ $mod = $this->getMod();
13
+ $req = $this->getRequestVO();
14
+
15
+ $retriever = ( new RetrieveIpsForLists() )
16
+ ->setDbHandler( $mod->getDbHandler_IPs() );
17
+ if ( $req->list === 'block' ) {
18
+ $list = $retriever->black();
19
+ }
20
+ else {
21
+ $list = $retriever->white();
22
+ }
23
+
24
+ return $list;
25
+ }
26
+ }
src/lib/src/Modules/IPs/Rest/Request/Lists/GetListIP.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Rest\Request\Lists;
4
+
5
+ class GetListIP extends Base {
6
+
7
+ protected function process() :array {
8
+ $req = $this->getRequestVO();
9
+ return [
10
+ 'ip' => $this->getIpData( $req->ip, $req->list )
11
+ ];
12
+ }
13
+ }
src/lib/src/Modules/IPs/Rest/Route/Base.php ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Rest\Route;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Rest\Route\RouteBase;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Rest\{
7
+ Exceptions};
8
+ use FernleafSystems\Wordpress\Services\Services;
9
+
10
+ abstract class Base extends RouteBase {
11
+
12
+ protected function customValidateRequestArg( $value, \WP_REST_Request $request, string $reqArgKey ) {
13
+
14
+ switch ( $reqArgKey ) {
15
+
16
+ case 'ip':
17
+ $srvIP = Services::IP();
18
+ if ( $srvIP->isValidIpRange( $value ) && !$srvIP->isValidIp_PublicRange( $value ) ) {
19
+ throw new Exceptions\NotIpAddressException( 'Not a public IP range' );
20
+ }
21
+ elseif ( !$srvIP->isValidIp_PublicRemote( $value ) ) {
22
+ throw new Exceptions\NotIpAddressException( 'Not a public IP address' );
23
+ }
24
+ break;
25
+
26
+ default:
27
+ return parent::customValidateRequestArg( $value, $request, $reqArgKey );
28
+ }
29
+
30
+ return true;
31
+ }
32
+
33
+ protected function getRouteArgSchema( string $key ) :array {
34
+ switch ( $key ) {
35
+ case 'ip':
36
+ $sch = [
37
+ 'description' => 'IP Address',
38
+ 'type' => 'string',
39
+ 'format' => 'ip',
40
+ 'required' => true,
41
+ ];
42
+ break;
43
+
44
+ default:
45
+ $sch = parent::getRouteArgSchema( $key );
46
+ break;
47
+ }
48
+ return $sch;
49
+ }
50
+ }
src/lib/src/Modules/IPs/Rest/Route/IPs/GetIP.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Rest\Route\IPs;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Rest\Request\IPs;
6
+
7
+ class GetIP extends IPsBase {
8
+
9
+ protected function getRouteArgsCustom() :array {
10
+ return [
11
+ 'ip' => $this->getRouteArgSchema( 'ip' ),
12
+ ];
13
+ }
14
+
15
+ protected function getRequestProcessorClass() :string {
16
+ return IPs\GetIP::class;
17
+ }
18
+
19
+ public function getRoutePath() :string {
20
+ return '/(?P<ip>[0-9a-f\.:]{3,})';
21
+ }
22
+ }
src/lib/src/Modules/IPs/Rest/Route/IPs/IPsBase.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Rest\Route\IPs;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Rest\Route\Base;
6
+
7
+ abstract class IPsBase extends Base {
8
+
9
+ public function getRoutePathPrefix() :string {
10
+ return '/ips';
11
+ }
12
+
13
+ protected function getRouteArgSchema( string $key ) :array {
14
+ switch ( $key ) {
15
+
16
+ default:
17
+ $sch = parent::getRouteArgSchema( $key );
18
+ break;
19
+ }
20
+ return $sch;
21
+ }
22
+ }
src/lib/src/Modules/IPs/Rest/Route/Lists/AddIP.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Rest\Route\Lists;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Rest\Request\Lists;
6
+
7
+ class AddIP extends ListsBase {
8
+
9
+ const ROUTE_METHOD = \WP_REST_Server::EDITABLE;
10
+
11
+ protected function getRouteArgsCustom() :array {
12
+ return [
13
+ 'ip' => $this->getRouteArgSchema( 'ip' ),
14
+ 'list' => $this->getRouteArgSchema( 'list' ),
15
+ 'label' => [
16
+ 'description' => 'The label to assign to the IP address.',
17
+ 'type' => 'string',
18
+ 'required' => true,
19
+ ],
20
+ ];
21
+ }
22
+
23
+ protected function getRequestProcessorClass() :string {
24
+ return Lists\AddIP::class;
25
+ }
26
+
27
+ public function getRoutePath() :string {
28
+ return '/(?P<list>bypass|block)/(?P<ip>[0-9a-f\.:]{3,})';
29
+ }
30
+ }
src/lib/src/Modules/IPs/Rest/Route/Lists/GetList.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Rest\Route\Lists;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Rest\Request\Lists;
6
+
7
+ class GetList extends ListsBase {
8
+
9
+ protected function getRouteArgsCustom() :array {
10
+ return [
11
+ 'list' => $this->getRouteArgSchema( 'list' ),
12
+ ];
13
+ }
14
+
15
+ protected function getRequestProcessorClass() :string {
16
+ return Lists\GetList::class;
17
+ }
18
+
19
+ public function getRoutePath() :string {
20
+ return '/(?P<list>bypass|block)';
21
+ }
22
+ }
src/lib/src/Modules/IPs/Rest/Route/Lists/GetListIP.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Rest\Route\Lists;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Rest\Request\Lists;
6
+
7
+ class GetListIP extends ListsBase {
8
+
9
+ public function getRoutePath() :string {
10
+ return '/(?P<list>bypass|block)/(?P<ip>[0-9a-f\.:]{3,})';
11
+ }
12
+
13
+ protected function getRouteArgsCustom() :array {
14
+ return [
15
+ 'ip' => $this->getRouteArgSchema( 'ip' ),
16
+ 'list' => $this->getRouteArgSchema( 'list' ),
17
+ ];
18
+ }
19
+
20
+ protected function getRequestProcessorClass() :string {
21
+ return Lists\GetListIP::class;
22
+ }
23
+ }
src/lib/src/Modules/IPs/Rest/Route/Lists/ListsBase.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Rest\Route\Lists;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Rest\Route\Base;
6
+
7
+ abstract class ListsBase extends Base {
8
+
9
+ public function getRoutePathPrefix() :string {
10
+ return '/ip_lists';
11
+ }
12
+
13
+ protected function getRouteArgSchema( string $key ) :array {
14
+ switch ( $key ) {
15
+
16
+ case 'list':
17
+ $sch = [
18
+ 'description' => 'The IP list name: either block (black) or bypass (white).',
19
+ 'type' => 'string',
20
+ 'enum' => [
21
+ 'bypass',
22
+ 'block',
23
+ ],
24
+ 'required' => true,
25
+ ];
26
+ break;
27
+
28
+ default:
29
+ $sch = parent::getRouteArgSchema( $key );
30
+ break;
31
+ }
32
+ return $sch;
33
+ }
34
+ }
src/lib/src/Modules/IPs/Strings.php CHANGED
@@ -438,7 +438,7 @@ class Strings extends Base\Strings {
438
  return [
439
  'created' => __( 'New Visitor Bonus', 'wp-simple-firewall' ),
440
  'known' => __( 'A Known Service Provider/Bot', 'wp-simple-firewall' ),
441
- 'notbot' => __( '"Not Bot" Registration', 'wp-simple-firewall' ),
442
  'frontpage' => __( 'Any Frontend Page Visited', 'wp-simple-firewall' ),
443
  'loginpage' => __( 'Login Page Visited', 'wp-simple-firewall' ),
444
  'bt404' => __( '404 Triggered', 'wp-simple-firewall' ),
438
  return [
439
  'created' => __( 'New Visitor Bonus', 'wp-simple-firewall' ),
440
  'known' => __( 'A Known Service Provider/Bot', 'wp-simple-firewall' ),
441
+ 'notbot' => __( 'Not Bot Registration', 'wp-simple-firewall' ),
442
  'frontpage' => __( 'Any Frontend Page Visited', 'wp-simple-firewall' ),
443
  'loginpage' => __( 'Login Page Visited', 'wp-simple-firewall' ),
444
  'bt404' => __( '404 Triggered', 'wp-simple-firewall' ),
src/lib/src/Modules/Insights/ModCon.php CHANGED
@@ -33,7 +33,11 @@ class ModCon extends BaseShield\ModCon {
33
  }
34
 
35
  public function getUrl_IpAnalysis( string $ip ) :string {
36
- return add_query_arg( [ 'analyse_ip' => $ip ], $this->getUrl_SubInsightsPage( 'ips' ) );
 
 
 
 
37
  }
38
 
39
  public function getUrl_ScansResults() :string {
@@ -44,6 +48,10 @@ class ModCon extends BaseShield\ModCon {
44
  return $this->getUrl_SubInsightsPage( 'scans_run' );
45
  }
46
 
 
 
 
 
47
  public function getUrl_SubInsightsPage( string $subPage ) :string {
48
  return add_query_arg(
49
  [ 'inav' => sanitize_key( $subPage ) ],
33
  }
34
 
35
  public function getUrl_IpAnalysis( string $ip ) :string {
36
+ return add_query_arg( [ 'analyse_ip' => $ip ], $this->getUrl_IPs() );
37
+ }
38
+
39
+ public function getUrl_IPs() :string {
40
+ return $this->getUrl_SubInsightsPage( 'ips' );
41
  }
42
 
43
  public function getUrl_ScansResults() :string {
48
  return $this->getUrl_SubInsightsPage( 'scans_run' );
49
  }
50
 
51
+ public function getUrl_Sessions() :string {
52
+ return $this->getUrl_SubInsightsPage( 'users' );
53
+ }
54
+
55
  public function getUrl_SubInsightsPage( string $subPage ) :string {
56
  return add_query_arg(
57
  [ 'inav' => sanitize_key( $subPage ) ],
src/lib/src/Modules/License/AjaxHandler.php CHANGED
@@ -25,37 +25,28 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
25
  return $response;
26
  }
27
 
28
- /**
29
- * @return array
30
- */
31
- private function ajaxExec_ConnectionDebug() {
32
- $oIP = Services::IP();
33
 
34
- $oPing = new Keyless\Ping();
35
- $oPing->lookup_url_stub = $this->getOptions()->getDef( 'license_store_url_api' );
36
- $bSuccess = $oPing->ping();
37
 
38
- $sHost = wp_parse_url( $oPing->lookup_url_stub, PHP_URL_HOST );
39
-
40
- if ( $bSuccess ) {
41
- $sMessage = 'Successfully connected to license server.';
42
  }
43
- elseif ( !$oIP->isValidIp( gethostbyname( $sHost ) ) ) {
44
- $sMessage = sprintf( 'Could not resolve host IP address: %s', $sHost );
45
  }
46
  else {
47
- $sMessage = 'Failed to connect to license server.';
48
  }
 
49
  return [
50
- 'success' => $bSuccess,
51
- 'message' => $sMessage
52
  ];
53
  }
54
 
55
- /**
56
- * @return array
57
- */
58
- private function ajaxExec_LicenseHandling() {
59
  /** @var ModCon $mod */
60
  $mod = $this->getMod();
61
  $licHandler = $mod->getLicenseHandler();
25
  return $response;
26
  }
27
 
28
+ private function ajaxExec_ConnectionDebug() :array {
 
 
 
 
29
 
30
+ $success = ( new Keyless\Ping() )->ping();
31
+ $host = wp_parse_url( Keyless\Base::DEFAULT_URL_STUB, PHP_URL_HOST );
 
32
 
33
+ if ( $success ) {
34
+ $msg = 'Successfully connected to license server.';
 
 
35
  }
36
+ elseif ( !Services::IP()->isValidIp( gethostbyname( $host ) ) ) {
37
+ $msg = sprintf( 'Could not resolve host IP address: %s', $host );
38
  }
39
  else {
40
+ $msg = 'Failed to connect to license server.';
41
  }
42
+
43
  return [
44
+ 'success' => $success,
45
+ 'message' => $msg
46
  ];
47
  }
48
 
49
+ private function ajaxExec_LicenseHandling() :array {
 
 
 
50
  /** @var ModCon $mod */
51
  $mod = $this->getMod();
52
  $licHandler = $mod->getLicenseHandler();
src/lib/src/Modules/License/Lib/LookupRequest.php CHANGED
@@ -17,7 +17,6 @@ class LookupRequest {
17
  $opts = $this->getOptions();
18
 
19
  $lookup = new Lookup();
20
- $lookup->lookup_url_stub = $opts->getDef( 'license_store_url_api' );
21
  $lookup->item_id = $opts->getDef( 'license_item_id' );
22
  $lookup->install_id = $con->getSiteInstallationId();
23
  $lookup->url = Services::WpGeneral()->getHomeUrl( '', true );
17
  $opts = $this->getOptions();
18
 
19
  $lookup = new Lookup();
 
20
  $lookup->item_id = $opts->getDef( 'license_item_id' );
21
  $lookup->install_id = $con->getSiteInstallationId();
22
  $lookup->url = Services::WpGeneral()->getHomeUrl( '', true );
src/lib/src/Modules/License/Rest.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\License;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\License\Rest\Route\{
6
+ LicenseCheck,
7
+ LicenseStatus
8
+ };
9
+
10
+ class Rest extends \FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Rest {
11
+
12
+ protected function enumRoutes() :array {
13
+ return [
14
+ 'license_check' => LicenseCheck::class,
15
+ 'license_status' => LicenseStatus::class,
16
+ ];
17
+ }
18
+ }
src/lib/src/Modules/License/Rest/Request/Base.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\License\Rest\Request;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Rest\Request\Process;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\License\ModCon;
7
+
8
+ abstract class Base extends Process {
9
+
10
+ protected function newReqVO() {
11
+ return new RequestVO();
12
+ }
13
+
14
+ protected function getLicenseDetails() :array {
15
+ /** @var ModCon $mod */
16
+ $mod = $this->getMod();
17
+ /** @var RequestVO $req */
18
+ $req = $this->getRequestVO();
19
+ $licHandler = $mod->getLicenseHandler();
20
+
21
+ $details = [ false ];
22
+ if ( $licHandler->hasValidWorkingLicense() ) {
23
+ $lic = $licHandler->getLicense()->getRawData();
24
+ $details = [];
25
+ foreach ( array_keys( $req->filter_fields ) as $field ) {
26
+ $details[ $field ] = $lic[ $field ];
27
+ }
28
+ }
29
+
30
+ return $details;
31
+ }
32
+ }
src/lib/src/Modules/License/Rest/Request/LicenseCheck.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\License\Rest\Request;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\License\ModCon;
6
+
7
+ class LicenseCheck extends Base {
8
+
9
+ protected function process() :array {
10
+ /** @var ModCon $mod */
11
+ $mod = $this->getMod();
12
+ $mod->getLicenseHandler()->verify( true );
13
+ return $this->getLicenseDetails();
14
+ }
15
+ }
src/lib/src/Modules/License/Rest/Request/LicenseStatus.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\License\Rest\Request;
4
+
5
+ class LicenseStatus extends Base {
6
+
7
+ protected function process() :array {
8
+ return $this->getLicenseDetails();
9
+ }
10
+ }
src/lib/src/Modules/License/Rest/Request/RequestVO.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\License\Rest\Request;
4
+
5
+ class RequestVO extends \FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Rest\Request\RequestVO {
6
+
7
+ protected function getDefaultFilterFields() :array {
8
+ return [
9
+ 'license',
10
+ 'item_name',
11
+ 'url',
12
+ 'customer_email',
13
+ 'expires',
14
+ 'expires_at',
15
+ 'is_trial',
16
+ 'install_id',
17
+ 'last_verified_at',
18
+ ];
19
+ }
20
+ }
src/lib/src/Modules/License/Rest/Route/Base.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\License\Rest\Route;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Rest\Route\RouteBase;
6
+
7
+ abstract class Base extends RouteBase {
8
+
9
+ public function getRoutePath() :string {
10
+ return '/license';
11
+ }
12
+
13
+ protected function getRouteArgsDefaults() :array {
14
+ return [
15
+ 'filter_fields' => [
16
+ 'description' => '[Filter] Comma-separated fields to include.',
17
+ 'type' => 'array', // WordPress kindly converts CSV to array
18
+ 'pattern' => '^((([a-z_]+),?)+)?$',
19
+ 'required' => false,
20
+ ],
21
+ ];
22
+ }
23
+ }
src/lib/src/Modules/License/Rest/Route/LicenseCheck.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\License\Rest\Route;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\License\Rest\Request;
6
+
7
+ class LicenseCheck extends Base {
8
+
9
+ const ROUTE_METHOD = \WP_REST_Server::EDITABLE;
10
+
11
+ protected function getRequestProcessorClass() :string {
12
+ return Request\LicenseCheck::class;
13
+ }
14
+ }
src/lib/src/Modules/License/Rest/Route/LicenseStatus.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\License\Rest\Route;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\License\Rest\Request;
6
+
7
+ class LicenseStatus extends Base {
8
+
9
+ protected function getRequestProcessorClass() :string {
10
+ return Request\LicenseStatus::class;
11
+ }
12
+ }
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/MfaProfilesController.php CHANGED
@@ -148,12 +148,6 @@ class MfaProfilesController extends Shield\Modules\Base\Common\ExecOnceModConsum
148
  ->render( $attributes );
149
  }
150
 
151
- /**
152
- * @deprecated 14.0
153
- */
154
- private function addHooks() {
155
- }
156
-
157
  /**
158
  * This MUST only ever be hooked into when the User is looking at their OWN profile, so we can use "current user"
159
  * functions. Otherwise we need to be careful of mixing up users.
148
  ->render( $attributes );
149
  }
150
 
 
 
 
 
 
 
151
  /**
152
  * This MUST only ever be hooked into when the User is looking at their OWN profile, so we can use "current user"
153
  * functions. Otherwise we need to be careful of mixing up users.
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/BaseProvider.php CHANGED
@@ -75,13 +75,6 @@ abstract class BaseProvider {
75
 
76
  abstract public function isProviderEnabled() :bool;
77
 
78
- /**
79
- * @deprecated 13.1
80
- */
81
- protected function isSecretValid() :bool {
82
- return false;
83
- }
84
-
85
  /**
86
  * @return mixed
87
  */
75
 
76
  abstract public function isProviderEnabled() :bool;
77
 
 
 
 
 
 
 
 
78
  /**
79
  * @return mixed
80
  */
src/lib/src/Modules/LoginGuard/ModCon.php CHANGED
@@ -209,14 +209,6 @@ class ModCon extends BaseShield\ModCon {
209
  return $cfg;
210
  }
211
 
212
- /**
213
- * @return Lib\TwoFactor\MfaController
214
- * @deprecated 13.1
215
- */
216
- public function getLoginIntentController() {
217
- return $this->getMfaController();
218
- }
219
-
220
  public function getMfaController() :Lib\TwoFactor\MfaController {
221
  if ( !isset( $this->mfaCon ) ) {
222
  $this->mfaCon = ( new Lib\TwoFactor\MfaController() )->setMod( $this );
209
  return $cfg;
210
  }
211
 
 
 
 
 
 
 
 
 
212
  public function getMfaController() :Lib\TwoFactor\MfaController {
213
  if ( !isset( $this->mfaCon ) ) {
214
  $this->mfaCon = ( new Lib\TwoFactor\MfaController() )->setMod( $this );
src/lib/src/Modules/Plugin/Debug.php CHANGED
@@ -9,10 +9,16 @@ use FernleafSystems\Wordpress\Plugin\Shield\Tests\RunTests;
9
  class Debug extends Modules\Base\Debug {
10
 
11
  public function run() {
12
- $this->tests();
13
  die( 'finish' );
14
  }
15
 
 
 
 
 
 
 
16
  private function testbotsignals() {
17
  $r = ( new BuildData() )
18
  ->setMod( $this->getCon()->getModule_IPs() )
9
  class Debug extends Modules\Base\Debug {
10
 
11
  public function run() {
12
+ $this->dbIntegrity();
13
  die( 'finish' );
14
  }
15
 
16
+ private function dbIntegrity() {
17
+ ( new Lib\Ops\VerifyDatabaseIntegrity() )
18
+ ->setCon( $this->getCon() )
19
+ ->run();
20
+ }
21
+
22
  private function testbotsignals() {
23
  $r = ( new BuildData() )
24
  ->setMod( $this->getCon()->getModule_IPs() )
src/lib/src/Modules/Plugin/Lib/Debug/Collate.php CHANGED
@@ -223,9 +223,7 @@ class Collate {
223
  'WP Hashes Ping' => ( new ApiPing() )->ping() ? 'Yes' : 'No',
224
  ];
225
 
226
- $licPing = new Licenses\Keyless\Ping();
227
- $licPing->lookup_url_stub = $con->getModule_License()->getOptions()->getDef( 'license_store_url_api' );
228
- $data[ 'Ping License Server' ] = $licPing->ping() ? 'Yes' : 'No';
229
 
230
  $data[ 'Write TMP/Cache DIR' ] = $con->cache_dir_handler->dirExists() ? 'Yes: '.$con->getPluginCachePath() : 'No';
231
 
223
  'WP Hashes Ping' => ( new ApiPing() )->ping() ? 'Yes' : 'No',
224
  ];
225
 
226
+ $data[ 'Ping License Server' ] = ( new Licenses\Keyless\Ping() )->ping() ? 'Yes' : 'No';
 
 
227
 
228
  $data[ 'Write TMP/Cache DIR' ] = $con->cache_dir_handler->dirExists() ? 'Yes: '.$con->getPluginCachePath() : 'No';
229
 
src/lib/src/Modules/Plugin/Lib/ImportExport/Export.php CHANGED
@@ -94,13 +94,13 @@ class Export {
94
  /**
95
  * @return string[]
96
  */
97
- public function toStandardArray() :array{
98
- $sExport = json_encode( $this->getExportData() );
99
  return [
100
  '# Site URL: '.Services::WpGeneral()->getHomeUrl(),
101
  '# Export Date: '.Services::WpGeneral()->getTimeStringForDisplay(),
102
- '# Hash: '.sha1( $sExport ),
103
- $sExport
104
  ];
105
  }
106
 
@@ -114,14 +114,27 @@ class Export {
114
  );
115
  }
116
 
117
- private function getExportData() :array{
 
 
 
 
 
 
 
 
 
118
  $all = [];
119
  foreach ( $this->getCon()->modules as $mod ) {
120
- $oOpts = $mod->getOptions();
121
- $all[ $mod->getOptionsStorageKey() ] = array_diff_key(
122
- $oOpts->getTransferableOptions(),
123
- array_flip( $oOpts->getXferExcluded() )
124
- );
 
 
 
 
125
  }
126
  return $all;
127
  }
@@ -130,7 +143,7 @@ class Export {
130
  * @param string $url
131
  * @return bool
132
  */
133
- private function isUrlOnWhitelist( $url ) :bool{
134
  /** @var Plugin\Options $opts */
135
  $opts = $this->getOptions();
136
  return !empty( $url ) && in_array( $url, $opts->getImportExportWhitelist() );
@@ -140,7 +153,7 @@ class Export {
140
  * @param string $url
141
  * @return bool
142
  */
143
- private function verifyUrlWithHandshake( $url ):bool {
144
  $bVerified = false;
145
 
146
  if ( !empty( $url ) ) {
94
  /**
95
  * @return string[]
96
  */
97
+ public function toStandardArray() :array {
98
+ $export = json_encode( $this->getExportData() );
99
  return [
100
  '# Site URL: '.Services::WpGeneral()->getHomeUrl(),
101
  '# Export Date: '.Services::WpGeneral()->getTimeStringForDisplay(),
102
+ '# Hash: '.sha1( $export ),
103
+ $export
104
  ];
105
  }
106
 
114
  );
115
  }
116
 
117
+ public function getExportData() :array {
118
+ $all = [];
119
+ foreach ( $this->getRawOptionsExport() as $modSlug => $modOptions ) {
120
+ $mod = $this->getCon()->modules[ $modSlug ];
121
+ $all[ $mod->getOptionsStorageKey() ] = $modOptions;
122
+ }
123
+ return $all;
124
+ }
125
+
126
+ public function getRawOptionsExport( bool $filterExcluded = true ) :array {
127
  $all = [];
128
  foreach ( $this->getCon()->modules as $mod ) {
129
+ $opts = $mod->getOptions();
130
+ $xfr = $opts->getTransferableOptions();
131
+ if ( $filterExcluded ) {
132
+ $xfr = array_diff_key(
133
+ $xfr,
134
+ array_flip( $opts->getXferExcluded() )
135
+ );
136
+ }
137
+ $all[ $mod->getSlug() ] = $xfr;
138
  }
139
  return $all;
140
  }
143
  * @param string $url
144
  * @return bool
145
  */
146
+ private function isUrlOnWhitelist( $url ) :bool {
147
  /** @var Plugin\Options $opts */
148
  $opts = $this->getOptions();
149
  return !empty( $url ) && in_array( $url, $opts->getImportExportWhitelist() );
153
  * @param string $url
154
  * @return bool
155
  */
156
+ private function verifyUrlWithHandshake( $url ) :bool {
157
  $bVerified = false;
158
 
159
  if ( !empty( $url ) ) {
src/lib/src/Modules/Plugin/Lib/Ops/ResetPlugin.php CHANGED
@@ -1,13 +1,9 @@
1
- <?php
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Lib\Ops;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\PluginControllerConsumer;
6
 
7
- /**
8
- * Class ResetPlugin
9
- * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Lib\Ops
10
- */
11
  class ResetPlugin {
12
 
13
  use PluginControllerConsumer;
1
+ <?php declare( strict_types=1 );
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Lib\Ops;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\PluginControllerConsumer;
6
 
 
 
 
 
7
  class ResetPlugin {
8
 
9
  use PluginControllerConsumer;
src/lib/src/Modules/Plugin/Lib/Ops/VerifyDatabaseIntegrity.php ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Lib\Ops;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\PluginControllerConsumer;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
+
8
+ class VerifyDatabaseIntegrity {
9
+
10
+ use PluginControllerConsumer;
11
+
12
+ public function run() {
13
+ $this->verifyForeignKeys();
14
+ }
15
+
16
+ /**
17
+ * Seeks to find DB tables where the registered foreign keys are invalid. This can happen, it seems, if db tables
18
+ * are renamed after they've been created, and the foreign key restraints reference tables that no longer exist.
19
+ */
20
+ private function verifyForeignKeys() {
21
+ $WPDB = Services::WpDb();
22
+
23
+ $tablesToDelete = [];
24
+ foreach ( $this->getCon()->modules as $mod ) {
25
+ try {
26
+ $dbhs = $mod->getDbHandler()->loadAllDbHandlers();
27
+ }
28
+ catch ( \Exception $e ) {
29
+ continue;
30
+ }
31
+ foreach ( $dbhs as $dbh ) {
32
+ $schema = $dbh->getTableSchema();
33
+
34
+ foreach ( $dbh->getTableSchema()->getColumnsDefs() as $col => $def ) {
35
+ if ( !empty( $def[ 'foreign_key' ] ) ) {
36
+
37
+ $fk = $def[ 'foreign_key' ];
38
+ $ft = sprintf( '%s%s', ( $fk[ 'wp_prefix' ] ?? true ) ? $WPDB->getPrefix() : '', $fk[ 'ref_table' ] );
39
+
40
+ $constraintFound = false;
41
+ foreach ( $this->getForeignKeyConstraintsOn( $ft ) as $fkConstraint ) {
42
+ $constraintFound = ( $fkConstraint[ 'TABLE_NAME' ] ?? '' ) === $schema->table
43
+ && ( $fkConstraint[ 'COLUMN_NAME' ] ?? '' ) === $col;
44
+ if ( $constraintFound ) {
45
+ break;
46
+ }
47
+ }
48
+ if ( !$constraintFound ) {
49
+ $tablesToDelete[] = $schema->table;
50
+ }
51
+ }
52
+ }
53
+ }
54
+ }
55
+
56
+ if ( !empty( $tablesToDelete ) ) {
57
+ error_log( sprintf( 'invalid foreign key configuration found. Dropping Shield tables: %s',
58
+ implode( ",", $tablesToDelete ) ) );
59
+ $WPDB->doSql( sprintf( 'DROP TABLE IF EXISTS `%s`', implode( "`,`", $tablesToDelete ) ) );
60
+ }
61
+ }
62
+
63
+ /**
64
+ * array(5) {
65
+ * ["TABLE_NAME"]=>
66
+ * string(25) "test1_icwp_wpsf_botsignal"
67
+ * ["COLUMN_NAME"]=>
68
+ * string(6) "ip_ref"
69
+ * ["CONSTRAINT_NAME"]=>
70
+ * string(32) "test1_icwp_wpsf_botsignal_ibfk_1"
71
+ * ["REFERENCED_TABLE_NAME"]=>
72
+ * string(19) "test1_icwp_wpsf_ips"
73
+ * ["REFERENCED_COLUMN_NAME"]=>
74
+ * string(2) "id"
75
+ * }
76
+ */
77
+ private function getForeignKeyConstraintsOn( string $table ) :array {
78
+ $DB = Services::WpDb();
79
+ $data = $DB->selectCustom( sprintf( "
80
+ SELECT
81
+ TABLE_NAME,COLUMN_NAME,CONSTRAINT_NAME,REFERENCED_TABLE_NAME,REFERENCED_COLUMN_NAME
82
+ FROM
83
+ INFORMATION_SCHEMA.KEY_COLUMN_USAGE
84
+ WHERE
85
+ REFERENCED_TABLE_SCHEMA = '%s' AND REFERENCED_TABLE_NAME = '%s';
86
+ ",
87
+ DB_NAME, $table )
88
+ );
89
+ return is_array( $data ) ? $data : [];
90
+ }
91
+ }
src/lib/src/Modules/Plugin/Lib/OverrideLocale.php CHANGED
@@ -5,10 +5,6 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Lib;
5
  use FernleafSystems\Wordpress\Plugin\Shield\Controller\I18n\LoadTextDomain;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
 
8
- /**
9
- * Class OverrideLocale
10
- * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Lib
11
- */
12
  class OverrideLocale {
13
 
14
  use ModConsumer;
5
  use FernleafSystems\Wordpress\Plugin\Shield\Controller\I18n\LoadTextDomain;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
 
 
 
 
 
8
  class OverrideLocale {
9
 
10
  use ModConsumer;
src/lib/src/Modules/Plugin/Lib/TourManager.php CHANGED
@@ -5,10 +5,6 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Lib;
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
  use FernleafSystems\Wordpress\Services\Services;
7
 
8
- /**
9
- * Class TourManager
10
- * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Lib
11
- */
12
  class TourManager {
13
 
14
  use ModConsumer;
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
  use FernleafSystems\Wordpress\Services\Services;
7
 
 
 
 
 
8
  class TourManager {
9
 
10
  use ModConsumer;
src/lib/src/Modules/Plugin/Options.php CHANGED
@@ -51,7 +51,8 @@ class Options extends BaseShield\Options {
51
  }
52
 
53
  public function isEnabledWpcli() :bool {
54
- return $this->isPremium() && $this->isOpt( 'enable_wpcli', 'Y' );
 
55
  }
56
 
57
  public function isTrackingPermissionSet() :bool {
51
  }
52
 
53
  public function isEnabledWpcli() :bool {
54
+ return $this->isPremium()
55
+ && apply_filters( 'shield/enable_wpcli', $this->isOpt( 'enable_wpcli', 'Y' ) );
56
  }
57
 
58
  public function isTrackingPermissionSet() :bool {
src/lib/src/Modules/Plugin/Rest.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Rest\Route\{
6
+ Debug\Retrieve,
7
+ Options
8
+ };
9
+
10
+ class Rest extends \FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Rest {
11
+
12
+ protected function enumRoutes() :array {
13
+ return [
14
+ 'debug_get' => Retrieve::class,
15
+ 'option_get' => Options\GetSingle::class,
16
+ 'option_set' => Options\SetSingle::class,
17
+ 'options_get' => Options\GetAll::class,
18
+ 'options_set' => Options\SetBulk::class,
19
+ ];
20
+ }
21
+ }
src/lib/src/Modules/Plugin/Rest/Exceptions/OptionDoesNotExistException.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Rest\Exceptions;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Core\Rest\Exceptions\InvalidRequestParametersException;
6
+
7
+ class OptionDoesNotExistException extends InvalidRequestParametersException {
8
+
9
+ }
src/lib/src/Modules/Plugin/Rest/Request/Debug/Retrieve.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Rest\Request\Debug;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Rest\Request\Process;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Lib\Debug\Collate;
7
+
8
+ class Retrieve extends Process {
9
+
10
+ protected function process() :array {
11
+ return ( new Collate() )
12
+ ->setMod( $this->getMod() )
13
+ ->run();
14
+ }
15
+ }
src/lib/src/Modules/Plugin/Rest/Request/Options/Base.php ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Rest\Request\Options;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Rest\Request\Process;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Lib\ImportExport\Export;
7
+
8
+ abstract class Base extends Process {
9
+
10
+ /**
11
+ * @return RequestVO
12
+ */
13
+ protected function newReqVO() {
14
+ return new RequestVO();
15
+ }
16
+
17
+ protected function getAllOptions() :array {
18
+ /** @var RequestVO $req */
19
+ $req = $this->getRequestVO();
20
+ $all = [];
21
+ $filterFields = $req->filter_fields;
22
+ foreach ( ( new Export() )->setMod( $this->getMod() )->getRawOptionsExport() as $modOpts ) {
23
+ foreach ( array_keys( $modOpts ) as $key ) {
24
+ if ( empty( $req->filter_keys ) || in_array( $key, $req->filter_keys ) ) {
25
+ $optDef = $this->getOptionData( $key );
26
+ $all[] = empty( $filterFields ) ? $optDef : array_intersect_key( $optDef, $filterFields );
27
+ }
28
+ }
29
+ }
30
+ return $all;
31
+ }
32
+
33
+ /**
34
+ * Option key existence is checked in the Route.
35
+ */
36
+ protected function getOptionData( string $key ) :array {
37
+ $def = [];
38
+ foreach ( $this->getCon()->modules as $module ) {
39
+ $opts = $module->getOptions();
40
+ $maybe = $opts->getOptDefinition( $key );
41
+ if ( !empty( $maybe ) ) {
42
+ $def = $maybe;
43
+ $def[ 'module' ] = $module->getSlug();
44
+ $def[ 'value' ] = $opts->getOpt( $key );
45
+ break;
46
+ }
47
+ }
48
+ return $def;
49
+ }
50
+ }
src/lib/src/Modules/Plugin/Rest/Request/Options/GetAll.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Rest\Request\Options;
4
+
5
+ class GetAll extends Base {
6
+
7
+ /**
8
+ * @inheritDoc
9
+ */
10
+ protected function process() :array {
11
+ return $this->getAllOptions();
12
+ }
13
+ }
src/lib/src/Modules/Plugin/Rest/Request/Options/GetSingle.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Rest\Request\Options;
4
+
5
+ class GetSingle extends Base {
6
+
7
+ /**
8
+ * @inheritDoc
9
+ */
10
+ protected function process() :array {
11
+ $req = $this->getRequestVO();
12
+
13
+ $theOption = null;
14
+ foreach ( $this->getAllOptions() as $option ) {
15
+ if ( $option[ 'key' ] === $req->key ) {
16
+ $theOption = $option;
17
+ break;
18
+ }
19
+ }
20
+
21
+ return [
22
+ 'options' => $theOption
23
+ ];
24
+ }
25
+ }
src/lib/src/Modules/Plugin/Rest/Request/Options/RequestVO.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Rest\Request\Options;
4
+
5
+ /**
6
+ * @property array[] $options
7
+ * @property string[] $filter_keys
8
+ */
9
+ class RequestVO extends \FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Rest\Request\RequestVO {
10
+
11
+ public function __get( string $key ) {
12
+ $value = parent::__get( $key );
13
+
14
+ switch ( $key ) {
15
+ case 'filter_keys':
16
+ $value = (array)$value;
17
+ break;
18
+ }
19
+
20
+ return $value;
21
+ }
22
+
23
+ protected function getDefaultFilterFields() :array {
24
+ return [
25
+ 'key',
26
+ 'value',
27
+ 'module',
28
+ ];
29
+ }
30
+ }
src/lib/src/Modules/Plugin/Rest/Request/Options/SetBulk.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Rest\Request\Options;
4
+
5
+ class SetBulk extends Base {
6
+
7
+ /**
8
+ * @inheritDoc
9
+ */
10
+ protected function process() :array {
11
+ $con = $this->getCon();
12
+ /** @var RequestVO $req */
13
+ $req = $this->getRequestVO();
14
+
15
+ $filterKeys = [];
16
+ foreach ( $req->options as $opt ) {
17
+ $def = $this->getOptionData( $opt[ 'key' ] );
18
+ if ( !empty( $def ) ) {
19
+ $filterKeys[] = $opt[ 'key' ];
20
+ $opts = $con->modules[ $def[ 'module' ] ]->getOptions();
21
+ if ( is_null( $opt[ 'value' ] ) ) {
22
+ $opts->resetOptToDefault( $opt[ 'key' ] );
23
+ }
24
+ else {
25
+ $opts->setOpt( $opt[ 'key' ], $opt[ 'value' ] );
26
+ if ( serialize( $opt[ 'value' ] ) !== serialize( $opts->getOpt( $opt[ 'key' ] ) ) ) {
27
+ throw new \Exception( sprintf( 'Failed to update option (%s). Value may be of an incorrect type.', $opt[ 'key' ] ) );
28
+ }
29
+ }
30
+ }
31
+ }
32
+ $req->filter_keys = $filterKeys;
33
+ return $this->getAllOptions();
34
+ }
35
+ }
src/lib/src/Modules/Plugin/Rest/Request/Options/SetSingle.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Rest\Request\Options;
4
+
5
+ class SetSingle extends SetBulk {
6
+
7
+ /**
8
+ * We convert the request data to reflect that of SetBulk and call SetBulk's processor.
9
+ * @inheritDoc
10
+ */
11
+ protected function process() :array {
12
+ /** @var RequestVO $req */
13
+ $req = $this->getRequestVO();
14
+ $req->options = [
15
+ [
16
+ 'key' => $this->getWpRestRequest()->get_param( 'key' ),
17
+ 'value' => $this->getWpRestRequest()->get_param( 'value' ),
18
+ ]
19
+ ];
20
+ return parent::process();
21
+ }
22
+ }
src/lib/src/Modules/Plugin/Rest/Route/Debug/Retrieve.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Rest\Route\Debug;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Rest\Route\RouteBase;
6
+
7
+ class Retrieve extends RouteBase {
8
+
9
+ protected function getRequestProcessorClass() :string {
10
+ return \FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Rest\Request\Debug\Retrieve::class;
11
+ }
12
+
13
+ public function getRoutePath() :string {
14
+ return 'debug';
15
+ }
16
+ }
src/lib/src/Modules/Plugin/Rest/Route/Options/Base.php ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Rest\Route\Options;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Rest\Route\RouteBase;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Lib\ImportExport\Export;
7
+
8
+ abstract class Base extends RouteBase {
9
+
10
+ private static $allOpts;
11
+
12
+ public function getRoutePathPrefix() :string {
13
+ return '/options';
14
+ }
15
+
16
+ protected function getRouteArgsDefaults() :array {
17
+ $optFields = array_unique( array_merge(
18
+ [
19
+ 'all', // special case
20
+ 'value',
21
+ 'module',
22
+ ],
23
+ array_keys( $this->getMod()->getOptions()->getOptDefinition( 'global_enable_plugin_features' ) )
24
+ ) );
25
+
26
+ return [
27
+ 'filter_fields' => [
28
+ 'description' => '[Filter] Comma-separated fields to include in option info.',
29
+ 'type' => 'array', // WordPress kindly converts CSV to array
30
+ 'pattern' => sprintf( '^(((%s),?)+)?$', implode( '|', $optFields ) ),
31
+ 'required' => false,
32
+ ],
33
+ ];
34
+ }
35
+
36
+ protected function getRouteArgSchema( string $key ) :array {
37
+ switch ( $key ) {
38
+ case 'key':
39
+ $sch = [
40
+ 'description' => 'Option key',
41
+ 'type' => 'string',
42
+ 'enum' => $this->getAllPossibleOptKeys(),
43
+ 'required' => true,
44
+ 'readonly' => true,
45
+ ];
46
+ break;
47
+
48
+ case 'value':
49
+ $sch = [
50
+ 'description' => 'Option value',
51
+ 'required' => true,
52
+ 'type' => [
53
+ 'object',
54
+ 'string',
55
+ 'number',
56
+ 'null'
57
+ ],
58
+ ];
59
+ break;
60
+
61
+ default:
62
+ $sch = parent::getRouteArgSchema( $key );
63
+ break;
64
+ }
65
+ return $sch;
66
+ }
67
+
68
+ protected function getAllPossibleOptKeys() :array {
69
+ if ( !isset( self::$allOpts ) ) {
70
+ $allOpts = [];
71
+ foreach ( ( new Export() )->setMod( $this->getMod() )->getRawOptionsExport() as $modOpts ) {
72
+ $allOpts = array_merge( $allOpts, array_keys( $modOpts ) );
73
+ }
74
+ natsort( $allOpts );
75
+ self::$allOpts = array_values( $allOpts );
76
+ }
77
+ return self::$allOpts;
78
+ }
79
+ }
src/lib/src/Modules/Plugin/Rest/Route/Options/BaseBulk.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Rest\Route\Options;
4
+
5
+ abstract class BaseBulk extends Base {
6
+
7
+ public function getRoutePath() :string {
8
+ return '';
9
+ }
10
+
11
+ protected function getRouteArgsDefaults() :array {
12
+ return array_merge(
13
+ parent::getRouteArgsDefaults(),
14
+ [
15
+ 'filter_keys' => [
16
+ 'description' => '[Filter][Comma-Separated] Option keys to include.',
17
+ 'type' => 'array', // WordPress kindly converts CSV to array
18
+ 'pattern' => sprintf( '^(((%s),?)+)?$', implode( '|', $this->getAllPossibleOptKeys() ) ),
19
+ 'required' => false,
20
+ ],
21
+ ]
22
+ );
23
+ }
24
+ }
src/lib/src/Modules/Plugin/Rest/Route/Options/BaseSingle.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Rest\Route\Options;
4
+
5
+ abstract class BaseSingle extends Base {
6
+
7
+ public function getRoutePath() :string {
8
+ return '/(?P<key>[0-9a-z_]+)';
9
+ }
10
+
11
+ protected function getRouteArgsDefaults() :array {
12
+ return array_merge(
13
+ parent::getRouteArgsDefaults(),
14
+ [
15
+ 'key' => $this->getRouteArgSchema( 'key' ),
16
+ ]
17
+ );
18
+ }
19
+ }
src/lib/src/Modules/Plugin/Rest/Route/Options/GetAll.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Rest\Route\Options;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Rest\Request\Options;
6
+
7
+ class GetAll extends BaseBulk {
8
+
9
+ protected function getRequestProcessorClass() :string {
10
+ return Options\GetAll::class;
11
+ }
12
+ }
src/lib/src/Modules/Plugin/Rest/Route/Options/GetSingle.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Rest\Route\Options;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Rest\Request\Options;
6
+
7
+ class GetSingle extends BaseSingle {
8
+
9
+ protected function getRequestProcessorClass() :string {
10
+ return Options\GetSingle::class;
11
+ }
12
+ }
src/lib/src/Modules/Plugin/Rest/Route/Options/SetBulk.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Rest\Route\Options;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Rest\Request\Options;
6
+
7
+ class SetBulk extends BaseBulk {
8
+
9
+ const ROUTE_METHOD = \WP_REST_Server::EDITABLE;
10
+
11
+ protected function getRouteArgsCustom() :array {
12
+ return [
13
+ 'options' => [
14
+ 'description' => 'Array of options to set. Each must include option key and value',
15
+ 'required' => true,
16
+ 'type' => 'array',
17
+ 'items' => [
18
+ 'type' => 'object',
19
+ 'properties' => [
20
+ 'key' => $this->getRouteArgSchema( 'key' ),
21
+ 'value' => $this->getRouteArgSchema( 'value' ),
22
+ ],
23
+ ],
24
+ ],
25
+ ];
26
+ }
27
+
28
+ protected function getRequestProcessorClass() :string {
29
+ return Options\SetBulk::class;
30
+ }
31
+ }
src/lib/src/Modules/Plugin/Rest/Route/Options/SetSingle.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Rest\Route\Options;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Rest\Request\Options;
6
+
7
+ class SetSingle extends BaseSingle {
8
+
9
+ const ROUTE_METHOD = \WP_REST_Server::EDITABLE;
10
+
11
+ protected function getRouteArgsCustom() :array {
12
+ return [
13
+ 'value' => $this->getRouteArgSchema( 'value' ),
14
+ ];
15
+ }
16
+
17
+ protected function getRequestProcessorClass() :string {
18
+ return Options\SetSingle::class;
19
+ }
20
+ }
src/lib/src/Modules/Plugin/Strings.php CHANGED
@@ -13,39 +13,39 @@ class Strings extends Base\Strings {
13
  */
14
  public function getEventStrings() :array {
15
  return [
16
- 'debug_log' => [
17
  'name' => __( 'Custom Debug', 'wp-simple-firewall' ),
18
  'audit' => [
19
  '{{message}}',
20
  ],
21
  ],
22
- 'frontpage_load' => [
23
  'name' => sprintf( '%s: %s', __( 'Loaded', 'wp-simple-firewall' ),
24
  __( 'Front Page', 'wp-simple-firewall' ) ),
25
  'audit' => [
26
  __( 'Front page loaded', 'wp-simple-firewall' ),
27
  ],
28
  ],
29
- 'loginpage_load' => [
30
  'name' => sprintf( '%s: %s', __( 'Loaded', 'wp-simple-firewall' ),
31
  __( 'Login Page', 'wp-simple-firewall' ) ),
32
  'audit' => [
33
  __( 'Login page loaded', 'wp-simple-firewall' ),
34
  ],
35
  ],
36
- 'recaptcha_success' => [
37
  'name' => __( 'CAPTCHA Pass', 'wp-simple-firewall' ),
38
  'audit' => [
39
  __( 'CAPTCHA test successful.', 'wp-simple-firewall' ),
40
  ],
41
  ],
42
- 'recaptcha_fail' => [
43
  'name' => __( 'CAPTCHA Fail', 'wp-simple-firewall' ),
44
  'audit' => [
45
  __( 'CAPTCHA test failed.', 'wp-simple-firewall' ),
46
  ],
47
  ],
48
- 'test_cron_run' => [
49
  'name' => __( 'Test Cron Run', 'wp-simple-firewall' ),
50
  'audit' => [
51
  __( 'Test WP Cron ran successfully.', 'wp-simple-firewall' ),
@@ -57,50 +57,50 @@ class Strings extends Base\Strings {
57
  __( 'Sent notifications to whitelisted sites for required options import.', 'wp-simple-firewall' ),
58
  ],
59
  ],
60
- 'import_notify_received' => [
61
  'name' => __( 'Import Notify Received', 'wp-simple-firewall' ),
62
  'audit' => [
63
  __( 'Received notification that options import required.', 'wp-simple-firewall' ),
64
  __( 'Current master site: {{master_site}}', 'wp-simple-firewall' ),
65
  ],
66
  ],
67
- 'options_exported' => [
68
  'name' => __( 'Options Exported', 'wp-simple-firewall' ),
69
  'audit' => [
70
  __( 'Options exported to site: {{site}}', 'wp-simple-firewall' ),
71
  ],
72
  ],
73
- 'options_imported' => [
74
  'name' => __( 'Options Imported', 'wp-simple-firewall' ),
75
  'audit' => [
76
  __( 'Options exported from site: {{site}}', 'wp-simple-firewall' ),
77
  ],
78
  ],
79
- 'whitelist_site_added' => [
80
  'name' => __( 'Whitelist Site Added', 'wp-simple-firewall' ),
81
  'audit' => [
82
  __( 'Site added to export white list: {{site}}', 'wp-simple-firewall' ),
83
  ],
84
  ],
85
- 'whitelist_site_removed' => [
86
  'name' => __( 'Whitelist Site Removed', 'wp-simple-firewall' ),
87
  'audit' => [
88
  __( 'Site removed from export white list: {{site}}', 'wp-simple-firewall' ),
89
  ],
90
  ],
91
- 'master_url_set' => [
92
  'name' => __( 'Whitelist Site Removed', 'wp-simple-firewall' ),
93
  'audit' => [
94
  __( 'Master Site URL set: {{site}}', 'wp-simple-firewall' ),
95
  ],
96
  ],
97
- 'antibot_pass' => [
98
  'name' => __( 'AntiBot Pass', 'wp-simple-firewall' ),
99
  'audit' => [
100
  __( 'Request passed the AntiBot Test with a Visitor Score of "{{score}}" (minimum score: {{minimum}}).', 'wp-simple-firewall' ),
101
  ],
102
  ],
103
- 'antibot_fail' => [
104
  'name' => __( 'AntiBot Fail', 'wp-simple-firewall' ),
105
  'audit' => [
106
  __( 'Request failed the AntiBot Test with a Visitor Score of "{{score}}" (minimum score: {{minimum}}).', 'wp-simple-firewall' ),
13
  */
14
  public function getEventStrings() :array {
15
  return [
16
+ 'debug_log' => [
17
  'name' => __( 'Custom Debug', 'wp-simple-firewall' ),
18
  'audit' => [
19
  '{{message}}',
20
  ],
21
  ],
22
+ 'frontpage_load' => [
23
  'name' => sprintf( '%s: %s', __( 'Loaded', 'wp-simple-firewall' ),
24
  __( 'Front Page', 'wp-simple-firewall' ) ),
25
  'audit' => [
26
  __( 'Front page loaded', 'wp-simple-firewall' ),
27
  ],
28
  ],
29
+ 'loginpage_load' => [
30
  'name' => sprintf( '%s: %s', __( 'Loaded', 'wp-simple-firewall' ),
31
  __( 'Login Page', 'wp-simple-firewall' ) ),
32
  'audit' => [
33
  __( 'Login page loaded', 'wp-simple-firewall' ),
34
  ],
35
  ],
36
+ 'recaptcha_success' => [
37
  'name' => __( 'CAPTCHA Pass', 'wp-simple-firewall' ),
38
  'audit' => [
39
  __( 'CAPTCHA test successful.', 'wp-simple-firewall' ),
40
  ],
41
  ],
42
+ 'recaptcha_fail' => [
43
  'name' => __( 'CAPTCHA Fail', 'wp-simple-firewall' ),
44
  'audit' => [
45
  __( 'CAPTCHA test failed.', 'wp-simple-firewall' ),
46
  ],
47
  ],
48
+ 'test_cron_run' => [
49
  'name' => __( 'Test Cron Run', 'wp-simple-firewall' ),
50
  'audit' => [
51
  __( 'Test WP Cron ran successfully.', 'wp-simple-firewall' ),
57
  __( 'Sent notifications to whitelisted sites for required options import.', 'wp-simple-firewall' ),
58
  ],
59
  ],
60
+ 'import_notify_received' => [
61
  'name' => __( 'Import Notify Received', 'wp-simple-firewall' ),
62
  'audit' => [
63
  __( 'Received notification that options import required.', 'wp-simple-firewall' ),
64
  __( 'Current master site: {{master_site}}', 'wp-simple-firewall' ),
65
  ],
66
  ],
67
+ 'options_exported' => [
68
  'name' => __( 'Options Exported', 'wp-simple-firewall' ),
69
  'audit' => [
70
  __( 'Options exported to site: {{site}}', 'wp-simple-firewall' ),
71
  ],
72
  ],
73
+ 'options_imported' => [
74
  'name' => __( 'Options Imported', 'wp-simple-firewall' ),
75
  'audit' => [
76
  __( 'Options exported from site: {{site}}', 'wp-simple-firewall' ),
77
  ],
78
  ],
79
+ 'whitelist_site_added' => [
80
  'name' => __( 'Whitelist Site Added', 'wp-simple-firewall' ),
81
  'audit' => [
82
  __( 'Site added to export white list: {{site}}', 'wp-simple-firewall' ),
83
  ],
84
  ],
85
+ 'whitelist_site_removed' => [
86
  'name' => __( 'Whitelist Site Removed', 'wp-simple-firewall' ),
87
  'audit' => [
88
  __( 'Site removed from export white list: {{site}}', 'wp-simple-firewall' ),
89
  ],
90
  ],
91
+ 'master_url_set' => [
92
  'name' => __( 'Whitelist Site Removed', 'wp-simple-firewall' ),
93
  'audit' => [
94
  __( 'Master Site URL set: {{site}}', 'wp-simple-firewall' ),
95
  ],
96
  ],
97
+ 'antibot_pass' => [
98
  'name' => __( 'AntiBot Pass', 'wp-simple-firewall' ),
99
  'audit' => [
100
  __( 'Request passed the AntiBot Test with a Visitor Score of "{{score}}" (minimum score: {{minimum}}).', 'wp-simple-firewall' ),
101
  ],
102
  ],
103
+ 'antibot_fail' => [
104
  'name' => __( 'AntiBot Fail', 'wp-simple-firewall' ),
105
  'audit' => [
106
  __( 'Request failed the AntiBot Test with a Visitor Score of "{{score}}" (minimum score: {{minimum}}).', 'wp-simple-firewall' ),
src/lib/src/Modules/SecurityAdmin/ModCon.php CHANGED
@@ -40,6 +40,24 @@ class ModCon extends BaseShield\ModCon {
40
  return $this->securityAdminCon;
41
  }
42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  public function getSecAdminLoginAjaxData() :array {
44
  return $this->getAjaxActionData( 'sec_admin_login' );
45
  }
@@ -65,6 +83,8 @@ class ModCon extends BaseShield\ModCon {
65
  // If you delete the PIN, you also delete the sec admins. Prevents a lock out bug.
66
  $opts->setOpt( 'sec_admin_users', [] );
67
  }
 
 
68
  }
69
 
70
  protected function handleModAction( string $action ) {
40
  return $this->securityAdminCon;
41
  }
42
 
43
+ public function runDailyCron() {
44
+ parent::runDailyCron();
45
+ $this->runMuHandler();
46
+ }
47
+
48
+ private function runMuHandler() {
49
+ /** @var Options $opts */
50
+ $opts = $this->getOptions();
51
+
52
+ $mu = $this->getCon()->mu_handler;
53
+ try {
54
+ $opts->isEnabledMU() ? $mu->convertToMU() : $mu->convertToStandard();
55
+ }
56
+ catch ( \Exception $e ) {
57
+ }
58
+ $opts->setOpt( 'enable_mu', $mu->isActiveMU() ? 'Y' : 'N' );
59
+ }
60
+
61
  public function getSecAdminLoginAjaxData() :array {
62
  return $this->getAjaxActionData( 'sec_admin_login' );
63
  }
83
  // If you delete the PIN, you also delete the sec admins. Prevents a lock out bug.
84
  $opts->setOpt( 'sec_admin_users', [] );
85
  }
86
+
87
+ $this->runMuHandler();
88
  }
89
 
90
  protected function handleModAction( string $action ) {
src/lib/src/Modules/SecurityAdmin/Options.php CHANGED
@@ -68,6 +68,10 @@ class Options extends BaseShield\Options {
68
  return $this->isOpt( 'allow_email_override', 'Y' );
69
  }
70
 
 
 
 
 
71
  public function isSecAdminRestrictUsersEnabled() :bool {
72
  return $this->isOpt( 'admin_access_restrict_admin_users', 'Y' );
73
  }
68
  return $this->isOpt( 'allow_email_override', 'Y' );
69
  }
70
 
71
+ public function isEnabledMU() :bool {
72
+ return $this->isOpt( 'enable_mu', 'Y' );
73
+ }
74
+
75
  public function isSecAdminRestrictUsersEnabled() :bool {
76
  return $this->isOpt( 'admin_access_restrict_admin_users', 'Y' );
77
  }
src/lib/src/Modules/SecurityAdmin/Strings.php CHANGED
@@ -11,7 +11,7 @@ class Strings extends Base\Strings {
11
  */
12
  public function getEventStrings() :array {
13
  return [
14
- 'key_success' => [
15
  'name' => __( 'Security PIN Pass', 'wp-simple-firewall' ),
16
  'audit' => [
17
  __( 'Security PIN authentication successful.', 'wp-simple-firewall' ),
@@ -27,9 +27,7 @@ class Strings extends Base\Strings {
27
  }
28
 
29
  /**
30
- * @param string $section
31
- * @return array
32
- * @throws \Exception
33
  */
34
  public function getSectionStrings( string $section ) :array {
35
  $sPlugName = $this->getCon()->getHumanName();
@@ -93,9 +91,7 @@ class Strings extends Base\Strings {
93
  }
94
 
95
  /**
96
- * @param string $key
97
- * @return array
98
- * @throws \Exception
99
  */
100
  public function getOptionStrings( string $key ) :array {
101
  /** @var Options $opts */
@@ -107,20 +103,20 @@ class Strings extends Base\Strings {
107
  case 'enable_admin_access_restriction' :
108
  $name = sprintf( __( 'Enable %s Module', 'wp-simple-firewall' ), __( 'Security Admin', 'wp-simple-firewall' ) );
109
  $summary = __( 'Enforce Security Admin Access Restriction', 'wp-simple-firewall' );
110
- $description = __( "Enable this with great care and consideration. Ensure that you set an Security PIN that you'll remember.", 'wp-simple-firewall' );
111
  break;
112
 
113
  case 'admin_access_key' :
114
  $name = __( 'Security Admin PIN', 'wp-simple-firewall' );
115
  $summary = __( 'Provide/Update Security Admin PIN', 'wp-simple-firewall' );
116
- $description = [
117
  sprintf( '%s: %s', __( 'Careful', 'wp-simple-firewall' ), __( 'If you forget this, you could potentially lock yourself out from using this plugin.', 'wp-simple-firewall' ) ),
118
  '<strong>'.( $opts->hasSecurityPIN() ? __( 'Security PIN Currently Set', 'wp-simple-firewall' ) : __( 'Security PIN NOT Currently Set', 'wp-simple-firewall' ) ).'</strong>',
119
  ];
120
  if ( $opts->hasSecurityPIN() ) {
121
- $description[] = sprintf( __( 'To delete the current security PIN, type exactly "%s" and save.', 'wp-simple-firewall' ), '<strong>DELETE</strong>' );
122
  if ( !empty( $opts->getSecurityAdminUsers() ) ) {
123
- $description[] = sprintf( '%s: %s', __( 'Important', 'wp-simple-firewall' ), __( 'Deleting the PIN will also remove security admin users.', 'wp-simple-firewall' ) );
124
  }
125
  }
126
 
@@ -129,7 +125,7 @@ class Strings extends Base\Strings {
129
  case 'sec_admin_users' :
130
  $name = __( 'Security Admins', 'wp-simple-firewall' );
131
  $summary = __( 'Persistent Security Admins', 'wp-simple-firewall' );
132
- $description = [
133
  __( "Users provided will be security admins automatically, without needing the security PIN.", 'wp-simple-firewall' ),
134
  __( 'Enter admin username, email or ID.', 'wp-simple-firewall' ).' '.__( '1 entry per-line.', 'wp-simple-firewall' ),
135
  sprintf( '%s: %s', __( 'Note', 'wp-simple-firewall' ), __( 'Verified users will be converted to usernames.', 'wp-simple-firewall' ) )
@@ -139,122 +135,135 @@ class Strings extends Base\Strings {
139
  case 'admin_access_timeout' :
140
  $name = __( 'Security Admin Timeout', 'wp-simple-firewall' );
141
  $summary = __( 'Specify An Automatic Timeout Interval For Security Admin Access', 'wp-simple-firewall' );
142
- $description = __( 'This will automatically expire your Security Admin Session.', 'wp-simple-firewall' )
143
- .'<br />'
144
- .sprintf(
145
- '%s: %s',
146
- __( 'Default', 'wp-simple-firewall' ),
147
- sprintf( '%s minutes', $opts->getOptDefault( 'admin_access_timeout' ) )
148
- );
149
  break;
150
 
151
  case 'allow_email_override' :
152
  $name = __( 'Allow Email Override', 'wp-simple-firewall' );
153
  $summary = __( 'Allow Email Override Of Admin Access Restrictions', 'wp-simple-firewall' );
154
- $description = __( 'Allow the use of verification emails to override and switch off the Security Admin restrictions.', 'wp-simple-firewall' )
155
- .'<br/>'.sprintf( __( "The email address specified in %s's General settings will be used.", 'wp-simple-firewall' ), $sPlugName );
 
 
 
 
 
 
 
 
 
 
 
 
 
156
  break;
157
 
158
  case 'admin_access_restrict_posts' :
159
  $name = __( 'Pages', 'wp-simple-firewall' );
160
  $summary = __( 'Restrict Access To Key WordPress Posts And Pages Actions', 'wp-simple-firewall' );
161
- $description = sprintf( '%s: %s', __( 'Careful', 'wp-simple-firewall' ), __( 'This will restrict access to page/post creation, editing and deletion.', 'wp-simple-firewall' ) )
162
- .'<br />'.sprintf( '%s: %s', __( 'Note', 'wp-simple-firewall' ), sprintf( __( 'Selecting "%s" will also restrict all other options.', 'wp-simple-firewall' ), __( 'Edit', 'wp-simple-firewall' ) ) );
163
  break;
164
 
165
  case 'admin_access_restrict_plugins' :
166
  $name = __( 'Plugins', 'wp-simple-firewall' );
167
  $summary = __( 'Restrict Access To Key WordPress Plugin Actions', 'wp-simple-firewall' );
168
- $description = sprintf( '%s: %s', __( 'Careful', 'wp-simple-firewall' ), __( 'This will restrict access to plugin installation, update, activation and deletion.', 'wp-simple-firewall' ) )
169
- .'<br />'.sprintf( '%s: %s', __( 'Note', 'wp-simple-firewall' ), sprintf( __( 'Selecting "%s" will also restrict all other options.', 'wp-simple-firewall' ), __( 'Activate', 'wp-simple-firewall' ) ) );
170
  break;
171
 
172
  case 'admin_access_restrict_options' :
173
  $name = __( 'WordPress Options', 'wp-simple-firewall' );
174
  $summary = __( 'Restrict Access To Certain WordPress Admin Options', 'wp-simple-firewall' );
175
- $description = sprintf( '%s: %s', __( 'Careful', 'wp-simple-firewall' ), __( 'This will restrict the ability of WordPress administrators from changing key WordPress settings.', 'wp-simple-firewall' ) );
176
  break;
177
 
178
  case 'admin_access_restrict_admin_users' :
179
  $name = __( 'Admin Users', 'wp-simple-firewall' );
180
  $summary = __( 'Restrict Access To Create/Delete/Modify Other Admin Users', 'wp-simple-firewall' );
181
- $description = sprintf( '%s: %s', __( 'Careful', 'wp-simple-firewall' ), __( 'This will restrict the ability of WordPress administrators from creating, modifying or promoting other administrators.', 'wp-simple-firewall' ) );
182
  break;
183
 
184
  case 'admin_access_restrict_themes' :
185
  $name = __( 'Themes', 'wp-simple-firewall' );
186
  $summary = __( 'Restrict Access To WordPress Theme Actions', 'wp-simple-firewall' );
187
- $description = sprintf( '%s: %s', __( 'Careful', 'wp-simple-firewall' ), __( 'This will restrict access to theme installation, update, activation and deletion.', 'wp-simple-firewall' ) )
188
- .'<br />'.
189
- sprintf( '%s: %s',
190
- __( 'Note', 'wp-simple-firewall' ),
191
- sprintf(
192
- __( 'Selecting "%s" will also restrict all other options.', 'wp-simple-firewall' ),
193
- sprintf(
194
- __( '%s and %s', 'wp-simple-firewall' ),
195
- __( 'Activate', 'wp-simple-firewall' ),
196
- __( 'Edit Theme Options', 'wp-simple-firewall' )
197
- )
198
- )
199
- );
200
  break;
201
 
202
  case 'whitelabel_enable' :
203
  $name = sprintf( '%s: %s', __( 'Enable', 'wp-simple-firewall' ), __( 'White Label', 'wp-simple-firewall' ) );
204
  $summary = __( 'Activate Your White Label Settings', 'wp-simple-firewall' );
205
- $description = __( 'Turn your White Label settings on/off.', 'wp-simple-firewall' );
206
  break;
207
  case 'wl_hide_updates' :
208
  $name = __( 'Hide Updates', 'wp-simple-firewall' );
209
  $summary = __( 'Hide Plugin Updates From Non-Security Admins', 'wp-simple-firewall' );
210
- $description = sprintf( __( 'Hide available %s updates from non-security administrators.', 'wp-simple-firewall' ), $sPlugName );
211
  break;
212
  case 'wl_pluginnamemain' :
213
  $name = __( 'Plugin Name', 'wp-simple-firewall' );
214
  $summary = __( 'The Name Of The Plugin', 'wp-simple-firewall' );
215
- $description = __( 'The name of the plugin that will be displayed to your site users.', 'wp-simple-firewall' );
216
  break;
217
  case 'wl_replace_badge_url' :
218
  $name = __( 'Replace Plugin Badge', 'wp-simple-firewall' );
219
  $summary = __( 'Replace Plugin Badge URL and Images', 'wp-simple-firewall' );
220
- $description = __( 'When using the plugin badge, replace the URL and link with your Whitelabel settings.', 'wp-simple-firewall' );
221
  break;
222
  case 'wl_namemenu' :
223
  $name = __( 'Menu Title', 'wp-simple-firewall' );
224
  $summary = __( 'The Main Menu Title Of The Plugin', 'wp-simple-firewall' );
225
- $description = sprintf( __( 'The Main Menu Title Of The Plugin. If left empty, the "%s" will be used.', 'wp-simple-firewall' ), __( 'Plugin Name', 'wp-simple-firewall' ) );
226
  break;
227
  case 'wl_companyname' :
228
  $name = __( 'Company Name', 'wp-simple-firewall' );
229
  $summary = __( 'The Name Of Your Company', 'wp-simple-firewall' );
230
- $description = __( 'Provide the name of your company.', 'wp-simple-firewall' );
231
  break;
232
  case 'wl_description' :
233
  $name = __( 'Description', 'wp-simple-firewall' );
234
  $summary = __( 'The Description Of The Plugin', 'wp-simple-firewall' );
235
- $description = __( 'The description of the plugin displayed on the plugins page.', 'wp-simple-firewall' );
236
  break;
237
  case 'wl_homeurl' :
238
  $name = __( 'Home URL', 'wp-simple-firewall' );
239
  $summary = __( 'Plugin Home Page URL', 'wp-simple-firewall' );
240
- $description = __( "When a user clicks the home link for this plugin, this is where they'll be directed.", 'wp-simple-firewall' );
241
  break;
242
  case 'wl_menuiconurl' :
243
  $name = __( 'Menu Icon', 'wp-simple-firewall' );
244
  $summary = __( 'Menu Icon URL', 'wp-simple-firewall' );
245
- $description = __( 'The URL of the icon to display in the menu.', 'wp-simple-firewall' )
246
- .' '.sprintf( __( 'The %s should measure %s.', 'wp-simple-firewall' ), __( 'icon', 'wp-simple-firewall' ), '16px x 16px' );
247
  break;
248
  case 'wl_dashboardlogourl' :
249
  $name = __( 'Plugin Badge Logo', 'wp-simple-firewall' );
250
  $summary = __( 'Plugin Badge Logo URL', 'wp-simple-firewall' );
251
- $description = __( 'The URL of the logo to display in the plugin badge.', 'wp-simple-firewall' )
252
- .' '.sprintf( __( 'The %s should measure %s.', 'wp-simple-firewall' ), __( 'logo', 'wp-simple-firewall' ), '128px x 128px' );
253
  break;
254
  case 'wl_login2fa_logourl' :
255
  $name = __( 'Dashboard and 2FA Login Logo URL', 'wp-simple-firewall' );
256
  $summary = __( 'Dashboard and 2FA Login Logo URL', 'wp-simple-firewall' );
257
- $description = __( 'The URL of the logo to display on the Dashboard and the Two-Factor Authentication login page.', 'wp-simple-firewall' );
258
  break;
259
 
260
  default:
@@ -264,7 +273,7 @@ class Strings extends Base\Strings {
264
  return [
265
  'name' => $name,
266
  'summary' => $summary,
267
- 'description' => $description,
268
  ];
269
  }
270
  }
11
  */
12
  public function getEventStrings() :array {
13
  return [
14
+ 'key_success' => [
15
  'name' => __( 'Security PIN Pass', 'wp-simple-firewall' ),
16
  'audit' => [
17
  __( 'Security PIN authentication successful.', 'wp-simple-firewall' ),
27
  }
28
 
29
  /**
30
+ * @inheritDoc
 
 
31
  */
32
  public function getSectionStrings( string $section ) :array {
33
  $sPlugName = $this->getCon()->getHumanName();
91
  }
92
 
93
  /**
94
+ * @inheritDoc
 
 
95
  */
96
  public function getOptionStrings( string $key ) :array {
97
  /** @var Options $opts */
103
  case 'enable_admin_access_restriction' :
104
  $name = sprintf( __( 'Enable %s Module', 'wp-simple-firewall' ), __( 'Security Admin', 'wp-simple-firewall' ) );
105
  $summary = __( 'Enforce Security Admin Access Restriction', 'wp-simple-firewall' );
106
+ $desc = __( "Enable this with great care and consideration. Ensure that you set an Security PIN that you'll remember.", 'wp-simple-firewall' );
107
  break;
108
 
109
  case 'admin_access_key' :
110
  $name = __( 'Security Admin PIN', 'wp-simple-firewall' );
111
  $summary = __( 'Provide/Update Security Admin PIN', 'wp-simple-firewall' );
112
+ $desc = [
113
  sprintf( '%s: %s', __( 'Careful', 'wp-simple-firewall' ), __( 'If you forget this, you could potentially lock yourself out from using this plugin.', 'wp-simple-firewall' ) ),
114
  '<strong>'.( $opts->hasSecurityPIN() ? __( 'Security PIN Currently Set', 'wp-simple-firewall' ) : __( 'Security PIN NOT Currently Set', 'wp-simple-firewall' ) ).'</strong>',
115
  ];
116
  if ( $opts->hasSecurityPIN() ) {
117
+ $desc[] = sprintf( __( 'To delete the current security PIN, type exactly "%s" and save.', 'wp-simple-firewall' ), '<strong>DELETE</strong>' );
118
  if ( !empty( $opts->getSecurityAdminUsers() ) ) {
119
+ $desc[] = sprintf( '%s: %s', __( 'Important', 'wp-simple-firewall' ), __( 'Deleting the PIN will also remove security admin users.', 'wp-simple-firewall' ) );
120
  }
121
  }
122
 
125
  case 'sec_admin_users' :
126
  $name = __( 'Security Admins', 'wp-simple-firewall' );
127
  $summary = __( 'Persistent Security Admins', 'wp-simple-firewall' );
128
+ $desc = [
129
  __( "Users provided will be security admins automatically, without needing the security PIN.", 'wp-simple-firewall' ),
130
  __( 'Enter admin username, email or ID.', 'wp-simple-firewall' ).' '.__( '1 entry per-line.', 'wp-simple-firewall' ),
131
  sprintf( '%s: %s', __( 'Note', 'wp-simple-firewall' ), __( 'Verified users will be converted to usernames.', 'wp-simple-firewall' ) )
135
  case 'admin_access_timeout' :
136
  $name = __( 'Security Admin Timeout', 'wp-simple-firewall' );
137
  $summary = __( 'Specify An Automatic Timeout Interval For Security Admin Access', 'wp-simple-firewall' );
138
+ $desc = __( 'This will automatically expire your Security Admin Session.', 'wp-simple-firewall' )
139
+ .'<br />'
140
+ .sprintf(
141
+ '%s: %s',
142
+ __( 'Default', 'wp-simple-firewall' ),
143
+ sprintf( '%s minutes', $opts->getOptDefault( 'admin_access_timeout' ) )
144
+ );
145
  break;
146
 
147
  case 'allow_email_override' :
148
  $name = __( 'Allow Email Override', 'wp-simple-firewall' );
149
  $summary = __( 'Allow Email Override Of Admin Access Restrictions', 'wp-simple-firewall' );
150
+ $desc = [
151
+ __( 'Allow the use of verification emails to override and switch off the Security Admin restrictions.', 'wp-simple-firewall' ),
152
+ sprintf( __( "The email address specified in %s's General settings will be used.", 'wp-simple-firewall' ), $sPlugName )
153
+ ];
154
+ break;
155
+
156
+ case 'enable_mu' :
157
+ $name = __( 'Run In MU Mode', 'wp-simple-firewall' );
158
+ $summary = __( 'Run Plugin In Must-Use (MU) Mode', 'wp-simple-firewall' );
159
+ $desc = [
160
+ __( "Setup the plugin to run as an MU-plugin to prevent accidental deactivation.", 'wp-simple-firewall' ),
161
+ __( "You should fully understand the implications of this, including the inability to deactivate the plugin from the WordPress dashboard while this setting is active.", 'wp-simple-firewall' ),
162
+ sprintf( '<strong>%s</strong>: %s', __( 'Important', 'wp-simple-firewall' ),
163
+ sprintf( __( 'WordPress must be at least version %s to activate this option.', 'wp-simple-firewall' ), '<code>5.6</code>' ) ),
164
+ ];
165
  break;
166
 
167
  case 'admin_access_restrict_posts' :
168
  $name = __( 'Pages', 'wp-simple-firewall' );
169
  $summary = __( 'Restrict Access To Key WordPress Posts And Pages Actions', 'wp-simple-firewall' );
170
+ $desc = sprintf( '%s: %s', __( 'Careful', 'wp-simple-firewall' ), __( 'This will restrict access to page/post creation, editing and deletion.', 'wp-simple-firewall' ) )
171
+ .'<br />'.sprintf( '%s: %s', __( 'Note', 'wp-simple-firewall' ), sprintf( __( 'Selecting "%s" will also restrict all other options.', 'wp-simple-firewall' ), __( 'Edit', 'wp-simple-firewall' ) ) );
172
  break;
173
 
174
  case 'admin_access_restrict_plugins' :
175
  $name = __( 'Plugins', 'wp-simple-firewall' );
176
  $summary = __( 'Restrict Access To Key WordPress Plugin Actions', 'wp-simple-firewall' );
177
+ $desc = sprintf( '%s: %s', __( 'Careful', 'wp-simple-firewall' ), __( 'This will restrict access to plugin installation, update, activation and deletion.', 'wp-simple-firewall' ) )
178
+ .'<br />'.sprintf( '%s: %s', __( 'Note', 'wp-simple-firewall' ), sprintf( __( 'Selecting "%s" will also restrict all other options.', 'wp-simple-firewall' ), __( 'Activate', 'wp-simple-firewall' ) ) );
179
  break;
180
 
181
  case 'admin_access_restrict_options' :
182
  $name = __( 'WordPress Options', 'wp-simple-firewall' );
183
  $summary = __( 'Restrict Access To Certain WordPress Admin Options', 'wp-simple-firewall' );
184
+ $desc = sprintf( '%s: %s', __( 'Careful', 'wp-simple-firewall' ), __( 'This will restrict the ability of WordPress administrators from changing key WordPress settings.', 'wp-simple-firewall' ) );
185
  break;
186
 
187
  case 'admin_access_restrict_admin_users' :
188
  $name = __( 'Admin Users', 'wp-simple-firewall' );
189
  $summary = __( 'Restrict Access To Create/Delete/Modify Other Admin Users', 'wp-simple-firewall' );
190
+ $desc = sprintf( '%s: %s', __( 'Careful', 'wp-simple-firewall' ), __( 'This will restrict the ability of WordPress administrators from creating, modifying or promoting other administrators.', 'wp-simple-firewall' ) );
191
  break;
192
 
193
  case 'admin_access_restrict_themes' :
194
  $name = __( 'Themes', 'wp-simple-firewall' );
195
  $summary = __( 'Restrict Access To WordPress Theme Actions', 'wp-simple-firewall' );
196
+ $desc = sprintf( '%s: %s', __( 'Careful', 'wp-simple-firewall' ), __( 'This will restrict access to theme installation, update, activation and deletion.', 'wp-simple-firewall' ) )
197
+ .'<br />'.
198
+ sprintf( '%s: %s',
199
+ __( 'Note', 'wp-simple-firewall' ),
200
+ sprintf(
201
+ __( 'Selecting "%s" will also restrict all other options.', 'wp-simple-firewall' ),
202
+ sprintf(
203
+ __( '%s and %s', 'wp-simple-firewall' ),
204
+ __( 'Activate', 'wp-simple-firewall' ),
205
+ __( 'Edit Theme Options', 'wp-simple-firewall' )
206
+ )
207
+ )
208
+ );
209
  break;
210
 
211
  case 'whitelabel_enable' :
212
  $name = sprintf( '%s: %s', __( 'Enable', 'wp-simple-firewall' ), __( 'White Label', 'wp-simple-firewall' ) );
213
  $summary = __( 'Activate Your White Label Settings', 'wp-simple-firewall' );
214
+ $desc = __( 'Turn your White Label settings on/off.', 'wp-simple-firewall' );
215
  break;
216
  case 'wl_hide_updates' :
217
  $name = __( 'Hide Updates', 'wp-simple-firewall' );
218
  $summary = __( 'Hide Plugin Updates From Non-Security Admins', 'wp-simple-firewall' );
219
+ $desc = sprintf( __( 'Hide available %s updates from non-security administrators.', 'wp-simple-firewall' ), $sPlugName );
220
  break;
221
  case 'wl_pluginnamemain' :
222
  $name = __( 'Plugin Name', 'wp-simple-firewall' );
223
  $summary = __( 'The Name Of The Plugin', 'wp-simple-firewall' );
224
+ $desc = __( 'The name of the plugin that will be displayed to your site users.', 'wp-simple-firewall' );
225
  break;
226
  case 'wl_replace_badge_url' :
227
  $name = __( 'Replace Plugin Badge', 'wp-simple-firewall' );
228
  $summary = __( 'Replace Plugin Badge URL and Images', 'wp-simple-firewall' );
229
+ $desc = __( 'When using the plugin badge, replace the URL and link with your Whitelabel settings.', 'wp-simple-firewall' );
230
  break;
231
  case 'wl_namemenu' :
232
  $name = __( 'Menu Title', 'wp-simple-firewall' );
233
  $summary = __( 'The Main Menu Title Of The Plugin', 'wp-simple-firewall' );
234
+ $desc = sprintf( __( 'The Main Menu Title Of The Plugin. If left empty, the "%s" will be used.', 'wp-simple-firewall' ), __( 'Plugin Name', 'wp-simple-firewall' ) );
235
  break;
236
  case 'wl_companyname' :
237
  $name = __( 'Company Name', 'wp-simple-firewall' );
238
  $summary = __( 'The Name Of Your Company', 'wp-simple-firewall' );
239
+ $desc = __( 'Provide the name of your company.', 'wp-simple-firewall' );
240
  break;
241
  case 'wl_description' :
242
  $name = __( 'Description', 'wp-simple-firewall' );
243
  $summary = __( 'The Description Of The Plugin', 'wp-simple-firewall' );
244
+ $desc = __( 'The description of the plugin displayed on the plugins page.', 'wp-simple-firewall' );
245
  break;
246
  case 'wl_homeurl' :
247
  $name = __( 'Home URL', 'wp-simple-firewall' );
248
  $summary = __( 'Plugin Home Page URL', 'wp-simple-firewall' );
249
+ $desc = __( "When a user clicks the home link for this plugin, this is where they'll be directed.", 'wp-simple-firewall' );
250
  break;
251
  case 'wl_menuiconurl' :
252
  $name = __( 'Menu Icon', 'wp-simple-firewall' );
253
  $summary = __( 'Menu Icon URL', 'wp-simple-firewall' );
254
+ $desc = __( 'The URL of the icon to display in the menu.', 'wp-simple-firewall' )
255
+ .' '.sprintf( __( 'The %s should measure %s.', 'wp-simple-firewall' ), __( 'icon', 'wp-simple-firewall' ), '16px x 16px' );
256
  break;
257
  case 'wl_dashboardlogourl' :
258
  $name = __( 'Plugin Badge Logo', 'wp-simple-firewall' );
259
  $summary = __( 'Plugin Badge Logo URL', 'wp-simple-firewall' );
260
+ $desc = __( 'The URL of the logo to display in the plugin badge.', 'wp-simple-firewall' )
261
+ .' '.sprintf( __( 'The %s should measure %s.', 'wp-simple-firewall' ), __( 'logo', 'wp-simple-firewall' ), '128px x 128px' );
262
  break;
263
  case 'wl_login2fa_logourl' :
264
  $name = __( 'Dashboard and 2FA Login Logo URL', 'wp-simple-firewall' );
265
  $summary = __( 'Dashboard and 2FA Login Logo URL', 'wp-simple-firewall' );
266
+ $desc = __( 'The URL of the logo to display on the Dashboard and the Two-Factor Authentication login page.', 'wp-simple-firewall' );
267
  break;
268
 
269
  default:
273
  return [
274
  'name' => $name,
275
  'summary' => $summary,
276
+ 'description' => $desc,
277
  ];
278
  }
279
  }
src/lib/src/Modules/Traffic/Lib/LogHandlers/LocalDbWriter.php CHANGED
@@ -2,9 +2,9 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Traffic\Lib\LogHandlers;
4
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\DB\ReqLogs;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\DB\IPs\IPRecords;
8
  use Monolog\Handler\AbstractProcessingHandler;
9
 
10
  class LocalDbWriter extends AbstractProcessingHandler {
@@ -37,16 +37,25 @@ class LocalDbWriter extends AbstractProcessingHandler {
37
  unset( $logData[ 'extra' ][ 'meta_request' ][ 'ip' ] );
38
  unset( $logData[ 'extra' ][ 'meta_request' ][ 'rid' ] );
39
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  $success = $modData->getDbH_ReqLogs()
41
  ->getQueryUpdater()
42
- ->updateById( $reqRecord->id, [
43
- 'meta' => base64_encode( json_encode( array_merge(
44
- $logData[ 'extra' ][ 'meta_shield' ],
45
- $logData[ 'extra' ][ 'meta_request' ],
46
- $logData[ 'extra' ][ 'meta_user' ],
47
- $logData[ 'extra' ][ 'meta_wp' ]
48
- ) ) )
49
- ] );
50
 
51
  if ( !$success ) {
52
  throw new \Exception( 'Failed to insert' );
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Traffic\Lib\LogHandlers;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\DB\IPs\IPRecords;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\DB\ReqLogs;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
 
8
  use Monolog\Handler\AbstractProcessingHandler;
9
 
10
  class LocalDbWriter extends AbstractProcessingHandler {
37
  unset( $logData[ 'extra' ][ 'meta_request' ][ 'ip' ] );
38
  unset( $logData[ 'extra' ][ 'meta_request' ][ 'rid' ] );
39
 
40
+ $meta = array_merge(
41
+ $logData[ 'extra' ][ 'meta_shield' ],
42
+ $logData[ 'extra' ][ 'meta_request' ],
43
+ $logData[ 'extra' ][ 'meta_user' ],
44
+ $logData[ 'extra' ][ 'meta_wp' ]
45
+ );
46
+
47
+ $updateData = [];
48
+ foreach ( [ 'verb', 'code', 'path', 'type' ] as $item ) {
49
+ if ( !empty( $meta[ $item ] ) ) {
50
+ $updateData[ $item ] = $meta[ $item ];
51
+ unset( $meta[ $item ] );
52
+ }
53
+ }
54
+ $updateData[ 'meta' ] = base64_encode( json_encode( $meta ) );
55
+
56
  $success = $modData->getDbH_ReqLogs()
57
  ->getQueryUpdater()
58
+ ->updateById( $reqRecord->id, $updateData );
 
 
 
 
 
 
 
59
 
60
  if ( !$success ) {
61
  throw new \Exception( 'Failed to insert' );
src/lib/src/Modules/Traffic/Lib/RequestLogger.php CHANGED
@@ -1,10 +1,10 @@
1
- <?php
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Traffic\Lib;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Logging\Processors;
6
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\Traffic;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
 
8
  use FernleafSystems\Wordpress\Services\Services;
9
  use FernleafSystems\Wordpress\Services\Utilities\Net\IpID;
10
  use Monolog\Logger;
@@ -20,6 +20,8 @@ class RequestLogger extends ExecOnceModConsumer {
20
  $this->getLogger()
21
  ->pushHandler( ( new LogHandlers\LocalDbWriter() )->setMod( $this->getMod() ) );
22
 
 
 
23
  add_action( $this->getCon()->prefix( 'plugin_shutdown' ), function () {
24
  if ( $this->isRequestToBeLogged() ) {
25
  $this->getLogger()->log( 'debug', 'log request' );
@@ -27,13 +29,21 @@ class RequestLogger extends ExecOnceModConsumer {
27
  }, 1000 ); // high enough to come after audit trail
28
  }
29
 
 
 
 
 
 
 
 
 
 
 
30
  private function isRequestToBeLogged() :bool {
31
  /** @var Traffic\Options $opts */
32
  $opts = $this->getOptions();
33
  return !$this->getCon()->plugin_deleting
34
- && apply_filters( 'shield/is_log_traffic',
35
- $opts->isTrafficLoggerEnabled() && !$this->isCustomExcluded() && !$this->isRequestTypeExcluded()
36
- );
37
  }
38
 
39
  public function getLogger() :Logger {
@@ -49,6 +59,8 @@ class RequestLogger extends ExecOnceModConsumer {
49
  }
50
 
51
  private function isRequestTypeExcluded() :bool {
 
 
52
  /** @var Traffic\Options $opts */
53
  $opts = $this->getOptions();
54
  $excl = $opts->getReqTypeExclusions();
@@ -58,11 +70,11 @@ class RequestLogger extends ExecOnceModConsumer {
58
  || ( in_array( 'logged_in', $excl ) && $isLoggedIn )
59
  || ( in_array( 'ajax', $excl ) && Services::WpGeneral()->isAjax() )
60
  || ( in_array( 'cron', $excl ) && Services::WpGeneral()->isCron() )
61
- || ( in_array( 'server', $excl ) && $this->isThisServer() );
62
 
63
  if ( !$exclude && !$isLoggedIn ) {
64
- $exclude = ( in_array( 'search', $excl ) && $this->isServiceIp_Search() )
65
- || ( in_array( 'uptime', $excl ) && $this->isServiceIp_Uptime() );
66
  }
67
 
68
  return $exclude;
@@ -85,16 +97,25 @@ class RequestLogger extends ExecOnceModConsumer {
85
  return $exclude;
86
  }
87
 
 
 
 
88
  private function isServiceIp_Search() :bool {
89
  return in_array( Services::IP()->getIpDetector()->getIPIdentity(),
90
  Services::ServiceProviders()->getSearchProviders() );
91
  }
92
 
 
 
 
93
  private function isServiceIp_Uptime() :bool {
94
- return in_array( Services::IP()->getIpDetector()->getIPIdentity(),
95
- Services::ServiceProviders()->getUptimeProviders() );
96
  }
97
 
 
 
 
98
  private function isThisServer() :bool {
99
  return Services::IP()->getIpDetector()->getIPIdentity() === IpID::THIS_SERVER;
100
  }
1
+ <?php declare( strict_types=1 );
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Traffic\Lib;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Logging\Processors;
 
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Traffic;
8
  use FernleafSystems\Wordpress\Services\Services;
9
  use FernleafSystems\Wordpress\Services\Utilities\Net\IpID;
10
  use Monolog\Logger;
20
  $this->getLogger()
21
  ->pushHandler( ( new LogHandlers\LocalDbWriter() )->setMod( $this->getMod() ) );
22
 
23
+ $this->pushCustomHandlers();
24
+
25
  add_action( $this->getCon()->prefix( 'plugin_shutdown' ), function () {
26
  if ( $this->isRequestToBeLogged() ) {
27
  $this->getLogger()->log( 'debug', 'log request' );
29
  }, 1000 ); // high enough to come after audit trail
30
  }
31
 
32
+ private function pushCustomHandlers() {
33
+ $custom = apply_filters( 'shield/custom_request_log_handlers', [] );
34
+ array_map(
35
+ function ( $handler ) {
36
+ $this->getLogger()->pushHandler( $handler );
37
+ },
38
+ ( $this->getCon()->isPremiumActive() && is_array( $custom ) ) ? $custom : []
39
+ );
40
+ }
41
+
42
  private function isRequestToBeLogged() :bool {
43
  /** @var Traffic\Options $opts */
44
  $opts = $this->getOptions();
45
  return !$this->getCon()->plugin_deleting
46
+ && apply_filters( 'shield/is_log_traffic', $opts->isTrafficLoggerEnabled() && !$this->isCustomExcluded() && !$this->isRequestTypeExcluded() );
 
 
47
  }
48
 
49
  public function getLogger() :Logger {
59
  }
60
 
61
  private function isRequestTypeExcluded() :bool {
62
+ $srvProviders = Services::ServiceProviders();
63
+ $ipIdentity = Services::IP()->getIpDetector()->getIPIdentity();
64
  /** @var Traffic\Options $opts */
65
  $opts = $this->getOptions();
66
  $excl = $opts->getReqTypeExclusions();
70
  || ( in_array( 'logged_in', $excl ) && $isLoggedIn )
71
  || ( in_array( 'ajax', $excl ) && Services::WpGeneral()->isAjax() )
72
  || ( in_array( 'cron', $excl ) && Services::WpGeneral()->isCron() )
73
+ || ( in_array( 'server', $excl ) && $ipIdentity === IpID::THIS_SERVER );
74
 
75
  if ( !$exclude && !$isLoggedIn ) {
76
+ $exclude = ( in_array( 'search', $excl ) && in_array( $ipIdentity, $srvProviders->getSearchProviders() ) )
77
+ || ( in_array( 'uptime', $excl ) && in_array( $ipIdentity, $srvProviders->getUptimeProviders() ) );
78
  }
79
 
80
  return $exclude;
97
  return $exclude;
98
  }
99
 
100
+ /**
101
+ * @deprecated 14.1
102
+ */
103
  private function isServiceIp_Search() :bool {
104
  return in_array( Services::IP()->getIpDetector()->getIPIdentity(),
105
  Services::ServiceProviders()->getSearchProviders() );
106
  }
107
 
108
+ /**
109
+ * @deprecated 14.1
110
+ */
111
  private function isServiceIp_Uptime() :bool {
112
+ $IP = Services::IP();
113
+ return in_array( $IP->getIpDetector()->getIPIdentity(), Services::ServiceProviders()->getUptimeProviders() );
114
  }
115
 
116
+ /**
117
+ * @deprecated 14.1
118
+ */
119
  private function isThisServer() :bool {
120
  return Services::IP()->getIpDetector()->getIPIdentity() === IpID::THIS_SERVER;
121
  }
src/lib/src/Modules/Traffic/Lib/TrafficTable/BuildSearchPanesData.php ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Traffic\Lib\TrafficTable;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\DB\ReqLogs\Ops\Handler;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\ModCon;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
8
+ use FernleafSystems\Wordpress\Services\Services;
9
+
10
+ class BuildSearchPanesData {
11
+
12
+ use ModConsumer;
13
+
14
+ public function build() :array {
15
+ return [
16
+ 'options' => [
17
+ 'ip' => $this->buildForIPs(),
18
+ 'type' => $this->buildForType(),
19
+ 'offense' => $this->buildForOffense(),
20
+ 'code' => $this->buildForCodes(),
21
+ ]
22
+ ];
23
+ }
24
+
25
+ private function buildForCodes() :array {
26
+ $results = $this->runQuery( 'code as code', false );
27
+ return array_filter( array_map(
28
+ function ( $result ) {
29
+ $code = $result[ 'code' ] ?? null;
30
+ if ( !empty( $code ) ) {
31
+ $code = [
32
+ 'label' => $code,
33
+ 'value' => $code,
34
+ ];
35
+ }
36
+ return $code;
37
+ },
38
+ $results
39
+ ) );
40
+ }
41
+
42
+ private function buildForOffense() :array {
43
+ return [
44
+ [
45
+ 'label' => __( 'Offense', 'wp-simple-firewall' ),
46
+ 'value' => 1,
47
+ ],
48
+ [
49
+ 'label' => __( 'Not Offense', 'wp-simple-firewall' ),
50
+ 'value' => 0,
51
+ ]
52
+ ];
53
+ }
54
+
55
+ private function buildForType() :array {
56
+ $results = $this->runQuery( 'type as type', false );
57
+ return array_filter( array_map(
58
+ function ( $result ) {
59
+ $type = $result[ 'type' ] ?? null;
60
+ if ( !empty( $type ) ) {
61
+ $type = [
62
+ 'label' => Handler::GetTypeName( $type ),
63
+ 'value' => $type,
64
+ ];
65
+ }
66
+ return $type;
67
+ },
68
+ $results
69
+ ) );
70
+ }
71
+
72
+ private function buildForIPs() :array {
73
+ $results = $this->runQuery( 'INET6_NTOA(ips.ip) as ip', true );
74
+ return array_filter( array_map(
75
+ function ( $result ) {
76
+ $ip = $result[ 'ip' ] ?? null;
77
+ if ( !empty( $ip ) ) {
78
+ $ip = [
79
+ 'label' => $ip,
80
+ 'value' => $ip,
81
+ ];
82
+ }
83
+ return $ip;
84
+ },
85
+ $results
86
+ ) );
87
+ }
88
+
89
+ private function runQuery( string $select, bool $joinWithIPs ) :array {
90
+ /** @var ModCon $mod */
91
+ $mod = $this->getMod();
92
+ $results = Services::WpDb()->selectCustom(
93
+ sprintf( 'SELECT DISTINCT %s
94
+ FROM `%s` as `req`
95
+ %s;',
96
+ $select,
97
+ $mod->getDbH_ReqLogs()->getTableSchema()->table,
98
+ $joinWithIPs ? sprintf( 'INNER JOIN `%s` as ips ON ips.id = req.ip_ref',
99
+ $mod->getDbH_IPs()->getTableSchema()->table ) : ''
100
+
101
+ )
102
+ );
103
+ return is_array( $results ) ? $results : [];
104
+ }
105
+ }
src/lib/src/Modules/Traffic/Lib/TrafficTable/BuildTrafficTableData.php ADDED
@@ -0,0 +1,277 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Traffic\Lib\TrafficTable;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\DB\IPs\IPGeoVO;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\DB\ReqLogs\LoadLogs;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\DB\ReqLogs\LogRecord;
8
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\DB\ReqLogs\Ops\Handler;
9
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\Lib\GeoIP\Lookup;
10
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Ops\LookupIpOnList;
11
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\ModCon;
12
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
13
+ use FernleafSystems\Wordpress\Plugin\Shield\Tables\DataTables\Build\Traffic\ForTraffic;
14
+ use FernleafSystems\Wordpress\Plugin\Shield\Tables\DataTables\LoadData\BaseBuildTableData;
15
+ use FernleafSystems\Wordpress\Services\Services;
16
+
17
+ class BuildTrafficTableData extends BaseBuildTableData {
18
+
19
+ use ModConsumer;
20
+
21
+ /**
22
+ * @var LogRecord
23
+ */
24
+ private $log;
25
+
26
+ /**
27
+ * @var Lookup
28
+ */
29
+ private $geoLookup;
30
+
31
+ private $users = [];
32
+
33
+ private $ipInfo = [];
34
+
35
+ protected function getSearchPanesData() :array {
36
+ return ( new BuildSearchPanesData() )
37
+ ->setMod( $this->getCon()->getModule_Data() )
38
+ ->build();
39
+ }
40
+
41
+ /**
42
+ * @param LogRecord[] $records
43
+ */
44
+ protected function buildTableRowsFromRawLogs( array $records ) :array {
45
+ $this->users = [ 0 => __( 'No', 'wp-simple-firewall' ) ];
46
+
47
+ return array_values( array_filter( array_map(
48
+ function ( $log ) {
49
+ $WPU = Services::WpUsers();
50
+
51
+ $log->meta = array_merge(
52
+ [
53
+ 'ua' => 'Unknown',
54
+ 'offense' => false,
55
+ 'uid' => 0
56
+ ],
57
+ $log->meta
58
+ );
59
+
60
+ $this->log = $log;
61
+
62
+ $data = $log->getRawData();
63
+
64
+ $data[ 'ip' ] = $this->log->ip;
65
+ $data[ 'code' ] = $this->log->code;
66
+ $data[ 'offense' ] = $this->log->offense ? 'Offense' : 'Not Offense';
67
+ $data[ 'rid' ] = $this->log->rid ?? __( 'Unknown', 'wp-simple-firewall' );
68
+ $data[ 'path' ] = empty( $this->log->path ) ? '-' : $this->log->path;
69
+
70
+ $geo = $this->getCountryIP( $this->log->ip );
71
+ $data[ 'country' ] = empty( $geo->countryCode ) ?
72
+ __( 'Unknown', 'wp-simple-firewall' ) : $geo->countryName;
73
+
74
+ $userID = $this->log->meta[ 'uid' ] ?? 0;
75
+ if ( $userID > 0 ) {
76
+ if ( !isset( $users[ $userID ] ) ) {
77
+ $user = $WPU->getUserById( $userID );
78
+ $this->users[ $userID ] = empty( $user ) ? __( 'Unknown', 'wp-simple-firewall' ) :
79
+ sprintf( '<a href="%s" target="_blank" title="Go To Profile">%s</a>',
80
+ $WPU->getAdminUrl_ProfileEdit( $user ), $user->user_login );
81
+ }
82
+ }
83
+
84
+ $data[ 'page' ] = $this->getColumnContent_Page();
85
+ $data[ 'details' ] = $this->getColumnContent_Details();
86
+ $data[ 'response' ] = $this->getColumnContent_Response();
87
+ $data[ 'created_since' ] = $this->getColumnContent_Date( $this->log->created_at );
88
+ return $data;
89
+ },
90
+ $records
91
+ ) ) );
92
+ }
93
+
94
+ protected function countTotalRecords() :int {
95
+ return $this->getRecordsLoader()->countAll();
96
+ }
97
+
98
+ protected function countTotalRecordsFiltered() :int {
99
+ $loader = $this->getRecordsLoader();
100
+ $loader->wheres = $this->buildWheresFromSearchPanes();
101
+ return $loader->countAll();
102
+ }
103
+
104
+ /**
105
+ * The Wheres need to align with the structure of the Query called from getRecords()
106
+ */
107
+ protected function buildWheresFromSearchPanes() :array {
108
+ $wheres = [];
109
+ if ( !empty( $this->table_data[ 'searchPanes' ] ) ) {
110
+ foreach ( array_filter( $this->table_data[ 'searchPanes' ] ) as $column => $selected ) {
111
+ switch ( $column ) {
112
+ case 'ip':
113
+ $wheres[] = sprintf( "`ips`.ip=INET6_ATON('%s')", array_pop( $selected ) );
114
+ break;
115
+ case 'offense':
116
+ case 'type':
117
+ case 'code':
118
+ $wheres[] = sprintf( "`req`.%s IN ('%s')", $column, implode( "','", $selected ) );
119
+ break;
120
+ default:
121
+ break;
122
+ }
123
+ }
124
+ }
125
+ return $wheres;
126
+ }
127
+
128
+ protected function getRecordsLoader() :LoadLogs {
129
+ return ( new LoadLogs() )->setMod( $this->getCon()->getModule_Data() );
130
+ }
131
+
132
+ protected function getSearchableColumns() :array {
133
+ // Use the DataTables definition builder to locate searchable columns
134
+ return array_filter( array_map(
135
+ function ( $column ) {
136
+ return ( $column[ 'searchable' ] ?? false ) ? $column[ 'data' ] : '';
137
+ },
138
+ ( new ForTraffic() )
139
+ ->setMod( $this->getMod() )
140
+ ->buildRaw()[ 'columns' ]
141
+ ) );
142
+ }
143
+
144
+ /**
145
+ * @return LogRecord[]
146
+ */
147
+ protected function getRecords( array $wheres = [], int $offset = 0, int $limit = 0 ) :array {
148
+ $loader = $this->getRecordsLoader();
149
+ $loader->wheres = $wheres;
150
+ $loader->limit = $limit;
151
+ $loader->offset = $offset;
152
+ $loader->order_dir = $this->getOrderDirection();
153
+ return $loader->run();
154
+ }
155
+
156
+ private function getColumnContent_Details() :string {
157
+ $geo = $this->getCountryIP( $this->log->ip );
158
+ if ( empty( $geo->countryCode ) ) {
159
+ $country = __( 'Unknown', 'wp-simple-firewall' );
160
+ }
161
+ else {
162
+ $country = sprintf(
163
+ '<img class="icon-flag" src="%s" alt="%s" width="24px"/> %s',
164
+ sprintf( 'https://api.aptoweb.com/api/v1/country/flag/%s.svg', strtolower( $geo->countryCode ) ),
165
+ $geo->countryCode,
166
+ $geo->countryName
167
+ );
168
+ }
169
+
170
+ if ( $this->isWpCli() ) {
171
+ $content = 'WP-CLI';
172
+ }
173
+ else {
174
+ $content = sprintf( '<div>%s</div>', implode( '</div><div>', [
175
+ sprintf( '%s: %s', __( 'IP', 'wp-simple-firewall' ), $this->getIpAnalysisLink( $this->log->ip ) ),
176
+ sprintf( '%s: %s', __( 'IP Status', 'wp-simple-firewall' ), $this->getIpInfo( $this->log->ip ) ),
177
+ sprintf( '%s: %s', __( 'Logged-In', 'wp-simple-firewall' ), $this->users[ $this->log->meta[ 'uid' ] ] ),
178
+ sprintf( '%s: %s', __( 'Location', 'wp-simple-firewall' ), $country ),
179
+ esc_html( esc_js( sprintf( '%s - %s', __( 'User Agent', 'wp-simple-firewall' ), $this->log->meta[ 'ua' ] ) ) ),
180
+ ] ) );
181
+ }
182
+
183
+ return $content;
184
+ }
185
+
186
+ private function getColumnContent_Response() :string {
187
+ if ( $this->log->code >= 400 ) {
188
+ $codeType = 'danger';
189
+ }
190
+ elseif ( $this->log->code >= 300 ) {
191
+ $codeType = 'warning';
192
+ }
193
+ else {
194
+ $codeType = 'success';
195
+ }
196
+
197
+ return sprintf( '<div>%s</div>', implode( '</div><div>', [
198
+ sprintf( '%s: %s', __( 'Response', 'wp-simple-firewall' ),
199
+ sprintf( '<span class="badge bg-%s">%s</span>', $codeType, $this->log->code ) ),
200
+ sprintf( '%s: %s', __( 'Offense', 'wp-simple-firewall' ),
201
+ sprintf(
202
+ '<span class="badge bg-%s">%s</span>',
203
+ @$this->log->offense ? 'danger' : 'info',
204
+ @$this->log->offense ? __( 'Yes', 'wp-simple-firewall' ) : __( 'No', 'wp-simple-firewall' )
205
+ )
206
+ ),
207
+ ] ) );
208
+ }
209
+
210
+ private function getColumnContent_Page() :string {
211
+ $query = $this->log->meta[ 'query' ] ?? '';
212
+
213
+ $content = sprintf( '[<code style="display: inline !important;">%s</code>] ', Handler::GetTypeName( $this->log->type ) );
214
+ if ( $this->isWpCli() ) {
215
+ $content .= sprintf( '<code>:> %s</code>', esc_html( $this->log->path.' '.$query ) );
216
+ }
217
+ else {
218
+ $content .= strtoupper( $this->log->verb ).': <code>'.$this->log->path
219
+ .( empty( $query ) ? '' : '?<br/>'.ltrim( $query, '?' ) ).'</code>';
220
+ }
221
+ return $content;
222
+ }
223
+
224
+ private function getIpInfo( string $ip ) {
225
+
226
+ if ( !isset( $this->ipInfo[ $ip ] ) ) {
227
+
228
+ if ( empty( $ip ) ) {
229
+ $this->ipInfo[ '' ] = 'n/a';
230
+ }
231
+ else {
232
+ $badgeTemplate = '<span class="badge bg-%s">%s</span>';
233
+ $status = __( 'No Record', 'wp-simple-firewall' );
234
+
235
+ $record = ( new LookupIpOnList() )
236
+ ->setDbHandler( $this->getCon()->getModule_IPs()->getDbHandler_IPs() )
237
+ ->setIP( $ip )
238
+ ->lookup();
239
+
240
+ if ( empty( $record ) ) {
241
+ $status = __( 'No Record', 'wp-simple-firewall' );
242
+ }
243
+ elseif ( $record->blocked_at > 0 || $record->list === ModCon::LIST_MANUAL_BLACK ) {
244
+ $status = sprintf( $badgeTemplate, 'danger', __( 'Blocked', 'wp-simple-firewall' ) );
245
+ }
246
+ elseif ( $record->list === ModCon::LIST_AUTO_BLACK ) {
247
+ $status = sprintf( $badgeTemplate,
248
+ 'warning',
249
+ sprintf( _n( '%s offense', '%s offenses', $record->transgressions, 'wp-simple-firewall' ), $record->transgressions )
250
+ );
251
+ }
252
+ elseif ( $record->list === ModCon::LIST_MANUAL_WHITE ) {
253
+ $status = sprintf( $badgeTemplate,
254
+ 'success',
255
+ __( 'Bypass', 'wp-simple-firewall' )
256
+ );
257
+ }
258
+ $this->ipInfo[ $ip ] = $status;
259
+ }
260
+ }
261
+
262
+ return $this->ipInfo[ $ip ];
263
+ }
264
+
265
+ private function getCountryIP( string $ip ) :IPGeoVO {
266
+ if ( empty( $this->geoLookup ) ) {
267
+ $this->geoLookup = ( new Lookup() )->setCon( $this->getCon() );
268
+ }
269
+ return $this->geoLookup
270
+ ->setIP( $ip )
271
+ ->lookupIp();
272
+ }
273
+
274
+ private function isWpCli() :bool {
275
+ return $this->log->type === Handler::TYPE_WPCLI;
276
+ }
277
+ }
src/lib/src/Modules/Traffic/Lib/TrafficTable/DelegateAjaxHandler.php CHANGED
@@ -3,6 +3,8 @@
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Traffic\Lib\TrafficTable;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield;
 
 
6
  use FernleafSystems\Wordpress\Services\Services;
7
 
8
  class DelegateAjaxHandler {
@@ -10,7 +12,6 @@ class DelegateAjaxHandler {
10
  use Shield\Modules\ModConsumer;
11
 
12
  /**
13
- * @return array
14
  * @throws \Exception
15
  */
16
  public function processAjaxAction() :array {
@@ -28,17 +29,18 @@ class DelegateAjaxHandler {
28
  }
29
 
30
  /**
31
- * @return array
32
  * @throws \Exception
33
  */
34
  private function retrieveTableData() :array {
 
 
 
 
 
 
35
  return [
36
- 'success' => true,
37
- 'vars' => [
38
- 'data' => ( new LoadRawTableData() )
39
- ->setMod( $this->getMod() )
40
- ->loadForLogs()
41
- ],
42
  ];
43
  }
44
  }
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Traffic\Lib\TrafficTable;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\Lib\UpgradeReqLogsTable;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Tables\DataTables;
8
  use FernleafSystems\Wordpress\Services\Services;
9
 
10
  class DelegateAjaxHandler {
12
  use Shield\Modules\ModConsumer;
13
 
14
  /**
 
15
  * @throws \Exception
16
  */
17
  public function processAjaxAction() :array {
29
  }
30
 
31
  /**
 
32
  * @throws \Exception
33
  */
34
  private function retrieveTableData() :array {
35
+ ( new UpgradeReqLogsTable() )
36
+ ->setMod( $this->getCon()->getModule_Data() )
37
+ ->execute();
38
+
39
+ $builder = ( new BuildTrafficTableData() )->setMod( $this->getMod() );
40
+ $builder->table_data = Services::Request()->post( 'table_data', [] );
41
  return [
42
+ 'success' => true,
43
+ 'datatable_data' => $builder->build(),
 
 
 
 
44
  ];
45
  }
46
  }
src/lib/src/Modules/Traffic/Lib/TrafficTable/LoadRawTableData.php CHANGED
@@ -9,6 +9,7 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\ModCon;
9
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\DB\ReqLogs\LoadLogs;
10
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\DB\ReqLogs\LogRecord;
11
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
 
12
  use FernleafSystems\Wordpress\Plugin\Shield\Tables\DataTables\LoadData\BaseLoadTableData;
13
  use FernleafSystems\Wordpress\Services\Services;
14
 
@@ -30,7 +31,10 @@ class LoadRawTableData extends BaseLoadTableData {
30
 
31
  private $ipInfo = [];
32
 
33
- public function loadForLogs() :array {
 
 
 
34
  $this->users = [ 0 => __( 'No', 'wp-simple-firewall' ) ];
35
 
36
  return array_values( array_filter( array_map(
@@ -54,7 +58,6 @@ class LoadRawTableData extends BaseLoadTableData {
54
  $data = $log->getRawData();
55
 
56
  $data[ 'ip' ] = $this->log->ip;
57
- $data[ 'page' ] = $this->log->ip;
58
  $data[ 'code' ] = $this->log->meta[ 'code' ];
59
  $data[ 'offense' ] = $this->log->meta[ 'offense' ] ? 'Offense' : 'Not Offense';
60
  $data[ 'rid' ] = $this->log->rid ?? __( 'Unknown', 'wp-simple-firewall' );
@@ -81,17 +84,31 @@ class LoadRawTableData extends BaseLoadTableData {
81
  $data[ 'created_since' ] = $this->getColumnContent_Date( $this->log->created_at );
82
  return $data;
83
  },
84
- $this->getLogRecords()
85
  ) ) );
86
  }
87
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  /**
89
  * @return LogRecord[]
90
  */
91
- private function getLogRecords() :array {
92
- return ( new LoadLogs() )
93
- ->setMod( $this->getCon()->getModule_Data() )
94
- ->run();
 
 
95
  }
96
 
97
  private function getColumnContent_Details() :string {
9
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\DB\ReqLogs\LoadLogs;
10
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Data\DB\ReqLogs\LogRecord;
11
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
12
+ use FernleafSystems\Wordpress\Plugin\Shield\Tables\DataTables\Build\Traffic\ForTraffic;
13
  use FernleafSystems\Wordpress\Plugin\Shield\Tables\DataTables\LoadData\BaseLoadTableData;
14
  use FernleafSystems\Wordpress\Services\Services;
15
 
31
 
32
  private $ipInfo = [];
33
 
34
+ /**
35
+ * @param LogRecord[] $records
36
+ */
37
+ protected function buildTableRowsFromRawLogs( array $records ) :array {
38
  $this->users = [ 0 => __( 'No', 'wp-simple-firewall' ) ];
39
 
40
  return array_values( array_filter( array_map(
58
  $data = $log->getRawData();
59
 
60
  $data[ 'ip' ] = $this->log->ip;
 
61
  $data[ 'code' ] = $this->log->meta[ 'code' ];
62
  $data[ 'offense' ] = $this->log->meta[ 'offense' ] ? 'Offense' : 'Not Offense';
63
  $data[ 'rid' ] = $this->log->rid ?? __( 'Unknown', 'wp-simple-firewall' );
84
  $data[ 'created_since' ] = $this->getColumnContent_Date( $this->log->created_at );
85
  return $data;
86
  },
87
+ $records
88
  ) ) );
89
  }
90
 
91
+ protected function getSearchableColumns() :array {
92
+ // Use the DataTables definition builder to locate searchable columns
93
+ return array_filter( array_map(
94
+ function ( $column ) {
95
+ return ( $column[ 'searchable' ] ?? false ) ? $column[ 'data' ] : '';
96
+ },
97
+ ( new ForTraffic() )
98
+ ->setMod( $this->getMod() )
99
+ ->buildRaw()[ 'columns' ]
100
+ ) );
101
+ }
102
+
103
  /**
104
  * @return LogRecord[]
105
  */
106
+ protected function getRecords( int $offset = 0, int $limit = 0 ) :array {
107
+ $loader = ( new LoadLogs() )->setMod( $this->getCon()->getModule_Data() );
108
+ $loader->limit = $limit;
109
+ $loader->offset = $offset;
110
+ $loader->order_dir = $this->getOrderDirection();
111
+ return $loader->run();
112
  }
113
 
114
  private function getColumnContent_Details() :string {
src/lib/src/Modules/UserManagement/AjaxHandler.php CHANGED
@@ -63,7 +63,6 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
63
 
64
  $IDs = $req->post( 'ids' );
65
  if ( empty( $IDs ) || !is_array( $IDs ) ) {
66
- $success = false;
67
  $msg = __( 'No items selected.', 'wp-simple-firewall' );
68
  }
69
  elseif ( $req->post( 'bulk_action' ) != 'delete' ) {
@@ -71,9 +70,9 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
71
  }
72
  else {
73
  $yourId = $mod->getSession()->id;
74
- $bIncludesYourSession = in_array( $yourId, $IDs );
75
 
76
- if ( $bIncludesYourSession && ( count( $IDs ) == 1 ) ) {
77
  $msg = __( 'Please logout if you want to delete your own session.', 'wp-simple-firewall' );
78
  }
79
  else {
@@ -87,7 +86,7 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
87
  }
88
  }
89
  $msg = __( 'Selected items were deleted.', 'wp-simple-firewall' );
90
- if ( $bIncludesYourSession ) {
91
  $msg .= ' *'.__( 'Your session was retained', 'wp-simple-firewall' );
92
  }
93
  }
@@ -104,14 +103,14 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
104
  /** @var ModCon $mod */
105
  $mod = $this->getMod();
106
  $success = false;
107
- $nId = Services::Request()->post( 'rid', -1 );
108
- if ( !is_numeric( $nId ) || $nId < 0 ) {
109
  $msg = __( 'Invalid session selected', 'wp-simple-firewall' );
110
  }
111
- elseif ( $mod->getSession()->id === $nId ) {
112
  $msg = __( 'Please logout if you want to delete your own session.', 'wp-simple-firewall' );
113
  }
114
- elseif ( $con->getModule_Sessions()->getDbHandler_Sessions()->getQueryDeleter()->deleteById( $nId ) ) {
115
  $msg = __( 'User session deleted', 'wp-simple-firewall' );
116
  $success = true;
117
  }
63
 
64
  $IDs = $req->post( 'ids' );
65
  if ( empty( $IDs ) || !is_array( $IDs ) ) {
 
66
  $msg = __( 'No items selected.', 'wp-simple-firewall' );
67
  }
68
  elseif ( $req->post( 'bulk_action' ) != 'delete' ) {
70
  }
71
  else {
72
  $yourId = $mod->getSession()->id;
73
+ $includesYourSession = in_array( $yourId, $IDs );
74
 
75
+ if ( $includesYourSession && ( count( $IDs ) == 1 ) ) {
76
  $msg = __( 'Please logout if you want to delete your own session.', 'wp-simple-firewall' );
77
  }
78
  else {
86
  }
87
  }
88
  $msg = __( 'Selected items were deleted.', 'wp-simple-firewall' );
89
+ if ( $includesYourSession ) {
90
  $msg .= ' *'.__( 'Your session was retained', 'wp-simple-firewall' );
91
  }
92
  }
103
  /** @var ModCon $mod */
104
  $mod = $this->getMod();
105
  $success = false;
106
+ $id = Services::Request()->post( 'rid', -1 );
107
+ if ( !is_numeric( $id ) || $id < 0 ) {
108
  $msg = __( 'Invalid session selected', 'wp-simple-firewall' );
109
  }
110
+ elseif ( $mod->getSession()->id === $id ) {
111
  $msg = __( 'Please logout if you want to delete your own session.', 'wp-simple-firewall' );
112
  }
113
+ elseif ( $con->getModule_Sessions()->getDbHandler_Sessions()->getQueryDeleter()->deleteById( $id ) ) {
114
  $msg = __( 'User session deleted', 'wp-simple-firewall' );
115
  $success = true;
116
  }
src/lib/src/Modules/UserManagement/Lib/Suspend/PasswordExpiry.php CHANGED
@@ -35,11 +35,4 @@ class PasswordExpiry extends Base {
35
  return !empty( $meta->record->pass_started_at )
36
  && ( Services::Request()->ts() - $meta->record->pass_started_at > $opts->getPassExpireTimeout() );
37
  }
38
-
39
- /**
40
- * @deprecated 13.1
41
- */
42
- public function setMaxPasswordAge() {
43
- return $this;
44
- }
45
  }
35
  return !empty( $meta->record->pass_started_at )
36
  && ( Services::Request()->ts() - $meta->record->pass_started_at > $opts->getPassExpireTimeout() );
37
  }
 
 
 
 
 
 
 
38
  }
src/lib/src/Modules/UserManagement/Options.php CHANGED
@@ -6,18 +6,6 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
6
 
7
  class Options extends BaseShield\Options {
8
 
9
- /**
10
- * @deprecated 13.1
11
- */
12
- public function getSuspendHardUserIds() :array {
13
- return array_filter(
14
- $this->getOpt( 'hard_suspended_userids', [] ),
15
- function ( $ts ) {
16
- return is_int( $ts ) && $ts > 0;
17
- }
18
- );
19
- }
20
-
21
  public function getSuspendAutoIdleUserRoles() :array {
22
  return $this->getOpt( 'auto_idle_roles', [] );
23
  }
6
 
7
  class Options extends BaseShield\Options {
8
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  public function getSuspendAutoIdleUserRoles() :array {
10
  return $this->getOpt( 'auto_idle_roles', [] );
11
  }
src/lib/src/Modules/UserManagement/Processor.php CHANGED
@@ -2,6 +2,8 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\UserManagement;
4
 
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Users\BulkUpdateUserMeta;
7
  use FernleafSystems\Wordpress\Services\Services;
@@ -52,6 +54,35 @@ class Processor extends BaseShield\Processor {
52
  }
53
  }
54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  /**
56
  * @param string $username
57
  * @param \WP_User $user
@@ -100,20 +131,6 @@ class Processor extends BaseShield\Processor {
100
  return $this;
101
  }
102
 
103
- /**
104
- * @deprecated 13.1
105
- */
106
- private function setPasswordStartedAt( \WP_User $user ) :self {
107
- return $this;
108
- }
109
-
110
- /**
111
- * @deprecated 13.1
112
- */
113
- protected function setUserLastLoginTime( \WP_User $user ) :self {
114
- return $this;
115
- }
116
-
117
  /**
118
  * Adds the column to the users listing table to indicate
119
  * @param array $cols
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\UserManagement;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Databases\Session\EntryVO;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Databases\Session\Select;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Users\BulkUpdateUserMeta;
9
  use FernleafSystems\Wordpress\Services\Services;
54
  }
55
  }
56
 
57
+ public function addAdminBarMenuGroup( array $groups ) :array {
58
+ $con = $this->getCon();
59
+ $WPUsers = Services::WpUsers();
60
+ /** @var Select $sel */
61
+ $sel = $con->getModule_Sessions()->getDbHandler_Sessions()->getQuerySelector();
62
+ $sel->filterByLoginNotIdleExpired( Services::Request()->carbon()->subMinutes( 10 )->timestamp )
63
+ ->setOrderBy( 'last_activity_at', 'DESC' );
64
+
65
+ $thisGroup = [
66
+ 'title' => __( 'Recent Sessions', 'wp-simple-firewall' ),
67
+ 'href' => $con->getModule_Insights()->getUrl_Sessions(),
68
+ 'items' => [],
69
+ ];
70
+ /** @var EntryVO $session */
71
+ foreach ( $sel->query() as $session ) {
72
+ $thisGroup[ 'items' ][] = [
73
+ 'id' => $con->prefix( 'session-'.$session->id ),
74
+ 'title' => sprintf( '<a href="%s">%s (%s)</a>',
75
+ $WPUsers->getAdminUrl_ProfileEdit( $WPUsers->getUserByUsername( $session->wp_username ) ),
76
+ $session->wp_username, $session->ip ),
77
+ ];
78
+ }
79
+
80
+ if ( !empty( $thisGroup[ 'items' ] ) ) {
81
+ $groups[] = $thisGroup;
82
+ }
83
+ return $groups;
84
+ }
85
+
86
  /**
87
  * @param string $username
88
  * @param \WP_User $user
131
  return $this;
132
  }
133
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  /**
135
  * Adds the column to the users listing table to indicate
136
  * @param array $cols
src/lib/src/Modules/UserManagement/Upgrade.php DELETED
@@ -1,9 +0,0 @@
1
- <?php
2
-
3
- namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\UserManagement;
4
-
5
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
6
-
7
- class Upgrade extends Base\Upgrade {
8
-
9
- }
 
 
 
 
 
 
 
 
 
src/lib/src/Tables/Build/Ip.php CHANGED
@@ -8,10 +8,6 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Options;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Tables;
9
  use FernleafSystems\Wordpress\Services\Services;
10
 
11
- /**
12
- * Class Ip
13
- * @package FernleafSystems\Wordpress\Plugin\Shield\Tables\Build
14
- */
15
  class Ip extends BaseBuild {
16
 
17
  /**
@@ -54,23 +50,23 @@ class Ip extends BaseBuild {
54
 
55
  foreach ( $this->getEntriesRaw() as $key => $entry ) {
56
  /** @var IPs\EntryVO $entry */
57
- $aE = $entry->getRawData();
58
  $bBlocked = $entry->blocked_at > 0 || $entry->transgressions >= $nTransLimit;
59
- $aE[ 'last_trans_at' ] = Services::Request()
60
  ->carbon( true )
61
  ->setTimestamp( $entry->last_access_at )
62
  ->diffForHumans();
63
- $aE[ 'last_access_at' ] = $this->formatTimestampField( $entry->last_access_at );
64
- $aE[ 'created_at' ] = $this->formatTimestampField( $entry->created_at );
65
- $aE[ 'blocked' ] = $bBlocked ? __( 'Yes' ) : __( 'No' );
66
- $aE[ 'expires_at' ] = $this->formatTimestampField( $entry->last_access_at + $opts->getAutoExpireTime() );
67
- $aE[ 'is_you' ] = $srvIP->checkIp( $you, $entry->ip );
68
- $aE[ 'ip' ] = sprintf( '%s%s',
69
  $this->getIpAnalysisLink( $entry->ip ),
70
- $aE[ 'is_you' ] ? ' <span class="small">('.__( 'You', 'wp-simple-firewall' ).')</span>' : ''
71
  );
72
 
73
- $entries[ $key ] = $aE;
74
  }
75
  return $entries;
76
  }
8
  use FernleafSystems\Wordpress\Plugin\Shield\Tables;
9
  use FernleafSystems\Wordpress\Services\Services;
10
 
 
 
 
 
11
  class Ip extends BaseBuild {
12
 
13
  /**
50
 
51
  foreach ( $this->getEntriesRaw() as $key => $entry ) {
52
  /** @var IPs\EntryVO $entry */
53
+ $e = $entry->getRawData();
54
  $bBlocked = $entry->blocked_at > 0 || $entry->transgressions >= $nTransLimit;
55
+ $e[ 'last_trans_at' ] = Services::Request()
56
  ->carbon( true )
57
  ->setTimestamp( $entry->last_access_at )
58
  ->diffForHumans();
59
+ $e[ 'last_access_at' ] = $this->formatTimestampField( $entry->last_access_at );
60
+ $e[ 'created_at' ] = $this->formatTimestampField( $entry->created_at );
61
+ $e[ 'blocked' ] = $bBlocked ? __( 'Yes' ) : __( 'No' );
62
+ $e[ 'expires_at' ] = $this->formatTimestampField( $entry->last_access_at + $opts->getAutoExpireTime() );
63
+ $e[ 'is_you' ] = $srvIP->checkIp( $you, $entry->ip );
64
+ $e[ 'ip' ] = sprintf( '%s%s',
65
  $this->getIpAnalysisLink( $entry->ip ),
66
+ $e[ 'is_you' ] ? ' <span class="small">('.__( 'You', 'wp-simple-firewall' ).')</span>' : ''
67
  );
68
 
69
+ $entries[ $key ] = $e;
70
  }
71
  return $entries;
72
  }
src/lib/src/Tables/Build/Sessions.php CHANGED
@@ -6,10 +6,6 @@ use FernleafSystems\Wordpress\Plugin\Shield\Databases\Session;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Tables;
7
  use FernleafSystems\Wordpress\Services\Services;
8
 
9
- /**
10
- * Class Sessions
11
- * @package FernleafSystems\Wordpress\Plugin\Shield\Tables\Build
12
- */
13
  class Sessions extends BaseBuild {
14
 
15
  /**
@@ -61,29 +57,29 @@ class Sessions extends BaseBuild {
61
  $you = $srvIP->getRequestIp();
62
  foreach ( $this->getEntriesRaw() as $nKey => $entry ) {
63
  /** @var Session\EntryVO $entry */
64
- $aE = $entry->getRawData();
65
- $aE[ 'is_secadmin' ] = $this->isSecAdminSession( $entry ) ? __( 'Yes' ) : __( 'No' );
66
- $aE[ 'last_activity_at' ] = $this->formatTimestampField( $entry->last_activity_at );
67
- $aE[ 'logged_in_at' ] = $this->formatTimestampField( $entry->logged_in_at );
68
 
69
  try {
70
- $aE[ 'is_you' ] = $srvIP->checkIp( $you, $entry->ip );
71
  }
72
- catch ( \Exception $e ) {
73
- $aE[ 'is_you' ] = false;
74
  }
75
- $aE[ 'ip' ] = sprintf( '%s%s',
76
  $this->getIpAnalysisLink( $entry->ip ),
77
- $aE[ 'is_you' ] ? ' <small>('.__( 'You', 'wp-simple-firewall' ).')</small>' : ''
78
  );
79
 
80
- $oWpUsers = Services::WpUsers();
81
- $aE[ 'wp_username' ] = sprintf(
82
  '<a href="%s">%s</a>',
83
- $oWpUsers->getAdminUrl_ProfileEdit( $oWpUsers->getUserByUsername( $aE[ 'wp_username' ] ?? '' ) ),
84
- $aE[ 'wp_username' ]
85
  );
86
- $aEntries[ $nKey ] = $aE;
87
  }
88
  return $aEntries;
89
  }
6
  use FernleafSystems\Wordpress\Plugin\Shield\Tables;
7
  use FernleafSystems\Wordpress\Services\Services;
8
 
 
 
 
 
9
  class Sessions extends BaseBuild {
10
 
11
  /**
57
  $you = $srvIP->getRequestIp();
58
  foreach ( $this->getEntriesRaw() as $nKey => $entry ) {
59
  /** @var Session\EntryVO $entry */
60
+ $e = $entry->getRawData();
61
+ $e[ 'is_secadmin' ] = $this->isSecAdminSession( $entry ) ? __( 'Yes' ) : __( 'No' );
62
+ $e[ 'last_activity_at' ] = $this->formatTimestampField( $entry->last_activity_at );
63
+ $e[ 'logged_in_at' ] = $this->formatTimestampField( $entry->logged_in_at );
64
 
65
  try {
66
+ $e[ 'is_you' ] = $srvIP->checkIp( $you, $entry->ip );
67
  }
68
+ catch ( \Exception $ex ) {
69
+ $e[ 'is_you' ] = false;
70
  }
71
+ $e[ 'ip' ] = sprintf( '%s%s',
72
  $this->getIpAnalysisLink( $entry->ip ),
73
+ $e[ 'is_you' ] ? ' <small>('.__( 'You', 'wp-simple-firewall' ).')</small>' : ''
74
  );
75
 
76
+ $WPU = Services::WpUsers();
77
+ $e[ 'wp_username' ] = sprintf(
78
  '<a href="%s">%s</a>',
79
+ $WPU->getAdminUrl_ProfileEdit( $WPU->getUserByUsername( $e[ 'wp_username' ] ?? '' ) ),
80
+ $e[ 'wp_username' ]
81
  );
82
+ $aEntries[ $nKey ] = $e;
83
  }
84
  return $aEntries;
85
  }
src/lib/src/Tables/DataTables/Build/AuditTrail/ForAuditTrail.php CHANGED
@@ -28,24 +28,26 @@ class ForAuditTrail extends Base {
28
  protected function getColumnDefs() :array {
29
  return [
30
  'rid' => [
31
- 'data' => 'rid',
32
- 'title' => __( 'Request ID' ),
33
- 'className' => 'rid',
34
- 'orderable' => true,
35
- 'searchable' => true,
36
- 'visible' => false,
37
- 'searchPanes' => [
38
- 'show' => true,
 
39
  ],
40
  ],
41
  'event' => [
42
- 'data' => 'event',
43
- 'title' => __( 'Event' ),
44
- 'className' => 'event',
45
- 'orderable' => true,
46
- 'searchable' => true,
47
- 'visible' => false,
48
- 'searchPanes' => [
 
49
  'show' => true
50
  ],
51
  ],
@@ -53,7 +55,7 @@ class ForAuditTrail extends Base {
53
  'data' => 'event',
54
  'title' => __( 'Event Slug' ),
55
  'className' => 'event',
56
- 'orderable' => true,
57
  'searchable' => false,
58
  'visible' => false,
59
  'searchPanes' => [
@@ -72,24 +74,27 @@ class ForAuditTrail extends Base {
72
  ],
73
  ],
74
  'level' => [
75
- 'data' => 'level',
76
- 'title' => __( 'Severity' ),
77
- 'className' => 'level',
78
- 'orderable' => false,
79
- 'searchable' => true,
80
- 'visible' => false,
81
- 'searchPanes' => [
82
- 'show' => true
 
83
  ],
 
84
  ],
85
  'ip' => [
86
- 'data' => 'ip',
87
- 'title' => __( 'IP Address' ),
88
- 'className' => 'ip',
89
- 'orderable' => true,
90
- 'searchable' => true,
91
- 'visible' => false,
92
- 'searchPanes' => [
 
93
  'show' => true,
94
  ],
95
  ],
@@ -97,30 +102,32 @@ class ForAuditTrail extends Base {
97
  'data' => 'ip_linked',
98
  'title' => __( 'IP' ),
99
  'className' => 'ip_linked',
100
- 'orderable' => true,
101
- 'searchable' => true,
102
  'visible' => true,
103
  'searchPanes' => [
104
  'show' => false,
105
  ],
106
  ],
107
  'uid' => [
108
- 'data' => 'uid',
109
- 'title' => __( 'User ID' ),
110
- 'className' => 'uid',
111
- 'orderable' => true,
112
- 'searchable' => false,
113
- 'visible' => false,
 
114
  ],
115
  'user' => [
116
- 'data' => 'user',
117
- 'title' => __( 'User' ),
118
- 'className' => 'user',
119
- 'orderable' => true,
120
- 'searchable' => true,
121
- 'visible' => true,
122
- 'searchPanes' => [
123
- 'show' => true
 
124
  ],
125
  ],
126
  'message' => [
@@ -149,13 +156,13 @@ class ForAuditTrail extends Base {
149
  ],
150
  ],
151
  'meta' => [
152
- 'data' => 'meta',
153
- 'title' => __( 'Meta' ),
154
- 'className' => 'meta',
155
- 'orderable' => false,
156
- 'searchable' => false,
157
- 'visible' => true,
158
- 'searchPanes' => [
159
  'show' => false
160
  ],
161
  ],
28
  protected function getColumnDefs() :array {
29
  return [
30
  'rid' => [
31
+ 'data' => 'rid',
32
+ 'title' => __( 'Request ID' ),
33
+ 'className' => 'rid',
34
+ 'orderable' => false,
35
+ 'searchable' => true,
36
+ 'search_builder' => true,
37
+ 'visible' => false,
38
+ 'searchPanes' => [
39
+ 'show' => false,
40
  ],
41
  ],
42
  'event' => [
43
+ 'data' => 'event',
44
+ 'title' => __( 'Event' ),
45
+ 'className' => 'event',
46
+ 'orderable' => false,
47
+ 'searchable' => true,
48
+ 'search_builder' => true,
49
+ 'visible' => false,
50
+ 'searchPanes' => [
51
  'show' => true
52
  ],
53
  ],
55
  'data' => 'event',
56
  'title' => __( 'Event Slug' ),
57
  'className' => 'event',
58
+ 'orderable' => false,
59
  'searchable' => false,
60
  'visible' => false,
61
  'searchPanes' => [
74
  ],
75
  ],
76
  'level' => [
77
+ 'data' => 'level',
78
+ 'title' => __( 'Level' ),
79
+ 'className' => 'level',
80
+ 'orderable' => false,
81
+ 'searchable' => true,
82
+ 'search_builder' => true,
83
+ 'visible' => false,
84
+ 'searchPanes' => [
85
+ 'show' => false
86
  ],
87
+ 'searchBuilderTitle' => __( 'Severity' )
88
  ],
89
  'ip' => [
90
+ 'data' => 'ip',
91
+ 'title' => __( 'IP Address' ),
92
+ 'className' => 'ip',
93
+ 'orderable' => false,
94
+ 'searchable' => true,
95
+ 'search_builder' => true,
96
+ 'visible' => false,
97
+ 'searchPanes' => [
98
  'show' => true,
99
  ],
100
  ],
102
  'data' => 'ip_linked',
103
  'title' => __( 'IP' ),
104
  'className' => 'ip_linked',
105
+ 'orderable' => false,
106
+ 'searchable' => false,
107
  'visible' => true,
108
  'searchPanes' => [
109
  'show' => false,
110
  ],
111
  ],
112
  'uid' => [
113
+ 'data' => 'uid',
114
+ 'title' => __( 'User ID' ),
115
+ 'className' => 'uid',
116
+ 'orderable' => false,
117
+ 'searchable' => false,
118
+ 'search_builder' => true,
119
+ 'visible' => false,
120
  ],
121
  'user' => [
122
+ 'data' => 'user',
123
+ 'title' => __( 'User' ),
124
+ 'className' => 'user',
125
+ 'orderable' => false,
126
+ 'searchable' => true,
127
+ 'search_builder' => false,
128
+ 'visible' => true,
129
+ 'searchPanes' => [
130
+ 'show' => false
131
  ],
132
  ],
133
  'message' => [
156
  ],
157
  ],
158
  'meta' => [
159
+ 'data' => 'meta',
160
+ 'title' => __( 'Meta' ),
161
+ 'className' => 'meta',
162
+ 'orderable' => false,
163
+ 'searchable' => false,
164
+ 'visible' => true,
165
+ 'searchPanes' => [
166
  'show' => false
167
  ],
168
  ],
src/lib/src/Tables/DataTables/Build/Base.php CHANGED
@@ -16,15 +16,18 @@ abstract class Base {
16
  abstract protected function getOrderColumnSlug() :string;
17
 
18
  public function build() :string {
19
- return json_encode( [
 
 
 
 
20
  // array_values() to ensure data of the correct format
21
- 'columns' => array_values( $this->getColumnsForDisplay() ),
22
- 'order' => $this->getInitialOrdering()
23
- ] );
24
  }
25
 
26
  /**
27
- * @return array
28
  * @throws \Exception
29
  */
30
  public function getInitialOrdering() :array {
@@ -45,20 +48,23 @@ abstract class Base {
45
  }
46
 
47
  /**
48
- * @return array
49
  * @throws \Exception
50
  */
51
  public function getColumnsForDisplay() :array {
52
  $columns = [];
53
  foreach ( $this->getColumnsToDisplay() as $colSlug ) {
54
- $columns[ $colSlug ] = $this->pluckColumn( $colSlug );
 
 
 
 
 
 
55
  }
56
  return $columns;
57
  }
58
 
59
  /**
60
- * @param string $columnSlug
61
- * @return array
62
  * @throws \Exception
63
  */
64
  protected function pluckColumn( string $columnSlug ) :array {
16
  abstract protected function getOrderColumnSlug() :string;
17
 
18
  public function build() :string {
19
+ return json_encode( $this->buildRaw() );
20
+ }
21
+
22
+ public function buildRaw() :array {
23
+ return [
24
  // array_values() to ensure data of the correct format
25
+ 'columns' => array_values( $this->getColumnsForDisplay() ),
26
+ 'order' => $this->getInitialOrdering(),
27
+ ];
28
  }
29
 
30
  /**
 
31
  * @throws \Exception
32
  */
33
  public function getInitialOrdering() :array {
48
  }
49
 
50
  /**
 
51
  * @throws \Exception
52
  */
53
  public function getColumnsForDisplay() :array {
54
  $columns = [];
55
  foreach ( $this->getColumnsToDisplay() as $colSlug ) {
56
+ $col = $this->pluckColumn( $colSlug );
57
+
58
+ if ( $col[ 'search_builder' ] ?? false ) {
59
+ $col[ 'className' ] .= ' search_builder';
60
+ }
61
+
62
+ $columns[ $colSlug ] = $col;
63
  }
64
  return $columns;
65
  }
66
 
67
  /**
 
 
68
  * @throws \Exception
69
  */
70
  protected function pluckColumn( string $columnSlug ) :array {
src/lib/src/Tables/DataTables/Build/Traffic/ForTraffic.php CHANGED
@@ -17,6 +17,7 @@ class ForTraffic extends Base {
17
  'details',
18
  'response',
19
  'date',
 
20
  'path',
21
  'code',
22
  'offense',
@@ -30,18 +31,18 @@ class ForTraffic extends Base {
30
  'data' => 'rid',
31
  'title' => __( 'Request ID' ),
32
  'className' => 'rid',
33
- 'orderable' => true,
34
  'searchable' => true,
35
  'visible' => false,
36
  'searchPanes' => [
37
- 'show' => true,
38
  ],
39
  ],
40
  'page' => [
41
  'data' => 'page',
42
  'title' => __( 'Page' ),
43
  'className' => 'page',
44
- 'orderable' => true,
45
  'searchable' => true,
46
  'visible' => true,
47
  'searchPanes' => [
@@ -70,11 +71,22 @@ class ForTraffic extends Base {
70
  'show' => false
71
  ],
72
  ],
 
 
 
 
 
 
 
 
 
 
 
73
  'ip' => [
74
  'data' => 'ip',
75
  'title' => __( 'IP Address' ),
76
  'className' => 'ip',
77
- 'orderable' => true,
78
  'searchable' => true,
79
  'visible' => false,
80
  'searchPanes' => [
@@ -85,7 +97,7 @@ class ForTraffic extends Base {
85
  'data' => 'code',
86
  'title' => __( 'Response Code' ),
87
  'className' => 'code',
88
- 'orderable' => true,
89
  'searchable' => true,
90
  'visible' => false,
91
  'searchPanes' => [
@@ -96,11 +108,11 @@ class ForTraffic extends Base {
96
  'data' => 'country',
97
  'title' => __( 'Country' ),
98
  'className' => 'country',
99
- 'orderable' => true,
100
  'searchable' => true,
101
  'visible' => false,
102
  'searchPanes' => [
103
- 'show' => true,
104
  ],
105
  ],
106
  'offense' => [
@@ -108,13 +120,13 @@ class ForTraffic extends Base {
108
  'title' => __( 'Is Offense' ),
109
  'className' => 'offense',
110
  'orderable' => false,
111
- 'searchable' => true,
112
  'visible' => false,
113
  'searchPanes' => [
114
  'show' => true,
115
  ],
116
  ],
117
- 'path' => [
118
  'data' => 'path',
119
  'title' => __( 'Path' ),
120
  'className' => 'path',
@@ -122,14 +134,14 @@ class ForTraffic extends Base {
122
  'searchable' => true,
123
  'visible' => false,
124
  'searchPanes' => [
125
- 'show' => true,
126
  ],
127
  ],
128
  'uid' => [
129
  'data' => 'uid',
130
  'title' => __( 'User ID' ),
131
  'className' => 'uid',
132
- 'orderable' => true,
133
  'searchable' => false,
134
  'visible' => false,
135
  ],
17
  'details',
18
  'response',
19
  'date',
20
+ 'type',
21
  'path',
22
  'code',
23
  'offense',
31
  'data' => 'rid',
32
  'title' => __( 'Request ID' ),
33
  'className' => 'rid',
34
+ 'orderable' => false,
35
  'searchable' => true,
36
  'visible' => false,
37
  'searchPanes' => [
38
+ 'show' => false,
39
  ],
40
  ],
41
  'page' => [
42
  'data' => 'page',
43
  'title' => __( 'Page' ),
44
  'className' => 'page',
45
+ 'orderable' => false,
46
  'searchable' => true,
47
  'visible' => true,
48
  'searchPanes' => [
71
  'show' => false
72
  ],
73
  ],
74
+ 'type' => [
75
+ 'data' => 'type',
76
+ 'title' => __( 'Type' ),
77
+ 'className' => 'type',
78
+ 'orderable' => false,
79
+ 'searchable' => false,
80
+ 'visible' => false,
81
+ 'searchPanes' => [
82
+ 'show' => true,
83
+ ],
84
+ ],
85
  'ip' => [
86
  'data' => 'ip',
87
  'title' => __( 'IP Address' ),
88
  'className' => 'ip',
89
+ 'orderable' => false,
90
  'searchable' => true,
91
  'visible' => false,
92
  'searchPanes' => [
97
  'data' => 'code',
98
  'title' => __( 'Response Code' ),
99
  'className' => 'code',
100
+ 'orderable' => false,
101
  'searchable' => true,
102
  'visible' => false,
103
  'searchPanes' => [
108
  'data' => 'country',
109
  'title' => __( 'Country' ),
110
  'className' => 'country',
111
+ 'orderable' => false,
112
  'searchable' => true,
113
  'visible' => false,
114
  'searchPanes' => [
115
+ 'show' => false,
116
  ],
117
  ],
118
  'offense' => [
120
  'title' => __( 'Is Offense' ),
121
  'className' => 'offense',
122
  'orderable' => false,
123
+ 'searchable' => false,
124
  'visible' => false,
125
  'searchPanes' => [
126
  'show' => true,
127
  ],
128
  ],
129
+ 'path' => [
130
  'data' => 'path',
131
  'title' => __( 'Path' ),
132
  'className' => 'path',
134
  'searchable' => true,
135
  'visible' => false,
136
  'searchPanes' => [
137
+ 'show' => false,
138
  ],
139
  ],
140
  'uid' => [
141
  'data' => 'uid',
142
  'title' => __( 'User ID' ),
143
  'className' => 'uid',
144
+ 'orderable' => false,
145
  'searchable' => false,
146
  'visible' => false,
147
  ],
src/lib/src/Tables/DataTables/LoadData/BaseBuildTableData.php ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Tables\DataTables\LoadData;
4
+
5
+ use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
+ use FernleafSystems\Wordpress\Services\Services;
8
+
9
+ /**
10
+ * @property string $order_by
11
+ * @property string $order_dir
12
+ * @property array $table_data
13
+ */
14
+ abstract class BaseBuildTableData extends DynPropertiesClass {
15
+
16
+ use ModConsumer;
17
+
18
+ public function build() :array {
19
+ return [
20
+ 'data' => $this->loadForLogs(),
21
+ 'recordsTotal' => $this->countTotalRecords(),
22
+ 'recordsFiltered' => $this->countTotalRecordsFiltered(),
23
+ 'searchPanes' => $this->getSearchPanesData(),
24
+ ];
25
+ }
26
+
27
+ protected function getSearchPanesData() :array {
28
+ return [];
29
+ }
30
+
31
+ public function loadForLogs() :array {
32
+ $start = (int)$this->table_data[ 'start' ];
33
+ $length = (int)$this->table_data[ 'length' ];
34
+ $search = (string)$this->table_data[ 'search' ][ 'value' ] ?? '';
35
+ $wheres = $this->buildWheresFromSearchPanes();
36
+
37
+ $searchableColumns = array_flip( $this->getSearchableColumns() );
38
+
39
+ // We keep building logs and filtering by the search string until we have
40
+ // enough records built to return in order to satisfy the start + length.
41
+ $results = [];
42
+ $page = 0;
43
+ $pageLength = 100;
44
+ do {
45
+ $interimResults = $this->buildTableRowsFromRawLogs(
46
+ $this->getRecords( $wheres, $page*$pageLength, $pageLength )
47
+ );
48
+ // no more table results to process, so go with what we have.
49
+ if ( empty( $interimResults ) ) {
50
+ break;
51
+ }
52
+
53
+ foreach ( $interimResults as $result ) {
54
+
55
+ if ( empty( $search ) ) {
56
+ $results[] = $result;
57
+ }
58
+ else {
59
+ $searchable = array_intersect_key( $result, $searchableColumns );
60
+ foreach ( $searchable as $value ) {
61
+ $value = wp_strip_all_tags( $value );
62
+ if ( !is_string( $search ) ) {
63
+ error_log( var_export( $search, true ) );
64
+ }
65
+ if ( stripos( $value, $search ) !== false ) {
66
+ $results[] = $result;
67
+ break;
68
+ }
69
+ }
70
+ }
71
+ }
72
+
73
+ $page++;
74
+ } while ( count( $results ) < $start + $length );
75
+
76
+ $results = array_values( $results );
77
+ if ( count( $results ) < $start ) {
78
+ $results = [];
79
+ }
80
+ else {
81
+ $results = array_splice( $results, $start, $length );
82
+ }
83
+
84
+ return array_values( $results );
85
+ }
86
+
87
+ protected function buildWheresFromSearchPanes() :array {
88
+ return [];
89
+ }
90
+
91
+ protected function getOrderDirection() :string {
92
+ if ( !isset( $this->order_dir ) ) {
93
+ $dir = 'DESC';
94
+ if ( !empty( $this->table_data[ 'order' ] ) ) {
95
+ $col = $this->table_data[ 'order' ][ 0 ][ 'column' ];
96
+ $sortCol = $this->table_data[ 'columns' ][ $col ][ 'data' ];
97
+ $this->order_by = is_array( $sortCol ) ? $sortCol[ 'sort' ] : $sortCol;
98
+ $dir = strtoupper( $this->table_data[ 'order' ][ 0 ][ 'dir' ] );
99
+ if ( !in_array( $dir, [ 'ASC', 'DESC' ] ) ) {
100
+ $dir = 'DESC';
101
+ }
102
+ }
103
+ $this->order_dir = $dir;
104
+ }
105
+ return $this->order_dir;
106
+ }
107
+
108
+ protected function getRecords( array $wheres = [], int $offset = 0, int $limit = 0 ) :array {
109
+ return [];
110
+ }
111
+
112
+ abstract protected function countTotalRecords() :int;
113
+
114
+ abstract protected function countTotalRecordsFiltered() :int;
115
+
116
+ abstract protected function buildTableRowsFromRawLogs( array $records ) :array;
117
+
118
+ protected function getColumnContent_Date( int $ts ) :string {
119
+ return sprintf( '%s<br /><small>%s</small>',
120
+ Services::Request()
121
+ ->carbon( true )
122
+ ->setTimestamp( $ts )
123
+ ->diffForHumans(),
124
+ Services::WpGeneral()->getTimeStringForDisplay( $ts )
125
+ );
126
+ }
127
+
128
+ protected function getIpAnalysisLink( string $ip ) :string {
129
+ $srvIP = Services::IP();
130
+
131
+ if ( $srvIP->isValidIpRange( $ip ) ) {
132
+ $content = sprintf( '<a href="%s" target="_blank" title="%s">%s</a>',
133
+ $srvIP->getIpWhoisLookup( $ip ),
134
+ __( 'IP Analysis', 'wp-simple-firewall' ),
135
+ $ip
136
+ );
137
+ }
138
+ elseif ( Services::IP()->isValidIp( $ip ) ) {
139
+ $content = sprintf( '<a href="%s" target="_blank" title="%s">%s</a>',
140
+ $this->getCon()->getModule_Insights()->getUrl_IpAnalysis( $ip ),
141
+ __( 'IP Analysis', 'wp-simple-firewall' ),
142
+ $ip
143
+ );
144
+ }
145
+ else {
146
+ $content = __( 'IP Unavailable', 'wp-simple-firewall' );
147
+ }
148
+ return $content;
149
+ }
150
+
151
+ protected function getSearchableColumns() :array {
152
+ return [];
153
+ }
154
+ }
src/lib/src/Tables/DataTables/LoadData/BaseLoadTableData.php CHANGED
@@ -2,13 +2,97 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Tables\DataTables\LoadData;
4
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
  use FernleafSystems\Wordpress\Services\Services;
7
 
8
- class BaseLoadTableData {
 
 
 
 
 
9
 
10
  use ModConsumer;
11
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  protected function getColumnContent_Date( int $ts ) :string {
13
  return sprintf( '%s<br /><small>%s</small>',
14
  Services::Request()
@@ -41,4 +125,8 @@ class BaseLoadTableData {
41
  }
42
  return $content;
43
  }
 
 
 
 
44
  }
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Tables\DataTables\LoadData;
4
 
5
+ use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
  use FernleafSystems\Wordpress\Services\Services;
8
 
9
+ /**
10
+ * @property string $order_by
11
+ * @property string $order_dir
12
+ * @property array $table_data
13
+ */
14
+ abstract class BaseLoadTableData extends DynPropertiesClass {
15
 
16
  use ModConsumer;
17
 
18
+ public function loadForLogs() :array {
19
+ $start = (int)$this->table_data[ 'start' ];
20
+ $length = (int)$this->table_data[ 'length' ];
21
+ $search = (string)$this->table_data[ 'search' ][ 'value' ] ?? '';
22
+
23
+ $searchableColumns = array_flip( $this->getSearchableColumns() );
24
+
25
+ // We keep building logs and filtering by the search string until we have
26
+ // enough records built to return in order to satisfy the start + length.
27
+ $results = [];
28
+ $page = 0;
29
+ $pageLength = 100;
30
+ do {
31
+ $interimResults = $this->buildTableRowsFromRawLogs(
32
+ $this->getRecords( $page*$pageLength, $pageLength )
33
+ );
34
+ // no more table results to process, so go with what we have.
35
+ if ( empty( $interimResults ) ) {
36
+ break;
37
+ }
38
+
39
+ foreach ( $interimResults as $result ) {
40
+
41
+ if ( empty( $search ) ) {
42
+ $results[] = $result;
43
+ }
44
+ else {
45
+ $searchable = array_intersect_key( $result, $searchableColumns );
46
+ foreach ( $searchable as $value ) {
47
+ $value = wp_strip_all_tags( $value );
48
+ if (!is_string($search)) {
49
+ error_log( var_export( $search, true ) );
50
+ }
51
+ if ( stripos( $value, $search ) !== false ) {
52
+ $results[] = $result;
53
+ break;
54
+ }
55
+ }
56
+ }
57
+ }
58
+
59
+ $page++;
60
+ } while ( count( $results ) < $start + $length );
61
+
62
+ $results = array_values( $results );
63
+ if ( count( $results ) < $start ) {
64
+ $results = [];
65
+ }
66
+ else {
67
+ $results = array_splice( $results, $start, $length );
68
+ }
69
+
70
+ return array_values( $results );
71
+ }
72
+
73
+ protected function getOrderDirection() :string {
74
+ if ( !isset( $this->order_dir ) ) {
75
+ $dir = 'DESC';
76
+ if ( !empty( $this->table_data[ 'order' ] ) ) {
77
+ $col = $this->table_data[ 'order' ][ 0 ][ 'column' ];
78
+ $sortCol = $this->table_data[ 'columns' ][ $col ][ 'data' ];
79
+ $this->order_by = is_array( $sortCol ) ? $sortCol[ 'sort' ] : $sortCol;
80
+ $dir = strtoupper( $this->table_data[ 'order' ][ 0 ][ 'dir' ] );
81
+ if ( !in_array( $dir, [ 'ASC', 'DESC' ] ) ) {
82
+ $dir = 'DESC';
83
+ }
84
+ }
85
+ $this->order_dir = $dir;
86
+ }
87
+ return $this->order_dir;
88
+ }
89
+
90
+ protected function getRecords( int $offset = 0, int $limit = 0 ) :array {
91
+ return [];
92
+ }
93
+
94
+ abstract protected function buildTableRowsFromRawLogs( array $records ) :array;
95
+
96
  protected function getColumnContent_Date( int $ts ) :string {
97
  return sprintf( '%s<br /><small>%s</small>',
98
  Services::Request()
125
  }
126
  return $content;
127
  }
128
+
129
+ protected function getSearchableColumns() :array {
130
+ return [];
131
+ }
132
  }
src/lib/src/Tables/Render/WpCliTable/AuditTrail.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Tables\Render\WpCliTable;
4
 
5
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\Lib\LogTable\LoadRawTableData;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
 
8
  class AuditTrail {
@@ -10,7 +10,7 @@ class AuditTrail {
10
  use ModConsumer;
11
 
12
  public function render() {
13
- $rows = ( new LoadRawTableData() )
14
  ->setMod( $this->getMod() )
15
  ->loadForLogs();
16
 
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Tables\Render\WpCliTable;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\Lib\LogTable\BuildAuditTableData;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
 
8
  class AuditTrail {
10
  use ModConsumer;
11
 
12
  public function render() {
13
+ $rows = ( new BuildAuditTableData() )
14
  ->setMod( $this->getMod() )
15
  ->loadForLogs();
16
 
src/lib/src/Tests/RunTests.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Tests;
4
 
1
+ <?php declare( strict_types=1 );
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Tests;
4
 
src/lib/src/Users/BulkUpdateUserMeta.php CHANGED
@@ -20,7 +20,8 @@ class BulkUpdateUserMeta extends ExecOnceModConsumer {
20
  protected function run() {
21
  $con = $this->getCon();
22
  $userSearch = new \WP_User_Query( [
23
- 'exclude' => $this->getExistingUserMetaIDs()
 
24
  ] );
25
  foreach ( $userSearch->get_results() as $user ) {
26
  $con->getUserMeta( $user );
20
  protected function run() {
21
  $con = $this->getCon();
22
  $userSearch = new \WP_User_Query( [
23
+ 'exclude' => $this->getExistingUserMetaIDs(),
24
+ 'number' => 20,
25
  ] );
26
  foreach ( $userSearch->get_results() as $user ) {
27
  $con->getUserMeta( $user );
src/lib/src/Users/ShieldUserMeta.php CHANGED
@@ -79,12 +79,4 @@ class ShieldUserMeta extends UserMeta {
79
  }
80
  return $this;
81
  }
82
-
83
- /**
84
- * @return $this
85
- * @deprecated 13.1
86
- */
87
- public function updateFirstSeenAt() {
88
- return $this;
89
- }
90
  }
79
  }
80
  return $this;
81
  }
 
 
 
 
 
 
 
 
82
  }
src/lib/src/Utilities/AdminNotices/Controller.php CHANGED
@@ -60,25 +60,25 @@ class Controller {
60
  }
61
 
62
  protected function displayNotices() {
63
- foreach ( $this->collectAllPluginNotices() as $sKey => $oNotice ) {
64
- echo $this->renderNotice( $oNotice );
65
  }
66
  }
67
 
68
  /**
69
  * @return NoticeVO[]
70
  */
71
- protected function collectAllPluginNotices() {
72
- /** @var NoticeVO[] $aNotices */
73
- $aNotices = apply_filters( $this->getCon()->prefix( 'collectNotices' ), [] );
74
- if ( !is_array( $aNotices ) ) {
75
- $aNotices = [];
76
  }
77
- $aNotices[] = $this->getFlashNotice();
78
  return array_filter(
79
- $aNotices,
80
- function ( $oNotice ) {
81
- return ( $oNotice instanceof NoticeVO );
82
  }
83
  );
84
  }
@@ -113,7 +113,8 @@ class Controller {
113
  $msg = null;
114
  $meta = $this->getCon()->getCurrentUserMeta();
115
  if ( $meta instanceof UserMeta && is_array( $meta->flash_msg ) ) {
116
- if ( empty( $meta->flash_msg[ 'expires_at' ] ) || Services::Request()->ts() < $meta->flash_msg[ 'expires_at' ] ) {
 
117
  $msg = $meta->flash_msg;
118
  }
119
  else {
@@ -123,10 +124,7 @@ class Controller {
123
  return $msg;
124
  }
125
 
126
- /**
127
- * @return $this
128
- */
129
- private function clearFlashMessage() {
130
  $meta = $this->getCon()->getCurrentUserMeta();
131
  if ( $meta instanceof UserMeta && !empty( $meta->flash_msg ) ) {
132
  $meta->flash_msg = null;
@@ -134,35 +132,31 @@ class Controller {
134
  return $this;
135
  }
136
 
137
- /**
138
- * @param NoticeVO $oNotice
139
- * @return string
140
- */
141
- protected function renderNotice( $oNotice ) {
142
- $aRenderVars = $oNotice->render_data;
143
 
144
- if ( empty( $aRenderVars[ 'notice_classes' ] ) || !is_array( $aRenderVars[ 'notice_classes' ] ) ) {
145
- $aRenderVars[ 'notice_classes' ] = [];
146
  }
147
- $aRenderVars[ 'notice_classes' ][] = $oNotice->type;
148
- if ( !in_array( 'error', $aRenderVars[ 'notice_classes' ] ) ) {
149
- $aRenderVars[ 'notice_classes' ][] = 'updated';
150
  }
151
- $aRenderVars[ 'notice_classes' ][] = 'notice-'.$oNotice->id;
152
- $aRenderVars[ 'notice_classes' ] = implode( ' ', array_unique( $aRenderVars[ 'notice_classes' ] ) );
153
 
154
- $aRenderVars[ 'unique_render_id' ] = uniqid( $oNotice->id );
155
- $aRenderVars[ 'notice_id' ] = $oNotice->id;
156
 
157
- $aAjaxData = $this->getCon()->getNonceActionData( 'dismiss_admin_notice' );
158
- $aAjaxData[ 'hide' ] = 1;
159
- $aAjaxData[ 'notice_id' ] = $oNotice->id;
160
- $aRenderVars[ 'ajax' ][ 'dismiss_admin_notice' ] = json_encode( $aAjaxData );
161
 
162
  return $this->getCon()
163
  ->getRenderer()
164
- ->setTemplate( $oNotice->template )
165
- ->setRenderVars( $aRenderVars )
166
  ->setTemplateEngineTwig()
167
  ->render();
168
  }
60
  }
61
 
62
  protected function displayNotices() {
63
+ foreach ( $this->collectAllPluginNotices() as $notice ) {
64
+ echo $this->renderNotice( $notice );
65
  }
66
  }
67
 
68
  /**
69
  * @return NoticeVO[]
70
  */
71
+ protected function collectAllPluginNotices() :array {
72
+ /** @var NoticeVO[] $notices */
73
+ $notices = apply_filters( $this->getCon()->prefix( 'collectNotices' ), [] );
74
+ if ( !is_array( $notices ) ) {
75
+ $notices = [];
76
  }
77
+ $notices[] = $this->getFlashNotice();
78
  return array_filter(
79
+ $notices,
80
+ function ( $notice ) {
81
+ return ( $notice instanceof NoticeVO );
82
  }
83
  );
84
  }
113
  $msg = null;
114
  $meta = $this->getCon()->getCurrentUserMeta();
115
  if ( $meta instanceof UserMeta && is_array( $meta->flash_msg ) ) {
116
+ if ( empty( $meta->flash_msg[ 'expires_at' ] ) || Services::Request()
117
+ ->ts() < $meta->flash_msg[ 'expires_at' ] ) {
118
  $msg = $meta->flash_msg;
119
  }
120
  else {
124
  return $msg;
125
  }
126
 
127
+ private function clearFlashMessage() :self {
 
 
 
128
  $meta = $this->getCon()->getCurrentUserMeta();
129
  if ( $meta instanceof UserMeta && !empty( $meta->flash_msg ) ) {
130
  $meta->flash_msg = null;
132
  return $this;
133
  }
134
 
135
+ protected function renderNotice( NoticeVO $notice ) :string {
136
+ $data = $notice->render_data;
 
 
 
 
137
 
138
+ if ( empty( $data[ 'notice_classes' ] ) || !is_array( $data[ 'notice_classes' ] ) ) {
139
+ $data[ 'notice_classes' ] = [];
140
  }
141
+ $data[ 'notice_classes' ][] = $notice->type;
142
+ if ( !in_array( 'error', $data[ 'notice_classes' ] ) ) {
143
+ $data[ 'notice_classes' ][] = 'updated';
144
  }
145
+ $data[ 'notice_classes' ][] = 'notice-'.$notice->id;
146
+ $data[ 'notice_classes' ] = implode( ' ', array_unique( $data[ 'notice_classes' ] ) );
147
 
148
+ $data[ 'unique_render_id' ] = uniqid( $notice->id );
149
+ $data[ 'notice_id' ] = $notice->id;
150
 
151
+ $ajaxData = $this->getCon()->getNonceActionData( 'dismiss_admin_notice' );
152
+ $ajaxData[ 'hide' ] = 1;
153
+ $ajaxData[ 'notice_id' ] = $notice->id;
154
+ $data[ 'ajax' ][ 'dismiss_admin_notice' ] = json_encode( $ajaxData );
155
 
156
  return $this->getCon()
157
  ->getRenderer()
158
+ ->setTemplate( $notice->template )
159
+ ->setRenderVars( $data )
160
  ->setTemplateEngineTwig()
161
  ->render();
162
  }
src/lib/src/Utilities/MU/.mu-template.txt ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+ /*
3
+ * Plugin Name: SHIELD_PLUGIN_NAME (MU)
4
+ * Plugin URI: SHIELD_PLUGIN_URL
5
+ * Description: The Must-Use (MU) version of the SHIELD_PLUGIN_NAME plugin. To disable this, first turn-off the option within the Security Admin module.
6
+ * Author: SHIELD_PLUGIN_AUTHOR
7
+ * Author URI: SHIELD_PLUGIN_URL
8
+ */
9
+
10
+ call_user_func( function () {
11
+ $shieldFile = 'SHIELD_ROOT_FILE';
12
+ if ( file_exists( $shieldFile ) ) {
13
+ require_once( $shieldFile );
14
+ }
15
+ else {
16
+ add_action( 'admin_notices', function () {
17
+ echo sprintf(
18
+ '<div id="message" class="error">'.
19
+ '<p>The SHIELD_PLUGIN_NAME plugin appears to have been removed. Please also remove the MU-Plugin file: <code>%s</code>.</p></div>',
20
+ esc_html( __FILE__ )
21
+ );
22
+ } );
23
+ }
24
+ } );
src/lib/src/Utilities/MU/MUHandler.php ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Utilities\MU;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\PluginControllerConsumer;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
+
8
+ class MUHandler {
9
+
10
+ use PluginControllerConsumer;
11
+
12
+ const PLUGIN_FILE_NAME = 'a-shield-mu.php';
13
+
14
+ public function isActiveMU() :bool {
15
+ return Services::WpFs()->isFile( $this->getMuFilePath() );
16
+ }
17
+
18
+ /**
19
+ * @throws \Exception
20
+ */
21
+ public function convertToStandard() :bool {
22
+ if ( $this->isActiveMU() ) {
23
+ $file = $this->getMuFilePath();
24
+ Services::WpFs()->deleteFile( $file );
25
+ if ( $this->isActiveMU() ) {
26
+ throw new \Exception( sprintf( 'Could not delete the MU File: %s', $file ) );
27
+ }
28
+ }
29
+ return !$this->isActiveMU();
30
+ }
31
+
32
+ /**
33
+ * @throws \Exception
34
+ */
35
+ public function convertToMU() :bool {
36
+ $FS = Services::WpFs();
37
+
38
+ if ( !Services::WpGeneral()->getWordpressIsAtLeastVersion( '5.6' ) ) {
39
+ throw new \Exception( sprintf( 'WP Version must be at least: %s', '5.6' ) );
40
+ }
41
+
42
+ $muDir = $this->getMuDir();
43
+ if ( !$FS->isDir( $muDir ) ) {
44
+ $FS->mkdir( $muDir );
45
+ }
46
+
47
+ if ( !$FS->isDir( $muDir ) ) {
48
+ throw new \Exception( sprintf( 'Could not create MU Dir: %s', $muDir ) );
49
+ }
50
+
51
+ $file = $this->getMuFilePath();
52
+ $content = $this->buildContent();
53
+ $FS->putFileContent( $file, $content );
54
+
55
+ if ( !$FS->isFile( $file ) ) {
56
+ throw new \Exception( sprintf( 'Could not create MU File: %s', $file ) );
57
+ }
58
+ if ( $FS->getFileContent( $file ) !== $content ) {
59
+ throw new \Exception( sprintf( 'Could not write content to MU File: %s', $file ) );
60
+ }
61
+
62
+ // Now test we haven't destroyed the site loading.
63
+ if ( !$this->testLoopback() ) {
64
+ $this->convertToStandard();
65
+ throw new \Exception( "Cancelled - Could not verify site loads successfully" );
66
+ }
67
+
68
+ return $this->isActiveMU();
69
+ }
70
+
71
+ protected function testLoopback() :bool {
72
+ $status = Services::Rest()->callInternal( [
73
+ 'route' => '/wp-site-health/v1/tests/loopback-requests'
74
+ ] )->get_data()[ 'status' ] ?? '';
75
+ return $status === 'good';
76
+ }
77
+
78
+ private function getMuFilePath() :string {
79
+ return path_join( $this->getMuDir(), self::PLUGIN_FILE_NAME );
80
+ }
81
+
82
+ private function getMuDir() :string {
83
+ return defined( 'WPMU_PLUGIN_DIR' ) ? WPMU_PLUGIN_DIR :
84
+ path_join( dirname( $this->getCon()->getRootDir(), 2 ), 'mu-plugins' );
85
+ }
86
+
87
+ /**
88
+ * @throws \Exception
89
+ */
90
+ private function buildContent() :string {
91
+ $con = $this->getCon();
92
+ $FS = Services::WpFs();
93
+ $templateFile = path_join( __DIR__, '.mu-template.txt' );
94
+ $template = $FS->getFileContent( $templateFile );
95
+ if ( empty( $template ) ) {
96
+ throw new \Exception( sprintf( "Couldn't read mu-plugin template from %s", $templateFile ) );
97
+ }
98
+ $replacements = [
99
+ 'SHIELD_ROOT_FILE' => $con->getRootFile(),
100
+ 'SHIELD_PLUGIN_NAME' => $con->getHumanName(),
101
+ 'SHIELD_PLUGIN_URL' => $con->getLabels()[ 'PluginURI' ],
102
+ 'SHIELD_PLUGIN_AUTHOR' => $con->getLabels()[ 'Author' ],
103
+ ];
104
+ return str_replace( array_keys( $replacements ), array_values( $replacements ), $template );
105
+ }
106
+ }
src/lib/vendor/composer/ClassLoader.php CHANGED
@@ -42,30 +42,75 @@ namespace Composer\Autoload;
42
  */
43
  class ClassLoader
44
  {
 
45
  private $vendorDir;
46
 
47
  // PSR-4
 
 
 
 
48
  private $prefixLengthsPsr4 = array();
 
 
 
 
49
  private $prefixDirsPsr4 = array();
 
 
 
 
50
  private $fallbackDirsPsr4 = array();
51
 
52
  // PSR-0
 
 
 
 
53
  private $prefixesPsr0 = array();
 
 
 
 
54
  private $fallbackDirsPsr0 = array();
55
 
 
56
  private $useIncludePath = false;
 
 
 
 
 
57
  private $classMap = array();
 
 
58
  private $classMapAuthoritative = false;
 
 
 
 
 
59
  private $missingClasses = array();
 
 
60
  private $apcuPrefix;
61
 
 
 
 
62
  private static $registeredLoaders = array();
63
 
 
 
 
64
  public function __construct($vendorDir = null)
65
  {
66
  $this->vendorDir = $vendorDir;
67
  }
68
 
 
 
 
69
  public function getPrefixes()
70
  {
71
  if (!empty($this->prefixesPsr0)) {
@@ -75,28 +120,47 @@ class ClassLoader
75
  return array();
76
  }
77
 
 
 
 
 
78
  public function getPrefixesPsr4()
79
  {
80
  return $this->prefixDirsPsr4;
81
  }
82
 
 
 
 
 
83
  public function getFallbackDirs()
84
  {
85
  return $this->fallbackDirsPsr0;
86
  }
87
 
 
 
 
 
88
  public function getFallbackDirsPsr4()
89
  {
90
  return $this->fallbackDirsPsr4;
91
  }
92
 
 
 
 
 
93
  public function getClassMap()
94
  {
95
  return $this->classMap;
96
  }
97
 
98
  /**
99
- * @param array $classMap Class to filename map
 
 
 
100
  */
101
  public function addClassMap(array $classMap)
102
  {
@@ -111,9 +175,11 @@ class ClassLoader
111
  * Registers a set of PSR-0 directories for a given prefix, either
112
  * appending or prepending to the ones previously set for this prefix.
113
  *
114
- * @param string $prefix The prefix
115
- * @param array|string $paths The PSR-0 root directories
116
- * @param bool $prepend Whether to prepend the directories
 
 
117
  */
118
  public function add($prefix, $paths, $prepend = false)
119
  {
@@ -156,11 +222,13 @@ class ClassLoader
156
  * Registers a set of PSR-4 directories for a given namespace, either
157
  * appending or prepending to the ones previously set for this namespace.
158
  *
159
- * @param string $prefix The prefix/namespace, with trailing '\\'
160
- * @param array|string $paths The PSR-4 base directories
161
- * @param bool $prepend Whether to prepend the directories
162
  *
163
  * @throws \InvalidArgumentException
 
 
164
  */
165
  public function addPsr4($prefix, $paths, $prepend = false)
166
  {
@@ -204,8 +272,10 @@ class ClassLoader
204
  * Registers a set of PSR-0 directories for a given prefix,
205
  * replacing any others previously set for this prefix.
206
  *
207
- * @param string $prefix The prefix
208
- * @param array|string $paths The PSR-0 base directories
 
 
209
  */
210
  public function set($prefix, $paths)
211
  {
@@ -220,10 +290,12 @@ class ClassLoader
220
  * Registers a set of PSR-4 directories for a given namespace,
221
  * replacing any others previously set for this namespace.
222
  *
223
- * @param string $prefix The prefix/namespace, with trailing '\\'
224
- * @param array|string $paths The PSR-4 base directories
225
  *
226
  * @throws \InvalidArgumentException
 
 
227
  */
228
  public function setPsr4($prefix, $paths)
229
  {
@@ -243,6 +315,8 @@ class ClassLoader
243
  * Turns on searching the include path for class files.
244
  *
245
  * @param bool $useIncludePath
 
 
246
  */
247
  public function setUseIncludePath($useIncludePath)
248
  {
@@ -265,6 +339,8 @@ class ClassLoader
265
  * that have not been registered with the class map.
266
  *
267
  * @param bool $classMapAuthoritative
 
 
268
  */
269
  public function setClassMapAuthoritative($classMapAuthoritative)
270
  {
@@ -285,6 +361,8 @@ class ClassLoader
285
  * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
286
  *
287
  * @param string|null $apcuPrefix
 
 
288
  */
289
  public function setApcuPrefix($apcuPrefix)
290
  {
@@ -305,14 +383,18 @@ class ClassLoader
305
  * Registers this instance as an autoloader.
306
  *
307
  * @param bool $prepend Whether to prepend the autoloader or not
 
 
308
  */
309
  public function register($prepend = false)
310
  {
311
  spl_autoload_register(array($this, 'loadClass'), true, $prepend);
312
 
313
  if (null === $this->vendorDir) {
314
- //no-op
315
- } elseif ($prepend) {
 
 
316
  self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
317
  } else {
318
  unset(self::$registeredLoaders[$this->vendorDir]);
@@ -322,6 +404,8 @@ class ClassLoader
322
 
323
  /**
324
  * Unregisters this instance as an autoloader.
 
 
325
  */
326
  public function unregister()
327
  {
@@ -336,7 +420,7 @@ class ClassLoader
336
  * Loads the given class or interface.
337
  *
338
  * @param string $class The name of the class
339
- * @return bool|null True if loaded, null otherwise
340
  */
341
  public function loadClass($class)
342
  {
@@ -345,6 +429,8 @@ class ClassLoader
345
 
346
  return true;
347
  }
 
 
348
  }
349
 
350
  /**
@@ -399,6 +485,11 @@ class ClassLoader
399
  return self::$registeredLoaders;
400
  }
401
 
 
 
 
 
 
402
  private function findFileWithExtension($class, $ext)
403
  {
404
  // PSR-4 lookup
@@ -470,6 +561,10 @@ class ClassLoader
470
  * Scope isolated include.
471
  *
472
  * Prevents access to $this/self from included files.
 
 
 
 
473
  */
474
  function includeFile($file)
475
  {
42
  */
43
  class ClassLoader
44
  {
45
+ /** @var ?string */
46
  private $vendorDir;
47
 
48
  // PSR-4
49
+ /**
50
+ * @var array[]
51
+ * @psalm-var array<string, array<string, int>>
52
+ */
53
  private $prefixLengthsPsr4 = array();
54
+ /**
55
+ * @var array[]
56
+ * @psalm-var array<string, array<int, string>>
57
+ */
58
  private $prefixDirsPsr4 = array();
59
+ /**
60
+ * @var array[]
61
+ * @psalm-var array<string, string>
62
+ */
63
  private $fallbackDirsPsr4 = array();
64
 
65
  // PSR-0
66
+ /**
67
+ * @var array[]
68
+ * @psalm-var array<string, array<string, string[]>>
69
+ */
70
  private $prefixesPsr0 = array();
71
+ /**
72
+ * @var array[]
73
+ * @psalm-var array<string, string>
74
+ */
75
  private $fallbackDirsPsr0 = array();
76
 
77
+ /** @var bool */
78
  private $useIncludePath = false;
79
+
80
+ /**
81
+ * @var string[]
82
+ * @psalm-var array<string, string>
83
+ */
84
  private $classMap = array();
85
+
86
+ /** @var bool */
87
  private $classMapAuthoritative = false;
88
+
89
+ /**
90
+ * @var bool[]
91
+ * @psalm-var array<string, bool>
92
+ */
93
  private $missingClasses = array();
94
+
95
+ /** @var ?string */
96
  private $apcuPrefix;
97
 
98
+ /**
99
+ * @var self[]
100
+ */
101
  private static $registeredLoaders = array();
102
 
103
+ /**
104
+ * @param ?string $vendorDir
105
+ */
106
  public function __construct($vendorDir = null)
107
  {
108
  $this->vendorDir = $vendorDir;
109
  }
110
 
111
+ /**
112
+ * @return string[]
113
+ */
114
  public function getPrefixes()
115
  {
116
  if (!empty($this->prefixesPsr0)) {
120
  return array();
121
  }
122
 
123
+ /**
124
+ * @return array[]
125
+ * @psalm-return array<string, array<int, string>>
126
+ */
127
  public function getPrefixesPsr4()
128
  {
129
  return $this->prefixDirsPsr4;
130
  }
131
 
132
+ /**
133
+ * @return array[]
134
+ * @psalm-return array<string, string>
135
+ */
136
  public function getFallbackDirs()
137
  {
138
  return $this->fallbackDirsPsr0;
139
  }
140
 
141
+ /**
142
+ * @return array[]
143
+ * @psalm-return array<string, string>
144
+ */
145
  public function getFallbackDirsPsr4()
146
  {
147
  return $this->fallbackDirsPsr4;
148
  }
149
 
150
+ /**
151
+ * @return string[] Array of classname => path
152
+ * @psalm-return array<string, string>
153
+ */
154
  public function getClassMap()
155
  {
156
  return $this->classMap;
157
  }
158
 
159
  /**
160
+ * @param string[] $classMap Class to filename map
161
+ * @psalm-param array<string, string> $classMap
162
+ *
163
+ * @return void
164
  */
165
  public function addClassMap(array $classMap)
166
  {
175
  * Registers a set of PSR-0 directories for a given prefix, either
176
  * appending or prepending to the ones previously set for this prefix.
177
  *
178
+ * @param string $prefix The prefix
179
+ * @param string[]|string $paths The PSR-0 root directories
180
+ * @param bool $prepend Whether to prepend the directories
181
+ *
182
+ * @return void
183
  */
184
  public function add($prefix, $paths, $prepend = false)
185
  {
222
  * Registers a set of PSR-4 directories for a given namespace, either
223
  * appending or prepending to the ones previously set for this namespace.
224
  *
225
+ * @param string $prefix The prefix/namespace, with trailing '\\'
226
+ * @param string[]|string $paths The PSR-4 base directories
227
+ * @param bool $prepend Whether to prepend the directories
228
  *
229
  * @throws \InvalidArgumentException
230
+ *
231
+ * @return void
232
  */
233
  public function addPsr4($prefix, $paths, $prepend = false)
234
  {
272
  * Registers a set of PSR-0 directories for a given prefix,
273
  * replacing any others previously set for this prefix.
274
  *
275
+ * @param string $prefix The prefix
276
+ * @param string[]|string $paths The PSR-0 base directories
277
+ *
278
+ * @return void
279
  */
280
  public function set($prefix, $paths)
281
  {
290
  * Registers a set of PSR-4 directories for a given namespace,
291
  * replacing any others previously set for this namespace.
292
  *
293
+ * @param string $prefix The prefix/namespace, with trailing '\\'
294
+ * @param string[]|string $paths The PSR-4 base directories
295
  *
296
  * @throws \InvalidArgumentException
297
+ *
298
+ * @return void
299
  */
300
  public function setPsr4($prefix, $paths)
301
  {
315
  * Turns on searching the include path for class files.
316
  *
317
  * @param bool $useIncludePath
318
+ *
319
+ * @return void
320
  */
321
  public function setUseIncludePath($useIncludePath)
322
  {
339
  * that have not been registered with the class map.
340
  *
341
  * @param bool $classMapAuthoritative
342
+ *
343
+ * @return void
344
  */
345
  public function setClassMapAuthoritative($classMapAuthoritative)
346
  {
361
  * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
362
  *
363
  * @param string|null $apcuPrefix
364
+ *
365
+ * @return void
366
  */
367
  public function setApcuPrefix($apcuPrefix)
368
  {
383
  * Registers this instance as an autoloader.
384
  *
385
  * @param bool $prepend Whether to prepend the autoloader or not
386
+ *
387
+ * @return void
388
  */
389
  public function register($prepend = false)
390
  {
391
  spl_autoload_register(array($this, 'loadClass'), true, $prepend);
392
 
393
  if (null === $this->vendorDir) {
394
+ return;
395
+ }
396
+
397
+ if ($prepend) {
398
  self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
399
  } else {
400
  unset(self::$registeredLoaders[$this->vendorDir]);
404
 
405
  /**
406
  * Unregisters this instance as an autoloader.
407
+ *
408
+ * @return void
409
  */
410
  public function unregister()
411
  {
420
  * Loads the given class or interface.
421
  *
422
  * @param string $class The name of the class
423
+ * @return true|null True if loaded, null otherwise
424
  */
425
  public function loadClass($class)
426
  {
429
 
430
  return true;
431
  }
432
+
433
+ return null;
434
  }
435
 
436
  /**
485
  return self::$registeredLoaders;
486
  }
487
 
488
+ /**
489
+ * @param string $class
490
+ * @param string $ext
491
+ * @return string|false
492
+ */
493
  private function findFileWithExtension($class, $ext)
494
  {
495
  // PSR-4 lookup
561
  * Scope isolated include.
562
  *
563
  * Prevents access to $this/self from included files.
564
+ *
565
+ * @param string $file
566
+ * @return void
567
+ * @private
568
  */
569
  function includeFile($file)
570
  {
src/lib/vendor/composer/autoload_classmap.php CHANGED
@@ -47,9 +47,22 @@ return array(
47
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Databases\\Common\\Iterator' => $vendorDir . '/fernleafsystems/wordpress-plugin-core/src/Databases/Common/Iterator.php',
48
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Databases\\Common\\RecordConsumer' => $vendorDir . '/fernleafsystems/wordpress-plugin-core/src/Databases/Common/RecordConsumer.php',
49
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Databases\\Common\\SubQueryLoader' => $vendorDir . '/fernleafsystems/wordpress-plugin-core/src/Databases/Common/SubQueryLoader.php',
 
50
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Databases\\Common\\TableSchema' => $vendorDir . '/fernleafsystems/wordpress-plugin-core/src/Databases/Common/TableSchema.php',
51
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Databases\\Exceptions\\ColumnDoesNotExistException' => $vendorDir . '/fernleafsystems/wordpress-plugin-core/src/Databases/Exceptions/ColumnDoesNotExistException.php',
52
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Databases\\Exceptions\\NoSlugProvidedException' => $vendorDir . '/fernleafsystems/wordpress-plugin-core/src/Databases/Exceptions/NoSlugProvidedException.php',
 
 
 
 
 
 
 
 
 
 
 
 
53
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Utility\\User\\PluginMeta' => $vendorDir . '/fernleafsystems/wordpress-plugin-core/src/Utility/User/PluginMeta.php',
54
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Diff\\Base' => $baseDir . '/src/ChangeTrack/Diff/Base.php',
55
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Diff\\DiffComments' => $baseDir . '/src/ChangeTrack/Diff/DiffComments.php',
@@ -214,8 +227,9 @@ return array(
214
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\LogHandlers\\LogFileHandler' => $baseDir . '/src/Modules/AuditTrail/Lib/LogHandlers/LogFileHandler.php',
215
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\LogHandlers\\Utility\\LogFileDirCreate' => $baseDir . '/src/Modules/AuditTrail/Lib/LogHandlers/Utility/LogFileDirCreate.php',
216
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\LogHandlers\\Utility\\LogFileRotate' => $baseDir . '/src/Modules/AuditTrail/Lib/LogHandlers/Utility/LogFileRotate.php',
 
 
217
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\LogTable\\DelegateAjaxHandler' => $baseDir . '/src/Modules/AuditTrail/Lib/LogTable/DelegateAjaxHandler.php',
218
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\LogTable\\LoadRawTableData' => $baseDir . '/src/Modules/AuditTrail/Lib/LogTable/LoadRawTableData.php',
219
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\Utility\\GetLogFileContent' => $baseDir . '/src/Modules/AuditTrail/Lib/Utility/GetLogFileContent.php',
220
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\ModCon' => $baseDir . '/src/Modules/AuditTrail/ModCon.php',
221
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Options' => $baseDir . '/src/Modules/AuditTrail/Options.php',
@@ -248,14 +262,6 @@ return array(
248
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Insights\\OverviewCards' => $baseDir . '/src/Modules/Base/Insights/OverviewCards.php',
249
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Components\\UiTrack' => $baseDir . '/src/Modules/Base/Lib/Components/UiTrack.php',
250
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Request\\FormParams' => $baseDir . '/src/Modules/Base/Lib/Request/FormParams.php',
251
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\RequestVoConsumer' => $baseDir . '/src/Modules/Base/Lib/Rest/RequestVoConsumer.php',
252
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Request\\Process' => $baseDir . '/src/Modules/Base/Lib/Rest/Request/Process.php',
253
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Request\\RequestVO' => $baseDir . '/src/Modules/Base/Lib/Rest/Request/RequestVO.php',
254
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Route\\RestRouteConsumer' => $baseDir . '/src/Modules/Base/Lib/Rest/Route/RestRouteConsumer.php',
255
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Route\\RouteBase' => $baseDir . '/src/Modules/Base/Lib/Rest/Route/RouteBase.php',
256
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Route\\RouteCache' => $baseDir . '/src/Modules/Base/Lib/Rest/Route/RouteCache.php',
257
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Utility\\PreChecks' => $baseDir . '/src/Modules/Base/Lib/Rest/Utility/PreChecks.php',
258
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Utility\\RestLocker' => $baseDir . '/src/Modules/Base/Lib/Rest/Utility/RestLocker.php',
259
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\ModCon' => $baseDir . '/src/Modules/Base/ModCon.php',
260
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Options' => $baseDir . '/src/Modules/Base/Options.php',
261
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Options\\BuildForDisplay' => $baseDir . '/src/Modules/Base/Options/BuildForDisplay.php',
@@ -264,7 +270,12 @@ return array(
264
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Options\\WildCardOptions' => $baseDir . '/src/Modules/Base/Options/WildCardOptions.php',
265
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Processor' => $baseDir . '/src/Modules/Base/Processor.php',
266
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Reporting' => $baseDir . '/src/Modules/Base/Reporting.php',
267
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\RestHandler' => $baseDir . '/src/Modules/Base/RestHandler.php',
 
 
 
 
 
268
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Strings' => $baseDir . '/src/Modules/Base/Strings.php',
269
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\UI' => $baseDir . '/src/Modules/Base/UI.php',
270
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Upgrade' => $baseDir . '/src/Modules/Base/Upgrade.php',
@@ -320,7 +331,9 @@ return array(
320
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Data\\DB\\UserMeta\\Ops\\Record' => $baseDir . '/src/Modules/Data/DB/UserMeta/Ops/Record.php',
321
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Data\\DB\\UserMeta\\Ops\\Select' => $baseDir . '/src/Modules/Data/DB/UserMeta/Ops/Select.php',
322
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Data\\Lib\\GeoIP\\Lookup' => $baseDir . '/src/Modules/Data/Lib/GeoIP/Lookup.php',
 
323
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Data\\ModCon' => $baseDir . '/src/Modules/Data/ModCon.php',
 
324
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Email\\ModCon' => $baseDir . '/src/Modules/Email/ModCon.php',
325
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Email\\Options' => $baseDir . '/src/Modules/Email/Options.php',
326
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Email\\Processor' => $baseDir . '/src/Modules/Email/Processor.php',
@@ -437,7 +450,6 @@ return array(
437
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\Store' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/Store.php',
438
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\Base' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/Base.php',
439
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\BaseAction' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/BaseAction.php',
440
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\BaseBulk' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/BaseBulk.php',
441
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\Build' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/Build.php',
442
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\CleanStale' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/CleanStale.php',
443
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\CreateNew' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/CreateNew.php',
@@ -458,6 +470,18 @@ return array(
458
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Render\\ScanResults\\SectionThemes' => $baseDir . '/src/Modules/HackGuard/Render/ScanResults/SectionThemes.php',
459
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Render\\ScanResults\\SectionWordpress' => $baseDir . '/src/Modules/HackGuard/Render/ScanResults/SectionWordpress.php',
460
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Reporting' => $baseDir . '/src/Modules/HackGuard/Reporting.php',
 
 
 
 
 
 
 
 
 
 
 
 
461
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Scan\\Controller\\Afs' => $baseDir . '/src/Modules/HackGuard/Scan/Controller/Afs.php',
462
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Scan\\Controller\\Apc' => $baseDir . '/src/Modules/HackGuard/Scan/Controller/Apc.php',
463
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Scan\\Controller\\Base' => $baseDir . '/src/Modules/HackGuard/Scan/Controller/Base.php',
@@ -555,6 +579,22 @@ return array(
555
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\ModCon' => $baseDir . '/src/Modules/IPs/ModCon.php',
556
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Options' => $baseDir . '/src/Modules/IPs/Options.php',
557
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Processor' => $baseDir . '/src/Modules/IPs/Processor.php',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
558
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Strings' => $baseDir . '/src/Modules/IPs/Strings.php',
559
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\UI' => $baseDir . '/src/Modules/IPs/UI.php',
560
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Upgrade' => $baseDir . '/src/Modules/IPs/Upgrade.php',
@@ -649,6 +689,14 @@ return array(
649
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\ModCon' => $baseDir . '/src/Modules/License/ModCon.php',
650
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Options' => $baseDir . '/src/Modules/License/Options.php',
651
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Processor' => $baseDir . '/src/Modules/License/Processor.php',
 
 
 
 
 
 
 
 
652
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Strings' => $baseDir . '/src/Modules/License/Strings.php',
653
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\UI' => $baseDir . '/src/Modules/License/UI.php',
654
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\WpCli' => $baseDir . '/src/Modules/License/WpCli.php',
@@ -738,6 +786,7 @@ return array(
738
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Lib\\ImportExport\\Options\\BuildTransferableOptions' => $baseDir . '/src/Modules/Plugin/Lib/ImportExport/Options/BuildTransferableOptions.php',
739
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Lib\\ImportExport\\Options\\SaveExcludedOptions' => $baseDir . '/src/Modules/Plugin/Lib/ImportExport/Options/SaveExcludedOptions.php',
740
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Lib\\Ops\\ResetPlugin' => $baseDir . '/src/Modules/Plugin/Lib/Ops/ResetPlugin.php',
 
741
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Lib\\OverrideLocale' => $baseDir . '/src/Modules/Plugin/Lib/OverrideLocale.php',
742
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Lib\\PluginTelemetry' => $baseDir . '/src/Modules/Plugin/Lib/PluginTelemetry.php',
743
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Lib\\TestCacheDirWrite' => $baseDir . '/src/Modules/Plugin/Lib/TestCacheDirWrite.php',
@@ -745,6 +794,23 @@ return array(
745
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\ModCon' => $baseDir . '/src/Modules/Plugin/ModCon.php',
746
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Options' => $baseDir . '/src/Modules/Plugin/Options.php',
747
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Processor' => $baseDir . '/src/Modules/Plugin/Processor.php',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
748
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Strings' => $baseDir . '/src/Modules/Plugin/Strings.php',
749
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\UI' => $baseDir . '/src/Modules/Plugin/UI.php',
750
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Upgrade' => $baseDir . '/src/Modules/Plugin/Upgrade.php',
@@ -815,8 +881,9 @@ return array(
815
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Lib\\Limit\\TestIpLimit' => $baseDir . '/src/Modules/Traffic/Lib/Limit/TestIpLimit.php',
816
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Lib\\LogHandlers\\LocalDbWriter' => $baseDir . '/src/Modules/Traffic/Lib/LogHandlers/LocalDbWriter.php',
817
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Lib\\RequestLogger' => $baseDir . '/src/Modules/Traffic/Lib/RequestLogger.php',
 
 
818
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Lib\\TrafficTable\\DelegateAjaxHandler' => $baseDir . '/src/Modules/Traffic/Lib/TrafficTable/DelegateAjaxHandler.php',
819
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Lib\\TrafficTable\\LoadRawTableData' => $baseDir . '/src/Modules/Traffic/Lib/TrafficTable/LoadRawTableData.php',
820
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\ModCon' => $baseDir . '/src/Modules/Traffic/ModCon.php',
821
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Options' => $baseDir . '/src/Modules/Traffic/Options.php',
822
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Processor' => $baseDir . '/src/Modules/Traffic/Processor.php',
@@ -840,7 +907,6 @@ return array(
840
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Processor' => $baseDir . '/src/Modules/UserManagement/Processor.php',
841
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Strings' => $baseDir . '/src/Modules/UserManagement/Strings.php',
842
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\UI' => $baseDir . '/src/Modules/UserManagement/UI.php',
843
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Upgrade' => $baseDir . '/src/Modules/UserManagement/Upgrade.php',
844
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\WpCli' => $baseDir . '/src/Modules/UserManagement/WpCli.php',
845
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\WpCli\\SessionTerminate' => $baseDir . '/src/Modules/UserManagement/WpCli/SessionTerminate.php',
846
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Render\\LocateTemplateDirs' => $baseDir . '/src/Render/LocateTemplateDirs.php',
@@ -955,7 +1021,7 @@ return array(
955
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\DataTables\\Build\\Scans\\ForPluginTheme' => $baseDir . '/src/Tables/DataTables/Build/Scans/ForPluginTheme.php',
956
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\DataTables\\Build\\Scans\\ForWordpress' => $baseDir . '/src/Tables/DataTables/Build/Scans/ForWordpress.php',
957
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\DataTables\\Build\\Traffic\\ForTraffic' => $baseDir . '/src/Tables/DataTables/Build/Traffic/ForTraffic.php',
958
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\DataTables\\LoadData\\BaseLoadTableData' => $baseDir . '/src/Tables/DataTables/LoadData/BaseLoadTableData.php',
959
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\Common\\BaseTable' => $baseDir . '/src/Tables/Render/Common/BaseTable.php',
960
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\WpCliTable\\AuditTrail' => $baseDir . '/src/Tables/Render/WpCliTable/AuditTrail.php',
961
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\WpListTable\\AdminNotes' => $baseDir . '/src/Tables/Render/WpListTable/AdminNotes.php',
@@ -981,6 +1047,7 @@ return array(
981
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\HCaptcha\\TestRequest' => $baseDir . '/src/Utilities/HCaptcha/TestRequest.php',
982
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Htaccess\\RootHtaccess' => $baseDir . '/src/Utilities/Htaccess/RootHtaccess.php',
983
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\HumanSpam\\TestContent' => $baseDir . '/src/Utilities/HumanSpam/TestContent.php',
 
984
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Nonce\\Handler' => $baseDir . '/src/Utilities/Nonce/Handler.php',
985
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Options\\CleanStorage' => $baseDir . '/src/Utilities/Options/CleanStorage.php',
986
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\ReCaptcha\\Enqueue' => $baseDir . '/src/Utilities/ReCaptcha/Enqueue.php',
@@ -1032,6 +1099,7 @@ return array(
1032
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Code\\AssessPhpFile' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Code/AssessPhpFile.php',
1033
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Constants\\Regex' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Constants/Regex.php',
1034
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Consumers\\PluginConsumer' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Consumers/PluginConsumer.php',
 
1035
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Data' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Data.php',
1036
  'FernleafSystems\\Wordpress\\Services\\Utilities\\DataManipulation' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/DataManipulation.php',
1037
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Email' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Email.php',
47
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Databases\\Common\\Iterator' => $vendorDir . '/fernleafsystems/wordpress-plugin-core/src/Databases/Common/Iterator.php',
48
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Databases\\Common\\RecordConsumer' => $vendorDir . '/fernleafsystems/wordpress-plugin-core/src/Databases/Common/RecordConsumer.php',
49
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Databases\\Common\\SubQueryLoader' => $vendorDir . '/fernleafsystems/wordpress-plugin-core/src/Databases/Common/SubQueryLoader.php',
50
+ 'FernleafSystems\\Wordpress\\Plugin\\Core\\Databases\\Common\\TableReadyCache' => $vendorDir . '/fernleafsystems/wordpress-plugin-core/src/Databases/Common/TableReadyCache.php',
51
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Databases\\Common\\TableSchema' => $vendorDir . '/fernleafsystems/wordpress-plugin-core/src/Databases/Common/TableSchema.php',
52
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Databases\\Exceptions\\ColumnDoesNotExistException' => $vendorDir . '/fernleafsystems/wordpress-plugin-core/src/Databases/Exceptions/ColumnDoesNotExistException.php',
53
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Databases\\Exceptions\\NoSlugProvidedException' => $vendorDir . '/fernleafsystems/wordpress-plugin-core/src/Databases/Exceptions/NoSlugProvidedException.php',
54
+ 'FernleafSystems\\Wordpress\\Plugin\\Core\\Rest\\Exceptions\\ApiException' => $vendorDir . '/fernleafsystems/wordpress-plugin-core/src/Rest/Exceptions/ApiException.php',
55
+ 'FernleafSystems\\Wordpress\\Plugin\\Core\\Rest\\Exceptions\\ClientSideException' => $vendorDir . '/fernleafsystems/wordpress-plugin-core/src/Rest/Exceptions/ClientSideException.php',
56
+ 'FernleafSystems\\Wordpress\\Plugin\\Core\\Rest\\Exceptions\\CouldNotObtainLockException' => $vendorDir . '/fernleafsystems/wordpress-plugin-core/src/Rest/Exceptions/CouldNotObtainLockException.php',
57
+ 'FernleafSystems\\Wordpress\\Plugin\\Core\\Rest\\Exceptions\\InvalidRequestParametersException' => $vendorDir . '/fernleafsystems/wordpress-plugin-core/src/Rest/Exceptions/InvalidRequestParametersException.php',
58
+ 'FernleafSystems\\Wordpress\\Plugin\\Core\\Rest\\Exceptions\\ServerSideException' => $vendorDir . '/fernleafsystems/wordpress-plugin-core/src/Rest/Exceptions/ServerSideException.php',
59
+ 'FernleafSystems\\Wordpress\\Plugin\\Core\\Rest\\Request\\Process' => $vendorDir . '/fernleafsystems/wordpress-plugin-core/src/Rest/Request/Process.php',
60
+ 'FernleafSystems\\Wordpress\\Plugin\\Core\\Rest\\Request\\RequestVO' => $vendorDir . '/fernleafsystems/wordpress-plugin-core/src/Rest/Request/RequestVO.php',
61
+ 'FernleafSystems\\Wordpress\\Plugin\\Core\\Rest\\RestHandler' => $vendorDir . '/fernleafsystems/wordpress-plugin-core/src/Rest/RestHandler.php',
62
+ 'FernleafSystems\\Wordpress\\Plugin\\Core\\Rest\\Route\\RestRequestConsumer' => $vendorDir . '/fernleafsystems/wordpress-plugin-core/src/Rest/Route/RestRequestConsumer.php',
63
+ 'FernleafSystems\\Wordpress\\Plugin\\Core\\Rest\\Route\\RestRouteConsumer' => $vendorDir . '/fernleafsystems/wordpress-plugin-core/src/Rest/Route/RestRouteConsumer.php',
64
+ 'FernleafSystems\\Wordpress\\Plugin\\Core\\Rest\\Route\\RouteBase' => $vendorDir . '/fernleafsystems/wordpress-plugin-core/src/Rest/Route/RouteBase.php',
65
+ 'FernleafSystems\\Wordpress\\Plugin\\Core\\Rest\\Route\\RouteCache' => $vendorDir . '/fernleafsystems/wordpress-plugin-core/src/Rest/Route/RouteCache.php',
66
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Utility\\User\\PluginMeta' => $vendorDir . '/fernleafsystems/wordpress-plugin-core/src/Utility/User/PluginMeta.php',
67
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Diff\\Base' => $baseDir . '/src/ChangeTrack/Diff/Base.php',
68
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Diff\\DiffComments' => $baseDir . '/src/ChangeTrack/Diff/DiffComments.php',
227
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\LogHandlers\\LogFileHandler' => $baseDir . '/src/Modules/AuditTrail/Lib/LogHandlers/LogFileHandler.php',
228
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\LogHandlers\\Utility\\LogFileDirCreate' => $baseDir . '/src/Modules/AuditTrail/Lib/LogHandlers/Utility/LogFileDirCreate.php',
229
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\LogHandlers\\Utility\\LogFileRotate' => $baseDir . '/src/Modules/AuditTrail/Lib/LogHandlers/Utility/LogFileRotate.php',
230
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\LogTable\\BuildAuditTableData' => $baseDir . '/src/Modules/AuditTrail/Lib/LogTable/BuildAuditTableData.php',
231
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\LogTable\\BuildSearchPanesData' => $baseDir . '/src/Modules/AuditTrail/Lib/LogTable/BuildSearchPanesData.php',
232
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\LogTable\\DelegateAjaxHandler' => $baseDir . '/src/Modules/AuditTrail/Lib/LogTable/DelegateAjaxHandler.php',
 
233
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\Utility\\GetLogFileContent' => $baseDir . '/src/Modules/AuditTrail/Lib/Utility/GetLogFileContent.php',
234
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\ModCon' => $baseDir . '/src/Modules/AuditTrail/ModCon.php',
235
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Options' => $baseDir . '/src/Modules/AuditTrail/Options.php',
262
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Insights\\OverviewCards' => $baseDir . '/src/Modules/Base/Insights/OverviewCards.php',
263
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Components\\UiTrack' => $baseDir . '/src/Modules/Base/Lib/Components/UiTrack.php',
264
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Request\\FormParams' => $baseDir . '/src/Modules/Base/Lib/Request/FormParams.php',
 
 
 
 
 
 
 
 
265
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\ModCon' => $baseDir . '/src/Modules/Base/ModCon.php',
266
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Options' => $baseDir . '/src/Modules/Base/Options.php',
267
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Options\\BuildForDisplay' => $baseDir . '/src/Modules/Base/Options/BuildForDisplay.php',
270
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Options\\WildCardOptions' => $baseDir . '/src/Modules/Base/Options/WildCardOptions.php',
271
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Processor' => $baseDir . '/src/Modules/Base/Processor.php',
272
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Reporting' => $baseDir . '/src/Modules/Base/Reporting.php',
273
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Rest' => $baseDir . '/src/Modules/Base/Rest.php',
274
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Rest\\RequestVoConsumer' => $baseDir . '/src/Modules/Base/Rest/RequestVoConsumer.php',
275
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Rest\\Request\\Process' => $baseDir . '/src/Modules/Base/Rest/Request/Process.php',
276
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Rest\\Request\\RequestVO' => $baseDir . '/src/Modules/Base/Rest/Request/RequestVO.php',
277
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Rest\\Route\\RouteBase' => $baseDir . '/src/Modules/Base/Rest/Route/RouteBase.php',
278
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Rest\\Route\\RouteCache' => $baseDir . '/src/Modules/Base/Rest/Route/RouteCache.php',
279
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Strings' => $baseDir . '/src/Modules/Base/Strings.php',
280
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\UI' => $baseDir . '/src/Modules/Base/UI.php',
281
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Upgrade' => $baseDir . '/src/Modules/Base/Upgrade.php',
331
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Data\\DB\\UserMeta\\Ops\\Record' => $baseDir . '/src/Modules/Data/DB/UserMeta/Ops/Record.php',
332
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Data\\DB\\UserMeta\\Ops\\Select' => $baseDir . '/src/Modules/Data/DB/UserMeta/Ops/Select.php',
333
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Data\\Lib\\GeoIP\\Lookup' => $baseDir . '/src/Modules/Data/Lib/GeoIP/Lookup.php',
334
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Data\\Lib\\UpgradeReqLogsTable' => $baseDir . '/src/Modules/Data/Lib/UpgradeReqLogsTable.php',
335
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Data\\ModCon' => $baseDir . '/src/Modules/Data/ModCon.php',
336
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Data\\Upgrade' => $baseDir . '/src/Modules/Data/Upgrade.php',
337
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Email\\ModCon' => $baseDir . '/src/Modules/Email/ModCon.php',
338
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Email\\Options' => $baseDir . '/src/Modules/Email/Options.php',
339
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Email\\Processor' => $baseDir . '/src/Modules/Email/Processor.php',
450
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\Store' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/Store.php',
451
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\Base' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/Base.php',
452
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\BaseAction' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/BaseAction.php',
 
453
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\Build' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/Build.php',
454
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\CleanStale' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/CleanStale.php',
455
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\CreateNew' => $baseDir . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/CreateNew.php',
470
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Render\\ScanResults\\SectionThemes' => $baseDir . '/src/Modules/HackGuard/Render/ScanResults/SectionThemes.php',
471
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Render\\ScanResults\\SectionWordpress' => $baseDir . '/src/Modules/HackGuard/Render/ScanResults/SectionWordpress.php',
472
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Reporting' => $baseDir . '/src/Modules/HackGuard/Reporting.php',
473
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Rest' => $baseDir . '/src/Modules/HackGuard/Rest.php',
474
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Rest\\Request\\Base' => $baseDir . '/src/Modules/HackGuard/Rest/Request/Base.php',
475
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Rest\\Request\\RequestVO' => $baseDir . '/src/Modules/HackGuard/Rest/Request/RequestVO.php',
476
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Rest\\Request\\Results\\GetAll' => $baseDir . '/src/Modules/HackGuard/Rest/Request/Results/GetAll.php',
477
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Rest\\Request\\Scans\\Base' => $baseDir . '/src/Modules/HackGuard/Rest/Request/Scans/Base.php',
478
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Rest\\Request\\Scans\\Start' => $baseDir . '/src/Modules/HackGuard/Rest/Request/Scans/Start.php',
479
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Rest\\Request\\Scans\\Status' => $baseDir . '/src/Modules/HackGuard/Rest/Request/Scans/Status.php',
480
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Rest\\Route\\Base' => $baseDir . '/src/Modules/HackGuard/Rest/Route/Base.php',
481
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Rest\\Route\\Results\\GetAll' => $baseDir . '/src/Modules/HackGuard/Rest/Route/Results/GetAll.php',
482
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Rest\\Route\\Scans\\ScansBase' => $baseDir . '/src/Modules/HackGuard/Rest/Route/Scans/ScansBase.php',
483
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Rest\\Route\\Scans\\Start' => $baseDir . '/src/Modules/HackGuard/Rest/Route/Scans/Start.php',
484
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Rest\\Route\\Scans\\Status' => $baseDir . '/src/Modules/HackGuard/Rest/Route/Scans/Status.php',
485
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Scan\\Controller\\Afs' => $baseDir . '/src/Modules/HackGuard/Scan/Controller/Afs.php',
486
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Scan\\Controller\\Apc' => $baseDir . '/src/Modules/HackGuard/Scan/Controller/Apc.php',
487
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Scan\\Controller\\Base' => $baseDir . '/src/Modules/HackGuard/Scan/Controller/Base.php',
579
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\ModCon' => $baseDir . '/src/Modules/IPs/ModCon.php',
580
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Options' => $baseDir . '/src/Modules/IPs/Options.php',
581
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Processor' => $baseDir . '/src/Modules/IPs/Processor.php',
582
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest' => $baseDir . '/src/Modules/IPs/Rest.php',
583
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Exceptions\\NotIpAddressException' => $baseDir . '/src/Modules/IPs/Rest/Exceptions/NotIpAddressException.php',
584
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Request\\IPs\\Base' => $baseDir . '/src/Modules/IPs/Rest/Request/IPs/Base.php',
585
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Request\\IPs\\GetIP' => $baseDir . '/src/Modules/IPs/Rest/Request/IPs/GetIP.php',
586
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Request\\IPs\\RequestVO' => $baseDir . '/src/Modules/IPs/Rest/Request/IPs/RequestVO.php',
587
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Request\\Lists\\AddIP' => $baseDir . '/src/Modules/IPs/Rest/Request/Lists/AddIP.php',
588
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Request\\Lists\\Base' => $baseDir . '/src/Modules/IPs/Rest/Request/Lists/Base.php',
589
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Request\\Lists\\GetList' => $baseDir . '/src/Modules/IPs/Rest/Request/Lists/GetList.php',
590
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Request\\Lists\\GetListIP' => $baseDir . '/src/Modules/IPs/Rest/Request/Lists/GetListIP.php',
591
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Route\\Base' => $baseDir . '/src/Modules/IPs/Rest/Route/Base.php',
592
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Route\\IPs\\GetIP' => $baseDir . '/src/Modules/IPs/Rest/Route/IPs/GetIP.php',
593
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Route\\IPs\\IPsBase' => $baseDir . '/src/Modules/IPs/Rest/Route/IPs/IPsBase.php',
594
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Route\\Lists\\AddIP' => $baseDir . '/src/Modules/IPs/Rest/Route/Lists/AddIP.php',
595
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Route\\Lists\\GetList' => $baseDir . '/src/Modules/IPs/Rest/Route/Lists/GetList.php',
596
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Route\\Lists\\GetListIP' => $baseDir . '/src/Modules/IPs/Rest/Route/Lists/GetListIP.php',
597
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Route\\Lists\\ListsBase' => $baseDir . '/src/Modules/IPs/Rest/Route/Lists/ListsBase.php',
598
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Strings' => $baseDir . '/src/Modules/IPs/Strings.php',
599
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\UI' => $baseDir . '/src/Modules/IPs/UI.php',
600
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Upgrade' => $baseDir . '/src/Modules/IPs/Upgrade.php',
689
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\ModCon' => $baseDir . '/src/Modules/License/ModCon.php',
690
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Options' => $baseDir . '/src/Modules/License/Options.php',
691
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Processor' => $baseDir . '/src/Modules/License/Processor.php',
692
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Rest' => $baseDir . '/src/Modules/License/Rest.php',
693
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Rest\\Request\\Base' => $baseDir . '/src/Modules/License/Rest/Request/Base.php',
694
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Rest\\Request\\LicenseCheck' => $baseDir . '/src/Modules/License/Rest/Request/LicenseCheck.php',
695
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Rest\\Request\\LicenseStatus' => $baseDir . '/src/Modules/License/Rest/Request/LicenseStatus.php',
696
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Rest\\Request\\RequestVO' => $baseDir . '/src/Modules/License/Rest/Request/RequestVO.php',
697
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Rest\\Route\\Base' => $baseDir . '/src/Modules/License/Rest/Route/Base.php',
698
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Rest\\Route\\LicenseCheck' => $baseDir . '/src/Modules/License/Rest/Route/LicenseCheck.php',
699
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Rest\\Route\\LicenseStatus' => $baseDir . '/src/Modules/License/Rest/Route/LicenseStatus.php',
700
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Strings' => $baseDir . '/src/Modules/License/Strings.php',
701
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\UI' => $baseDir . '/src/Modules/License/UI.php',
702
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\WpCli' => $baseDir . '/src/Modules/License/WpCli.php',
786
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Lib\\ImportExport\\Options\\BuildTransferableOptions' => $baseDir . '/src/Modules/Plugin/Lib/ImportExport/Options/BuildTransferableOptions.php',
787
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Lib\\ImportExport\\Options\\SaveExcludedOptions' => $baseDir . '/src/Modules/Plugin/Lib/ImportExport/Options/SaveExcludedOptions.php',
788
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Lib\\Ops\\ResetPlugin' => $baseDir . '/src/Modules/Plugin/Lib/Ops/ResetPlugin.php',
789
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Lib\\Ops\\VerifyDatabaseIntegrity' => $baseDir . '/src/Modules/Plugin/Lib/Ops/VerifyDatabaseIntegrity.php',
790
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Lib\\OverrideLocale' => $baseDir . '/src/Modules/Plugin/Lib/OverrideLocale.php',
791
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Lib\\PluginTelemetry' => $baseDir . '/src/Modules/Plugin/Lib/PluginTelemetry.php',
792
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Lib\\TestCacheDirWrite' => $baseDir . '/src/Modules/Plugin/Lib/TestCacheDirWrite.php',
794
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\ModCon' => $baseDir . '/src/Modules/Plugin/ModCon.php',
795
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Options' => $baseDir . '/src/Modules/Plugin/Options.php',
796
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Processor' => $baseDir . '/src/Modules/Plugin/Processor.php',
797
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest' => $baseDir . '/src/Modules/Plugin/Rest.php',
798
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Exceptions\\OptionDoesNotExistException' => $baseDir . '/src/Modules/Plugin/Rest/Exceptions/OptionDoesNotExistException.php',
799
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Request\\Debug\\Retrieve' => $baseDir . '/src/Modules/Plugin/Rest/Request/Debug/Retrieve.php',
800
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Request\\Options\\Base' => $baseDir . '/src/Modules/Plugin/Rest/Request/Options/Base.php',
801
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Request\\Options\\GetAll' => $baseDir . '/src/Modules/Plugin/Rest/Request/Options/GetAll.php',
802
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Request\\Options\\GetSingle' => $baseDir . '/src/Modules/Plugin/Rest/Request/Options/GetSingle.php',
803
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Request\\Options\\RequestVO' => $baseDir . '/src/Modules/Plugin/Rest/Request/Options/RequestVO.php',
804
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Request\\Options\\SetBulk' => $baseDir . '/src/Modules/Plugin/Rest/Request/Options/SetBulk.php',
805
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Request\\Options\\SetSingle' => $baseDir . '/src/Modules/Plugin/Rest/Request/Options/SetSingle.php',
806
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Route\\Debug\\Retrieve' => $baseDir . '/src/Modules/Plugin/Rest/Route/Debug/Retrieve.php',
807
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Route\\Options\\Base' => $baseDir . '/src/Modules/Plugin/Rest/Route/Options/Base.php',
808
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Route\\Options\\BaseBulk' => $baseDir . '/src/Modules/Plugin/Rest/Route/Options/BaseBulk.php',
809
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Route\\Options\\BaseSingle' => $baseDir . '/src/Modules/Plugin/Rest/Route/Options/BaseSingle.php',
810
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Route\\Options\\GetAll' => $baseDir . '/src/Modules/Plugin/Rest/Route/Options/GetAll.php',
811
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Route\\Options\\GetSingle' => $baseDir . '/src/Modules/Plugin/Rest/Route/Options/GetSingle.php',
812
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Route\\Options\\SetBulk' => $baseDir . '/src/Modules/Plugin/Rest/Route/Options/SetBulk.php',
813
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Route\\Options\\SetSingle' => $baseDir . '/src/Modules/Plugin/Rest/Route/Options/SetSingle.php',
814
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Strings' => $baseDir . '/src/Modules/Plugin/Strings.php',
815
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\UI' => $baseDir . '/src/Modules/Plugin/UI.php',
816
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Upgrade' => $baseDir . '/src/Modules/Plugin/Upgrade.php',
881
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Lib\\Limit\\TestIpLimit' => $baseDir . '/src/Modules/Traffic/Lib/Limit/TestIpLimit.php',
882
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Lib\\LogHandlers\\LocalDbWriter' => $baseDir . '/src/Modules/Traffic/Lib/LogHandlers/LocalDbWriter.php',
883
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Lib\\RequestLogger' => $baseDir . '/src/Modules/Traffic/Lib/RequestLogger.php',
884
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Lib\\TrafficTable\\BuildSearchPanesData' => $baseDir . '/src/Modules/Traffic/Lib/TrafficTable/BuildSearchPanesData.php',
885
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Lib\\TrafficTable\\BuildTrafficTableData' => $baseDir . '/src/Modules/Traffic/Lib/TrafficTable/BuildTrafficTableData.php',
886
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Lib\\TrafficTable\\DelegateAjaxHandler' => $baseDir . '/src/Modules/Traffic/Lib/TrafficTable/DelegateAjaxHandler.php',
 
887
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\ModCon' => $baseDir . '/src/Modules/Traffic/ModCon.php',
888
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Options' => $baseDir . '/src/Modules/Traffic/Options.php',
889
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Processor' => $baseDir . '/src/Modules/Traffic/Processor.php',
907
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Processor' => $baseDir . '/src/Modules/UserManagement/Processor.php',
908
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Strings' => $baseDir . '/src/Modules/UserManagement/Strings.php',
909
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\UI' => $baseDir . '/src/Modules/UserManagement/UI.php',
 
910
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\WpCli' => $baseDir . '/src/Modules/UserManagement/WpCli.php',
911
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\WpCli\\SessionTerminate' => $baseDir . '/src/Modules/UserManagement/WpCli/SessionTerminate.php',
912
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Render\\LocateTemplateDirs' => $baseDir . '/src/Render/LocateTemplateDirs.php',
1021
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\DataTables\\Build\\Scans\\ForPluginTheme' => $baseDir . '/src/Tables/DataTables/Build/Scans/ForPluginTheme.php',
1022
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\DataTables\\Build\\Scans\\ForWordpress' => $baseDir . '/src/Tables/DataTables/Build/Scans/ForWordpress.php',
1023
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\DataTables\\Build\\Traffic\\ForTraffic' => $baseDir . '/src/Tables/DataTables/Build/Traffic/ForTraffic.php',
1024
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\DataTables\\LoadData\\BaseBuildTableData' => $baseDir . '/src/Tables/DataTables/LoadData/BaseBuildTableData.php',
1025
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\Common\\BaseTable' => $baseDir . '/src/Tables/Render/Common/BaseTable.php',
1026
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\WpCliTable\\AuditTrail' => $baseDir . '/src/Tables/Render/WpCliTable/AuditTrail.php',
1027
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\WpListTable\\AdminNotes' => $baseDir . '/src/Tables/Render/WpListTable/AdminNotes.php',
1047
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\HCaptcha\\TestRequest' => $baseDir . '/src/Utilities/HCaptcha/TestRequest.php',
1048
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Htaccess\\RootHtaccess' => $baseDir . '/src/Utilities/Htaccess/RootHtaccess.php',
1049
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\HumanSpam\\TestContent' => $baseDir . '/src/Utilities/HumanSpam/TestContent.php',
1050
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\MU\\MUHandler' => $baseDir . '/src/Utilities/MU/MUHandler.php',
1051
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Nonce\\Handler' => $baseDir . '/src/Utilities/Nonce/Handler.php',
1052
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Options\\CleanStorage' => $baseDir . '/src/Utilities/Options/CleanStorage.php',
1053
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\ReCaptcha\\Enqueue' => $baseDir . '/src/Utilities/ReCaptcha/Enqueue.php',
1099
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Code\\AssessPhpFile' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Code/AssessPhpFile.php',
1100
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Constants\\Regex' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Constants/Regex.php',
1101
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Consumers\\PluginConsumer' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Consumers/PluginConsumer.php',
1102
+ 'FernleafSystems\\Wordpress\\Services\\Utilities\\Consumers\\WpUserConsumer' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Consumers/WpUserConsumer.php',
1103
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Data' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Data.php',
1104
  'FernleafSystems\\Wordpress\\Services\\Utilities\\DataManipulation' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/DataManipulation.php',
1105
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Email' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Email.php',
src/lib/vendor/composer/autoload_real.php CHANGED
@@ -65,11 +65,16 @@ class ComposerAutoloaderInit4fc2c6daaffaf40b64b79b6d26830171
65
  }
66
  }
67
 
 
 
 
 
 
68
  function composerRequire4fc2c6daaffaf40b64b79b6d26830171($fileIdentifier, $file)
69
  {
70
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
71
- require $file;
72
-
73
  $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
 
 
74
  }
75
  }
65
  }
66
  }
67
 
68
+ /**
69
+ * @param string $fileIdentifier
70
+ * @param string $file
71
+ * @return void
72
+ */
73
  function composerRequire4fc2c6daaffaf40b64b79b6d26830171($fileIdentifier, $file)
74
  {
75
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
 
 
76
  $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
77
+
78
+ require $file;
79
  }
80
  }
src/lib/vendor/composer/autoload_static.php CHANGED
@@ -234,9 +234,22 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
234
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Databases\\Common\\Iterator' => __DIR__ . '/..' . '/fernleafsystems/wordpress-plugin-core/src/Databases/Common/Iterator.php',
235
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Databases\\Common\\RecordConsumer' => __DIR__ . '/..' . '/fernleafsystems/wordpress-plugin-core/src/Databases/Common/RecordConsumer.php',
236
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Databases\\Common\\SubQueryLoader' => __DIR__ . '/..' . '/fernleafsystems/wordpress-plugin-core/src/Databases/Common/SubQueryLoader.php',
 
237
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Databases\\Common\\TableSchema' => __DIR__ . '/..' . '/fernleafsystems/wordpress-plugin-core/src/Databases/Common/TableSchema.php',
238
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Databases\\Exceptions\\ColumnDoesNotExistException' => __DIR__ . '/..' . '/fernleafsystems/wordpress-plugin-core/src/Databases/Exceptions/ColumnDoesNotExistException.php',
239
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Databases\\Exceptions\\NoSlugProvidedException' => __DIR__ . '/..' . '/fernleafsystems/wordpress-plugin-core/src/Databases/Exceptions/NoSlugProvidedException.php',
 
 
 
 
 
 
 
 
 
 
 
 
240
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Utility\\User\\PluginMeta' => __DIR__ . '/..' . '/fernleafsystems/wordpress-plugin-core/src/Utility/User/PluginMeta.php',
241
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Diff\\Base' => __DIR__ . '/../..' . '/src/ChangeTrack/Diff/Base.php',
242
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Diff\\DiffComments' => __DIR__ . '/../..' . '/src/ChangeTrack/Diff/DiffComments.php',
@@ -401,8 +414,9 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
401
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\LogHandlers\\LogFileHandler' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/Lib/LogHandlers/LogFileHandler.php',
402
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\LogHandlers\\Utility\\LogFileDirCreate' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/Lib/LogHandlers/Utility/LogFileDirCreate.php',
403
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\LogHandlers\\Utility\\LogFileRotate' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/Lib/LogHandlers/Utility/LogFileRotate.php',
 
 
404
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\LogTable\\DelegateAjaxHandler' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/Lib/LogTable/DelegateAjaxHandler.php',
405
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\LogTable\\LoadRawTableData' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/Lib/LogTable/LoadRawTableData.php',
406
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\Utility\\GetLogFileContent' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/Lib/Utility/GetLogFileContent.php',
407
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\ModCon' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/ModCon.php',
408
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Options' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/Options.php',
@@ -435,14 +449,6 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
435
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Insights\\OverviewCards' => __DIR__ . '/../..' . '/src/Modules/Base/Insights/OverviewCards.php',
436
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Components\\UiTrack' => __DIR__ . '/../..' . '/src/Modules/Base/Lib/Components/UiTrack.php',
437
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Request\\FormParams' => __DIR__ . '/../..' . '/src/Modules/Base/Lib/Request/FormParams.php',
438
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\RequestVoConsumer' => __DIR__ . '/../..' . '/src/Modules/Base/Lib/Rest/RequestVoConsumer.php',
439
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Request\\Process' => __DIR__ . '/../..' . '/src/Modules/Base/Lib/Rest/Request/Process.php',
440
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Request\\RequestVO' => __DIR__ . '/../..' . '/src/Modules/Base/Lib/Rest/Request/RequestVO.php',
441
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Route\\RestRouteConsumer' => __DIR__ . '/../..' . '/src/Modules/Base/Lib/Rest/Route/RestRouteConsumer.php',
442
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Route\\RouteBase' => __DIR__ . '/../..' . '/src/Modules/Base/Lib/Rest/Route/RouteBase.php',
443
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Route\\RouteCache' => __DIR__ . '/../..' . '/src/Modules/Base/Lib/Rest/Route/RouteCache.php',
444
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Utility\\PreChecks' => __DIR__ . '/../..' . '/src/Modules/Base/Lib/Rest/Utility/PreChecks.php',
445
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Utility\\RestLocker' => __DIR__ . '/../..' . '/src/Modules/Base/Lib/Rest/Utility/RestLocker.php',
446
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\ModCon' => __DIR__ . '/../..' . '/src/Modules/Base/ModCon.php',
447
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Options' => __DIR__ . '/../..' . '/src/Modules/Base/Options.php',
448
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Options\\BuildForDisplay' => __DIR__ . '/../..' . '/src/Modules/Base/Options/BuildForDisplay.php',
@@ -451,7 +457,12 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
451
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Options\\WildCardOptions' => __DIR__ . '/../..' . '/src/Modules/Base/Options/WildCardOptions.php',
452
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Processor' => __DIR__ . '/../..' . '/src/Modules/Base/Processor.php',
453
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Reporting' => __DIR__ . '/../..' . '/src/Modules/Base/Reporting.php',
454
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\RestHandler' => __DIR__ . '/../..' . '/src/Modules/Base/RestHandler.php',
 
 
 
 
 
455
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Strings' => __DIR__ . '/../..' . '/src/Modules/Base/Strings.php',
456
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\UI' => __DIR__ . '/../..' . '/src/Modules/Base/UI.php',
457
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Upgrade' => __DIR__ . '/../..' . '/src/Modules/Base/Upgrade.php',
@@ -507,7 +518,9 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
507
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Data\\DB\\UserMeta\\Ops\\Record' => __DIR__ . '/../..' . '/src/Modules/Data/DB/UserMeta/Ops/Record.php',
508
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Data\\DB\\UserMeta\\Ops\\Select' => __DIR__ . '/../..' . '/src/Modules/Data/DB/UserMeta/Ops/Select.php',
509
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Data\\Lib\\GeoIP\\Lookup' => __DIR__ . '/../..' . '/src/Modules/Data/Lib/GeoIP/Lookup.php',
 
510
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Data\\ModCon' => __DIR__ . '/../..' . '/src/Modules/Data/ModCon.php',
 
511
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Email\\ModCon' => __DIR__ . '/../..' . '/src/Modules/Email/ModCon.php',
512
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Email\\Options' => __DIR__ . '/../..' . '/src/Modules/Email/Options.php',
513
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Email\\Processor' => __DIR__ . '/../..' . '/src/Modules/Email/Processor.php',
@@ -624,7 +637,6 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
624
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\Store' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/Store.php',
625
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\Base' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/Base.php',
626
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\BaseAction' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/BaseAction.php',
627
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\BaseBulk' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/BaseBulk.php',
628
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\Build' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/Build.php',
629
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\CleanStale' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/CleanStale.php',
630
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\CreateNew' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/CreateNew.php',
@@ -645,6 +657,18 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
645
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Render\\ScanResults\\SectionThemes' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Render/ScanResults/SectionThemes.php',
646
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Render\\ScanResults\\SectionWordpress' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Render/ScanResults/SectionWordpress.php',
647
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Reporting' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Reporting.php',
 
 
 
 
 
 
 
 
 
 
 
 
648
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Scan\\Controller\\Afs' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Scan/Controller/Afs.php',
649
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Scan\\Controller\\Apc' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Scan/Controller/Apc.php',
650
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Scan\\Controller\\Base' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Scan/Controller/Base.php',
@@ -742,6 +766,22 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
742
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\ModCon' => __DIR__ . '/../..' . '/src/Modules/IPs/ModCon.php',
743
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Options' => __DIR__ . '/../..' . '/src/Modules/IPs/Options.php',
744
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Processor' => __DIR__ . '/../..' . '/src/Modules/IPs/Processor.php',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
745
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Strings' => __DIR__ . '/../..' . '/src/Modules/IPs/Strings.php',
746
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\UI' => __DIR__ . '/../..' . '/src/Modules/IPs/UI.php',
747
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Upgrade' => __DIR__ . '/../..' . '/src/Modules/IPs/Upgrade.php',
@@ -836,6 +876,14 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
836
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\ModCon' => __DIR__ . '/../..' . '/src/Modules/License/ModCon.php',
837
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Options' => __DIR__ . '/../..' . '/src/Modules/License/Options.php',
838
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Processor' => __DIR__ . '/../..' . '/src/Modules/License/Processor.php',
 
 
 
 
 
 
 
 
839
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Strings' => __DIR__ . '/../..' . '/src/Modules/License/Strings.php',
840
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\UI' => __DIR__ . '/../..' . '/src/Modules/License/UI.php',
841
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\WpCli' => __DIR__ . '/../..' . '/src/Modules/License/WpCli.php',
@@ -925,6 +973,7 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
925
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Lib\\ImportExport\\Options\\BuildTransferableOptions' => __DIR__ . '/../..' . '/src/Modules/Plugin/Lib/ImportExport/Options/BuildTransferableOptions.php',
926
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Lib\\ImportExport\\Options\\SaveExcludedOptions' => __DIR__ . '/../..' . '/src/Modules/Plugin/Lib/ImportExport/Options/SaveExcludedOptions.php',
927
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Lib\\Ops\\ResetPlugin' => __DIR__ . '/../..' . '/src/Modules/Plugin/Lib/Ops/ResetPlugin.php',
 
928
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Lib\\OverrideLocale' => __DIR__ . '/../..' . '/src/Modules/Plugin/Lib/OverrideLocale.php',
929
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Lib\\PluginTelemetry' => __DIR__ . '/../..' . '/src/Modules/Plugin/Lib/PluginTelemetry.php',
930
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Lib\\TestCacheDirWrite' => __DIR__ . '/../..' . '/src/Modules/Plugin/Lib/TestCacheDirWrite.php',
@@ -932,6 +981,23 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
932
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\ModCon' => __DIR__ . '/../..' . '/src/Modules/Plugin/ModCon.php',
933
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Options' => __DIR__ . '/../..' . '/src/Modules/Plugin/Options.php',
934
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Processor' => __DIR__ . '/../..' . '/src/Modules/Plugin/Processor.php',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
935
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Strings' => __DIR__ . '/../..' . '/src/Modules/Plugin/Strings.php',
936
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\UI' => __DIR__ . '/../..' . '/src/Modules/Plugin/UI.php',
937
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Upgrade' => __DIR__ . '/../..' . '/src/Modules/Plugin/Upgrade.php',
@@ -1002,8 +1068,9 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
1002
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Lib\\Limit\\TestIpLimit' => __DIR__ . '/../..' . '/src/Modules/Traffic/Lib/Limit/TestIpLimit.php',
1003
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Lib\\LogHandlers\\LocalDbWriter' => __DIR__ . '/../..' . '/src/Modules/Traffic/Lib/LogHandlers/LocalDbWriter.php',
1004
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Lib\\RequestLogger' => __DIR__ . '/../..' . '/src/Modules/Traffic/Lib/RequestLogger.php',
 
 
1005
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Lib\\TrafficTable\\DelegateAjaxHandler' => __DIR__ . '/../..' . '/src/Modules/Traffic/Lib/TrafficTable/DelegateAjaxHandler.php',
1006
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Lib\\TrafficTable\\LoadRawTableData' => __DIR__ . '/../..' . '/src/Modules/Traffic/Lib/TrafficTable/LoadRawTableData.php',
1007
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\ModCon' => __DIR__ . '/../..' . '/src/Modules/Traffic/ModCon.php',
1008
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Options' => __DIR__ . '/../..' . '/src/Modules/Traffic/Options.php',
1009
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Processor' => __DIR__ . '/../..' . '/src/Modules/Traffic/Processor.php',
@@ -1027,7 +1094,6 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
1027
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Processor' => __DIR__ . '/../..' . '/src/Modules/UserManagement/Processor.php',
1028
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Strings' => __DIR__ . '/../..' . '/src/Modules/UserManagement/Strings.php',
1029
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\UI' => __DIR__ . '/../..' . '/src/Modules/UserManagement/UI.php',
1030
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Upgrade' => __DIR__ . '/../..' . '/src/Modules/UserManagement/Upgrade.php',
1031
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\WpCli' => __DIR__ . '/../..' . '/src/Modules/UserManagement/WpCli.php',
1032
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\WpCli\\SessionTerminate' => __DIR__ . '/../..' . '/src/Modules/UserManagement/WpCli/SessionTerminate.php',
1033
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Render\\LocateTemplateDirs' => __DIR__ . '/../..' . '/src/Render/LocateTemplateDirs.php',
@@ -1142,7 +1208,7 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
1142
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\DataTables\\Build\\Scans\\ForPluginTheme' => __DIR__ . '/../..' . '/src/Tables/DataTables/Build/Scans/ForPluginTheme.php',
1143
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\DataTables\\Build\\Scans\\ForWordpress' => __DIR__ . '/../..' . '/src/Tables/DataTables/Build/Scans/ForWordpress.php',
1144
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\DataTables\\Build\\Traffic\\ForTraffic' => __DIR__ . '/../..' . '/src/Tables/DataTables/Build/Traffic/ForTraffic.php',
1145
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\DataTables\\LoadData\\BaseLoadTableData' => __DIR__ . '/../..' . '/src/Tables/DataTables/LoadData/BaseLoadTableData.php',
1146
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\Common\\BaseTable' => __DIR__ . '/../..' . '/src/Tables/Render/Common/BaseTable.php',
1147
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\WpCliTable\\AuditTrail' => __DIR__ . '/../..' . '/src/Tables/Render/WpCliTable/AuditTrail.php',
1148
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\WpListTable\\AdminNotes' => __DIR__ . '/../..' . '/src/Tables/Render/WpListTable/AdminNotes.php',
@@ -1168,6 +1234,7 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
1168
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\HCaptcha\\TestRequest' => __DIR__ . '/../..' . '/src/Utilities/HCaptcha/TestRequest.php',
1169
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Htaccess\\RootHtaccess' => __DIR__ . '/../..' . '/src/Utilities/Htaccess/RootHtaccess.php',
1170
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\HumanSpam\\TestContent' => __DIR__ . '/../..' . '/src/Utilities/HumanSpam/TestContent.php',
 
1171
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Nonce\\Handler' => __DIR__ . '/../..' . '/src/Utilities/Nonce/Handler.php',
1172
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Options\\CleanStorage' => __DIR__ . '/../..' . '/src/Utilities/Options/CleanStorage.php',
1173
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\ReCaptcha\\Enqueue' => __DIR__ . '/../..' . '/src/Utilities/ReCaptcha/Enqueue.php',
@@ -1219,6 +1286,7 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
1219
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Code\\AssessPhpFile' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Code/AssessPhpFile.php',
1220
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Constants\\Regex' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Constants/Regex.php',
1221
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Consumers\\PluginConsumer' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Consumers/PluginConsumer.php',
 
1222
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Data' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Data.php',
1223
  'FernleafSystems\\Wordpress\\Services\\Utilities\\DataManipulation' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/DataManipulation.php',
1224
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Email' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Email.php',
234
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Databases\\Common\\Iterator' => __DIR__ . '/..' . '/fernleafsystems/wordpress-plugin-core/src/Databases/Common/Iterator.php',
235
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Databases\\Common\\RecordConsumer' => __DIR__ . '/..' . '/fernleafsystems/wordpress-plugin-core/src/Databases/Common/RecordConsumer.php',
236
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Databases\\Common\\SubQueryLoader' => __DIR__ . '/..' . '/fernleafsystems/wordpress-plugin-core/src/Databases/Common/SubQueryLoader.php',
237
+ 'FernleafSystems\\Wordpress\\Plugin\\Core\\Databases\\Common\\TableReadyCache' => __DIR__ . '/..' . '/fernleafsystems/wordpress-plugin-core/src/Databases/Common/TableReadyCache.php',
238
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Databases\\Common\\TableSchema' => __DIR__ . '/..' . '/fernleafsystems/wordpress-plugin-core/src/Databases/Common/TableSchema.php',
239
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Databases\\Exceptions\\ColumnDoesNotExistException' => __DIR__ . '/..' . '/fernleafsystems/wordpress-plugin-core/src/Databases/Exceptions/ColumnDoesNotExistException.php',
240
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Databases\\Exceptions\\NoSlugProvidedException' => __DIR__ . '/..' . '/fernleafsystems/wordpress-plugin-core/src/Databases/Exceptions/NoSlugProvidedException.php',
241
+ 'FernleafSystems\\Wordpress\\Plugin\\Core\\Rest\\Exceptions\\ApiException' => __DIR__ . '/..' . '/fernleafsystems/wordpress-plugin-core/src/Rest/Exceptions/ApiException.php',
242
+ 'FernleafSystems\\Wordpress\\Plugin\\Core\\Rest\\Exceptions\\ClientSideException' => __DIR__ . '/..' . '/fernleafsystems/wordpress-plugin-core/src/Rest/Exceptions/ClientSideException.php',
243
+ 'FernleafSystems\\Wordpress\\Plugin\\Core\\Rest\\Exceptions\\CouldNotObtainLockException' => __DIR__ . '/..' . '/fernleafsystems/wordpress-plugin-core/src/Rest/Exceptions/CouldNotObtainLockException.php',
244
+ 'FernleafSystems\\Wordpress\\Plugin\\Core\\Rest\\Exceptions\\InvalidRequestParametersException' => __DIR__ . '/..' . '/fernleafsystems/wordpress-plugin-core/src/Rest/Exceptions/InvalidRequestParametersException.php',
245
+ 'FernleafSystems\\Wordpress\\Plugin\\Core\\Rest\\Exceptions\\ServerSideException' => __DIR__ . '/..' . '/fernleafsystems/wordpress-plugin-core/src/Rest/Exceptions/ServerSideException.php',
246
+ 'FernleafSystems\\Wordpress\\Plugin\\Core\\Rest\\Request\\Process' => __DIR__ . '/..' . '/fernleafsystems/wordpress-plugin-core/src/Rest/Request/Process.php',
247
+ 'FernleafSystems\\Wordpress\\Plugin\\Core\\Rest\\Request\\RequestVO' => __DIR__ . '/..' . '/fernleafsystems/wordpress-plugin-core/src/Rest/Request/RequestVO.php',
248
+ 'FernleafSystems\\Wordpress\\Plugin\\Core\\Rest\\RestHandler' => __DIR__ . '/..' . '/fernleafsystems/wordpress-plugin-core/src/Rest/RestHandler.php',
249
+ 'FernleafSystems\\Wordpress\\Plugin\\Core\\Rest\\Route\\RestRequestConsumer' => __DIR__ . '/..' . '/fernleafsystems/wordpress-plugin-core/src/Rest/Route/RestRequestConsumer.php',
250
+ 'FernleafSystems\\Wordpress\\Plugin\\Core\\Rest\\Route\\RestRouteConsumer' => __DIR__ . '/..' . '/fernleafsystems/wordpress-plugin-core/src/Rest/Route/RestRouteConsumer.php',
251
+ 'FernleafSystems\\Wordpress\\Plugin\\Core\\Rest\\Route\\RouteBase' => __DIR__ . '/..' . '/fernleafsystems/wordpress-plugin-core/src/Rest/Route/RouteBase.php',
252
+ 'FernleafSystems\\Wordpress\\Plugin\\Core\\Rest\\Route\\RouteCache' => __DIR__ . '/..' . '/fernleafsystems/wordpress-plugin-core/src/Rest/Route/RouteCache.php',
253
  'FernleafSystems\\Wordpress\\Plugin\\Core\\Utility\\User\\PluginMeta' => __DIR__ . '/..' . '/fernleafsystems/wordpress-plugin-core/src/Utility/User/PluginMeta.php',
254
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Diff\\Base' => __DIR__ . '/../..' . '/src/ChangeTrack/Diff/Base.php',
255
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\ChangeTrack\\Diff\\DiffComments' => __DIR__ . '/../..' . '/src/ChangeTrack/Diff/DiffComments.php',
414
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\LogHandlers\\LogFileHandler' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/Lib/LogHandlers/LogFileHandler.php',
415
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\LogHandlers\\Utility\\LogFileDirCreate' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/Lib/LogHandlers/Utility/LogFileDirCreate.php',
416
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\LogHandlers\\Utility\\LogFileRotate' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/Lib/LogHandlers/Utility/LogFileRotate.php',
417
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\LogTable\\BuildAuditTableData' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/Lib/LogTable/BuildAuditTableData.php',
418
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\LogTable\\BuildSearchPanesData' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/Lib/LogTable/BuildSearchPanesData.php',
419
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\LogTable\\DelegateAjaxHandler' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/Lib/LogTable/DelegateAjaxHandler.php',
 
420
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\Utility\\GetLogFileContent' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/Lib/Utility/GetLogFileContent.php',
421
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\ModCon' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/ModCon.php',
422
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Options' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/Options.php',
449
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Insights\\OverviewCards' => __DIR__ . '/../..' . '/src/Modules/Base/Insights/OverviewCards.php',
450
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Components\\UiTrack' => __DIR__ . '/../..' . '/src/Modules/Base/Lib/Components/UiTrack.php',
451
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Request\\FormParams' => __DIR__ . '/../..' . '/src/Modules/Base/Lib/Request/FormParams.php',
 
 
 
 
 
 
 
 
452
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\ModCon' => __DIR__ . '/../..' . '/src/Modules/Base/ModCon.php',
453
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Options' => __DIR__ . '/../..' . '/src/Modules/Base/Options.php',
454
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Options\\BuildForDisplay' => __DIR__ . '/../..' . '/src/Modules/Base/Options/BuildForDisplay.php',
457
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Options\\WildCardOptions' => __DIR__ . '/../..' . '/src/Modules/Base/Options/WildCardOptions.php',
458
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Processor' => __DIR__ . '/../..' . '/src/Modules/Base/Processor.php',
459
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Reporting' => __DIR__ . '/../..' . '/src/Modules/Base/Reporting.php',
460
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Rest' => __DIR__ . '/../..' . '/src/Modules/Base/Rest.php',
461
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Rest\\RequestVoConsumer' => __DIR__ . '/../..' . '/src/Modules/Base/Rest/RequestVoConsumer.php',
462
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Rest\\Request\\Process' => __DIR__ . '/../..' . '/src/Modules/Base/Rest/Request/Process.php',
463
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Rest\\Request\\RequestVO' => __DIR__ . '/../..' . '/src/Modules/Base/Rest/Request/RequestVO.php',
464
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Rest\\Route\\RouteBase' => __DIR__ . '/../..' . '/src/Modules/Base/Rest/Route/RouteBase.php',
465
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Rest\\Route\\RouteCache' => __DIR__ . '/../..' . '/src/Modules/Base/Rest/Route/RouteCache.php',
466
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Strings' => __DIR__ . '/../..' . '/src/Modules/Base/Strings.php',
467
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\UI' => __DIR__ . '/../..' . '/src/Modules/Base/UI.php',
468
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Upgrade' => __DIR__ . '/../..' . '/src/Modules/Base/Upgrade.php',
518
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Data\\DB\\UserMeta\\Ops\\Record' => __DIR__ . '/../..' . '/src/Modules/Data/DB/UserMeta/Ops/Record.php',
519
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Data\\DB\\UserMeta\\Ops\\Select' => __DIR__ . '/../..' . '/src/Modules/Data/DB/UserMeta/Ops/Select.php',
520
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Data\\Lib\\GeoIP\\Lookup' => __DIR__ . '/../..' . '/src/Modules/Data/Lib/GeoIP/Lookup.php',
521
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Data\\Lib\\UpgradeReqLogsTable' => __DIR__ . '/../..' . '/src/Modules/Data/Lib/UpgradeReqLogsTable.php',
522
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Data\\ModCon' => __DIR__ . '/../..' . '/src/Modules/Data/ModCon.php',
523
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Data\\Upgrade' => __DIR__ . '/../..' . '/src/Modules/Data/Upgrade.php',
524
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Email\\ModCon' => __DIR__ . '/../..' . '/src/Modules/Email/ModCon.php',
525
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Email\\Options' => __DIR__ . '/../..' . '/src/Modules/Email/Options.php',
526
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Email\\Processor' => __DIR__ . '/../..' . '/src/Modules/Email/Processor.php',
637
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\Store' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/Store.php',
638
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\Base' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/Base.php',
639
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\BaseAction' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/BaseAction.php',
 
640
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\Build' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/Build.php',
641
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\CleanStale' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/CleanStale.php',
642
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Lib\\Snapshots\\StoreAction\\CreateNew' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Lib/Snapshots/StoreAction/CreateNew.php',
657
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Render\\ScanResults\\SectionThemes' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Render/ScanResults/SectionThemes.php',
658
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Render\\ScanResults\\SectionWordpress' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Render/ScanResults/SectionWordpress.php',
659
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Reporting' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Reporting.php',
660
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Rest' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Rest.php',
661
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Rest\\Request\\Base' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Rest/Request/Base.php',
662
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Rest\\Request\\RequestVO' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Rest/Request/RequestVO.php',
663
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Rest\\Request\\Results\\GetAll' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Rest/Request/Results/GetAll.php',
664
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Rest\\Request\\Scans\\Base' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Rest/Request/Scans/Base.php',
665
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Rest\\Request\\Scans\\Start' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Rest/Request/Scans/Start.php',
666
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Rest\\Request\\Scans\\Status' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Rest/Request/Scans/Status.php',
667
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Rest\\Route\\Base' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Rest/Route/Base.php',
668
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Rest\\Route\\Results\\GetAll' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Rest/Route/Results/GetAll.php',
669
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Rest\\Route\\Scans\\ScansBase' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Rest/Route/Scans/ScansBase.php',
670
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Rest\\Route\\Scans\\Start' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Rest/Route/Scans/Start.php',
671
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Rest\\Route\\Scans\\Status' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Rest/Route/Scans/Status.php',
672
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Scan\\Controller\\Afs' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Scan/Controller/Afs.php',
673
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Scan\\Controller\\Apc' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Scan/Controller/Apc.php',
674
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\HackGuard\\Scan\\Controller\\Base' => __DIR__ . '/../..' . '/src/Modules/HackGuard/Scan/Controller/Base.php',
766
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\ModCon' => __DIR__ . '/../..' . '/src/Modules/IPs/ModCon.php',
767
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Options' => __DIR__ . '/../..' . '/src/Modules/IPs/Options.php',
768
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Processor' => __DIR__ . '/../..' . '/src/Modules/IPs/Processor.php',
769
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest' => __DIR__ . '/../..' . '/src/Modules/IPs/Rest.php',
770
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Exceptions\\NotIpAddressException' => __DIR__ . '/../..' . '/src/Modules/IPs/Rest/Exceptions/NotIpAddressException.php',
771
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Request\\IPs\\Base' => __DIR__ . '/../..' . '/src/Modules/IPs/Rest/Request/IPs/Base.php',
772
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Request\\IPs\\GetIP' => __DIR__ . '/../..' . '/src/Modules/IPs/Rest/Request/IPs/GetIP.php',
773
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Request\\IPs\\RequestVO' => __DIR__ . '/../..' . '/src/Modules/IPs/Rest/Request/IPs/RequestVO.php',
774
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Request\\Lists\\AddIP' => __DIR__ . '/../..' . '/src/Modules/IPs/Rest/Request/Lists/AddIP.php',
775
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Request\\Lists\\Base' => __DIR__ . '/../..' . '/src/Modules/IPs/Rest/Request/Lists/Base.php',
776
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Request\\Lists\\GetList' => __DIR__ . '/../..' . '/src/Modules/IPs/Rest/Request/Lists/GetList.php',
777
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Request\\Lists\\GetListIP' => __DIR__ . '/../..' . '/src/Modules/IPs/Rest/Request/Lists/GetListIP.php',
778
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Route\\Base' => __DIR__ . '/../..' . '/src/Modules/IPs/Rest/Route/Base.php',
779
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Route\\IPs\\GetIP' => __DIR__ . '/../..' . '/src/Modules/IPs/Rest/Route/IPs/GetIP.php',
780
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Route\\IPs\\IPsBase' => __DIR__ . '/../..' . '/src/Modules/IPs/Rest/Route/IPs/IPsBase.php',
781
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Route\\Lists\\AddIP' => __DIR__ . '/../..' . '/src/Modules/IPs/Rest/Route/Lists/AddIP.php',
782
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Route\\Lists\\GetList' => __DIR__ . '/../..' . '/src/Modules/IPs/Rest/Route/Lists/GetList.php',
783
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Route\\Lists\\GetListIP' => __DIR__ . '/../..' . '/src/Modules/IPs/Rest/Route/Lists/GetListIP.php',
784
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Rest\\Route\\Lists\\ListsBase' => __DIR__ . '/../..' . '/src/Modules/IPs/Rest/Route/Lists/ListsBase.php',
785
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Strings' => __DIR__ . '/../..' . '/src/Modules/IPs/Strings.php',
786
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\UI' => __DIR__ . '/../..' . '/src/Modules/IPs/UI.php',
787
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Upgrade' => __DIR__ . '/../..' . '/src/Modules/IPs/Upgrade.php',
876
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\ModCon' => __DIR__ . '/../..' . '/src/Modules/License/ModCon.php',
877
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Options' => __DIR__ . '/../..' . '/src/Modules/License/Options.php',
878
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Processor' => __DIR__ . '/../..' . '/src/Modules/License/Processor.php',
879
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Rest' => __DIR__ . '/../..' . '/src/Modules/License/Rest.php',
880
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Rest\\Request\\Base' => __DIR__ . '/../..' . '/src/Modules/License/Rest/Request/Base.php',
881
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Rest\\Request\\LicenseCheck' => __DIR__ . '/../..' . '/src/Modules/License/Rest/Request/LicenseCheck.php',
882
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Rest\\Request\\LicenseStatus' => __DIR__ . '/../..' . '/src/Modules/License/Rest/Request/LicenseStatus.php',
883
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Rest\\Request\\RequestVO' => __DIR__ . '/../..' . '/src/Modules/License/Rest/Request/RequestVO.php',
884
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Rest\\Route\\Base' => __DIR__ . '/../..' . '/src/Modules/License/Rest/Route/Base.php',
885
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Rest\\Route\\LicenseCheck' => __DIR__ . '/../..' . '/src/Modules/License/Rest/Route/LicenseCheck.php',
886
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Rest\\Route\\LicenseStatus' => __DIR__ . '/../..' . '/src/Modules/License/Rest/Route/LicenseStatus.php',
887
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Strings' => __DIR__ . '/../..' . '/src/Modules/License/Strings.php',
888
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\UI' => __DIR__ . '/../..' . '/src/Modules/License/UI.php',
889
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\WpCli' => __DIR__ . '/../..' . '/src/Modules/License/WpCli.php',
973
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Lib\\ImportExport\\Options\\BuildTransferableOptions' => __DIR__ . '/../..' . '/src/Modules/Plugin/Lib/ImportExport/Options/BuildTransferableOptions.php',
974
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Lib\\ImportExport\\Options\\SaveExcludedOptions' => __DIR__ . '/../..' . '/src/Modules/Plugin/Lib/ImportExport/Options/SaveExcludedOptions.php',
975
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Lib\\Ops\\ResetPlugin' => __DIR__ . '/../..' . '/src/Modules/Plugin/Lib/Ops/ResetPlugin.php',
976
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Lib\\Ops\\VerifyDatabaseIntegrity' => __DIR__ . '/../..' . '/src/Modules/Plugin/Lib/Ops/VerifyDatabaseIntegrity.php',
977
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Lib\\OverrideLocale' => __DIR__ . '/../..' . '/src/Modules/Plugin/Lib/OverrideLocale.php',
978
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Lib\\PluginTelemetry' => __DIR__ . '/../..' . '/src/Modules/Plugin/Lib/PluginTelemetry.php',
979
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Lib\\TestCacheDirWrite' => __DIR__ . '/../..' . '/src/Modules/Plugin/Lib/TestCacheDirWrite.php',
981
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\ModCon' => __DIR__ . '/../..' . '/src/Modules/Plugin/ModCon.php',
982
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Options' => __DIR__ . '/../..' . '/src/Modules/Plugin/Options.php',
983
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Processor' => __DIR__ . '/../..' . '/src/Modules/Plugin/Processor.php',
984
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest' => __DIR__ . '/../..' . '/src/Modules/Plugin/Rest.php',
985
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Exceptions\\OptionDoesNotExistException' => __DIR__ . '/../..' . '/src/Modules/Plugin/Rest/Exceptions/OptionDoesNotExistException.php',
986
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Request\\Debug\\Retrieve' => __DIR__ . '/../..' . '/src/Modules/Plugin/Rest/Request/Debug/Retrieve.php',
987
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Request\\Options\\Base' => __DIR__ . '/../..' . '/src/Modules/Plugin/Rest/Request/Options/Base.php',
988
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Request\\Options\\GetAll' => __DIR__ . '/../..' . '/src/Modules/Plugin/Rest/Request/Options/GetAll.php',
989
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Request\\Options\\GetSingle' => __DIR__ . '/../..' . '/src/Modules/Plugin/Rest/Request/Options/GetSingle.php',
990
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Request\\Options\\RequestVO' => __DIR__ . '/../..' . '/src/Modules/Plugin/Rest/Request/Options/RequestVO.php',
991
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Request\\Options\\SetBulk' => __DIR__ . '/../..' . '/src/Modules/Plugin/Rest/Request/Options/SetBulk.php',
992
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Request\\Options\\SetSingle' => __DIR__ . '/../..' . '/src/Modules/Plugin/Rest/Request/Options/SetSingle.php',
993
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Route\\Debug\\Retrieve' => __DIR__ . '/../..' . '/src/Modules/Plugin/Rest/Route/Debug/Retrieve.php',
994
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Route\\Options\\Base' => __DIR__ . '/../..' . '/src/Modules/Plugin/Rest/Route/Options/Base.php',
995
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Route\\Options\\BaseBulk' => __DIR__ . '/../..' . '/src/Modules/Plugin/Rest/Route/Options/BaseBulk.php',
996
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Route\\Options\\BaseSingle' => __DIR__ . '/../..' . '/src/Modules/Plugin/Rest/Route/Options/BaseSingle.php',
997
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Route\\Options\\GetAll' => __DIR__ . '/../..' . '/src/Modules/Plugin/Rest/Route/Options/GetAll.php',
998
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Route\\Options\\GetSingle' => __DIR__ . '/../..' . '/src/Modules/Plugin/Rest/Route/Options/GetSingle.php',
999
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Route\\Options\\SetBulk' => __DIR__ . '/../..' . '/src/Modules/Plugin/Rest/Route/Options/SetBulk.php',
1000
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Rest\\Route\\Options\\SetSingle' => __DIR__ . '/../..' . '/src/Modules/Plugin/Rest/Route/Options/SetSingle.php',
1001
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Strings' => __DIR__ . '/../..' . '/src/Modules/Plugin/Strings.php',
1002
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\UI' => __DIR__ . '/../..' . '/src/Modules/Plugin/UI.php',
1003
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\Upgrade' => __DIR__ . '/../..' . '/src/Modules/Plugin/Upgrade.php',
1068
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Lib\\Limit\\TestIpLimit' => __DIR__ . '/../..' . '/src/Modules/Traffic/Lib/Limit/TestIpLimit.php',
1069
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Lib\\LogHandlers\\LocalDbWriter' => __DIR__ . '/../..' . '/src/Modules/Traffic/Lib/LogHandlers/LocalDbWriter.php',
1070
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Lib\\RequestLogger' => __DIR__ . '/../..' . '/src/Modules/Traffic/Lib/RequestLogger.php',
1071
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Lib\\TrafficTable\\BuildSearchPanesData' => __DIR__ . '/../..' . '/src/Modules/Traffic/Lib/TrafficTable/BuildSearchPanesData.php',
1072
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Lib\\TrafficTable\\BuildTrafficTableData' => __DIR__ . '/../..' . '/src/Modules/Traffic/Lib/TrafficTable/BuildTrafficTableData.php',
1073
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Lib\\TrafficTable\\DelegateAjaxHandler' => __DIR__ . '/../..' . '/src/Modules/Traffic/Lib/TrafficTable/DelegateAjaxHandler.php',
 
1074
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\ModCon' => __DIR__ . '/../..' . '/src/Modules/Traffic/ModCon.php',
1075
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Options' => __DIR__ . '/../..' . '/src/Modules/Traffic/Options.php',
1076
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Traffic\\Processor' => __DIR__ . '/../..' . '/src/Modules/Traffic/Processor.php',
1094
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Processor' => __DIR__ . '/../..' . '/src/Modules/UserManagement/Processor.php',
1095
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\Strings' => __DIR__ . '/../..' . '/src/Modules/UserManagement/Strings.php',
1096
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\UI' => __DIR__ . '/../..' . '/src/Modules/UserManagement/UI.php',
 
1097
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\WpCli' => __DIR__ . '/../..' . '/src/Modules/UserManagement/WpCli.php',
1098
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\UserManagement\\WpCli\\SessionTerminate' => __DIR__ . '/../..' . '/src/Modules/UserManagement/WpCli/SessionTerminate.php',
1099
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Render\\LocateTemplateDirs' => __DIR__ . '/../..' . '/src/Render/LocateTemplateDirs.php',
1208
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\DataTables\\Build\\Scans\\ForPluginTheme' => __DIR__ . '/../..' . '/src/Tables/DataTables/Build/Scans/ForPluginTheme.php',
1209
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\DataTables\\Build\\Scans\\ForWordpress' => __DIR__ . '/../..' . '/src/Tables/DataTables/Build/Scans/ForWordpress.php',
1210
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\DataTables\\Build\\Traffic\\ForTraffic' => __DIR__ . '/../..' . '/src/Tables/DataTables/Build/Traffic/ForTraffic.php',
1211
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\DataTables\\LoadData\\BaseBuildTableData' => __DIR__ . '/../..' . '/src/Tables/DataTables/LoadData/BaseBuildTableData.php',
1212
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\Common\\BaseTable' => __DIR__ . '/../..' . '/src/Tables/Render/Common/BaseTable.php',
1213
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\WpCliTable\\AuditTrail' => __DIR__ . '/../..' . '/src/Tables/Render/WpCliTable/AuditTrail.php',
1214
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\WpListTable\\AdminNotes' => __DIR__ . '/../..' . '/src/Tables/Render/WpListTable/AdminNotes.php',
1234
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\HCaptcha\\TestRequest' => __DIR__ . '/../..' . '/src/Utilities/HCaptcha/TestRequest.php',
1235
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Htaccess\\RootHtaccess' => __DIR__ . '/../..' . '/src/Utilities/Htaccess/RootHtaccess.php',
1236
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\HumanSpam\\TestContent' => __DIR__ . '/../..' . '/src/Utilities/HumanSpam/TestContent.php',
1237
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\MU\\MUHandler' => __DIR__ . '/../..' . '/src/Utilities/MU/MUHandler.php',
1238
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Nonce\\Handler' => __DIR__ . '/../..' . '/src/Utilities/Nonce/Handler.php',
1239
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Options\\CleanStorage' => __DIR__ . '/../..' . '/src/Utilities/Options/CleanStorage.php',
1240
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\ReCaptcha\\Enqueue' => __DIR__ . '/../..' . '/src/Utilities/ReCaptcha/Enqueue.php',
1286
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Code\\AssessPhpFile' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Code/AssessPhpFile.php',
1287
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Constants\\Regex' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Constants/Regex.php',
1288
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Consumers\\PluginConsumer' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Consumers/PluginConsumer.php',
1289
+ 'FernleafSystems\\Wordpress\\Services\\Utilities\\Consumers\\WpUserConsumer' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Consumers/WpUserConsumer.php',
1290
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Data' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Data.php',
1291
  'FernleafSystems\\Wordpress\\Services\\Utilities\\DataManipulation' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/DataManipulation.php',
1292
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Email' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Email.php',
src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Databases/Base/Handler.php CHANGED
@@ -7,16 +7,21 @@ use FernleafSystems\Wordpress\Plugin\Core\Databases\Common\{
7
  AlignTableWithSchema,
8
  Iterator,
9
  SubQueryLoader,
 
10
  TableSchema
11
  };
12
  use FernleafSystems\Wordpress\Plugin\Core\Databases\Exceptions\NoSlugProvidedException;
13
  use FernleafSystems\Wordpress\Services\Services;
14
- use FernleafSystems\Wordpress\Services\Utilities\Options\Transient;
15
 
16
  abstract class Handler {
17
 
18
  use ExecOnce;
19
 
 
 
 
 
 
20
  /**
21
  * @var bool
22
  */
@@ -221,20 +226,18 @@ abstract class Handler {
221
  }
222
 
223
  if ( !isset( $this->isReady ) ) {
 
224
  try {
225
- if ( Services::Request()->ts() - (int)Transient::Get( $this->getTransientReadyKey() ) < 30 ) {
226
  $this->isReady = true;
227
  }
228
  else {
229
- $schema = $this->getTableSchema();
230
  $align = new AlignTableWithSchema( $schema );
231
  $align->align();
232
  $this->isReady = $this->tableExists() && $align->isAligned();
233
- Transient::Set(
234
- $this->getTransientReadyKey(),
235
- Services::Request()->ts(),
236
- $schema->ready_check_interval
237
- );
238
  }
239
  }
240
  catch ( \Exception $e ) {
@@ -245,6 +248,16 @@ abstract class Handler {
245
  return $this->isReady;
246
  }
247
 
 
 
 
 
 
 
 
 
 
 
248
  protected function getTransientReadyKey() :string {
249
  return 'apto-db-ready-'.substr( md5( serialize( $this->getTableSchema() ) ), 0, 10 );
250
  }
7
  AlignTableWithSchema,
8
  Iterator,
9
  SubQueryLoader,
10
+ TableReadyCache,
11
  TableSchema
12
  };
13
  use FernleafSystems\Wordpress\Plugin\Core\Databases\Exceptions\NoSlugProvidedException;
14
  use FernleafSystems\Wordpress\Services\Services;
 
15
 
16
  abstract class Handler {
17
 
18
  use ExecOnce;
19
 
20
+ /**
21
+ * @var TableReadyCache
22
+ */
23
+ private static $ReadyCache;
24
+
25
  /**
26
  * @var bool
27
  */
226
  }
227
 
228
  if ( !isset( $this->isReady ) ) {
229
+ $schema = $this->getTableSchema();
230
  try {
231
+ if ( $this->getReadyCache()->isReady( $schema ) ) {
232
  $this->isReady = true;
233
  }
234
  else {
 
235
  $align = new AlignTableWithSchema( $schema );
236
  $align->align();
237
  $this->isReady = $this->tableExists() && $align->isAligned();
238
+ if ( $this->isReady ) {
239
+ $this->getReadyCache()->setReady( $schema );
240
+ }
 
 
241
  }
242
  }
243
  catch ( \Exception $e ) {
248
  return $this->isReady;
249
  }
250
 
251
+ protected function getReadyCache() :TableReadyCache {
252
+ if ( !isset( self::$ReadyCache ) ) {
253
+ self::$ReadyCache = new TableReadyCache();
254
+ }
255
+ return self::$ReadyCache;
256
+ }
257
+
258
+ /**
259
+ * @deprecated
260
+ */
261
  protected function getTransientReadyKey() :string {
262
  return 'apto-db-ready-'.substr( md5( serialize( $this->getTableSchema() ) ), 0, 10 );
263
  }
src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Databases/Common/CreateTable.php CHANGED
@@ -4,10 +4,6 @@ namespace FernleafSystems\Wordpress\Plugin\Core\Databases\Common;
4
 
5
  use FernleafSystems\Wordpress\Services\Services;
6
 
7
- /**
8
- * Class CreateTable
9
- * @package FernleafSystems\Wordpress\Plugin\Core\Databases\Common
10
- */
11
  class CreateTable {
12
 
13
  /**
4
 
5
  use FernleafSystems\Wordpress\Services\Services;
6
 
 
 
 
 
7
  class CreateTable {
8
 
9
  /**
src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Databases/Common/TableReadyCache.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Core\Databases\Common;
4
+
5
+ use FernleafSystems\Wordpress\Services\Services;
6
+
7
+ class TableReadyCache {
8
+
9
+ const DB_STATUS_KEY = 'apto-dbs-ready-status';
10
+ const READY_LIFETIME = 30;
11
+
12
+ private $status;
13
+
14
+ private $save = false;
15
+
16
+ public function __construct() {
17
+ add_action( 'shutdown', [ $this, 'save' ], PHP_INT_MIN );
18
+ }
19
+
20
+ public function save() {
21
+ $status = $this->getStatus();
22
+ if ( $this->save && !empty( $status ) ) {
23
+ ksort( $status );
24
+ Services::WpGeneral()->updateOption( self::DB_STATUS_KEY, $status );
25
+ }
26
+ }
27
+
28
+ public function isReady( TableSchema $schema, int $lifetime = self::READY_LIFETIME ) :bool {
29
+ return ( Services::Request()->ts() - $lifetime )
30
+ < ( $this->getStatus()[ $this->uniqTableID( $schema ) ] ?? 0 );
31
+ }
32
+
33
+ public function setReady( TableSchema $schema ) {
34
+ $status = $this->getStatus();
35
+ $status[ $this->uniqTableID( $schema ) ] = time();
36
+ $this->status = $status;
37
+ $this->save = true;
38
+ }
39
+
40
+ private function getStatus() :array {
41
+ if ( !isset( $this->status ) ) {
42
+ $this->status = Services::WpGeneral()->getOption( self::DB_STATUS_KEY );
43
+ if ( !is_array( $this->status ) ) {
44
+ $this->status = [];
45
+ }
46
+ $this->status = array_filter( $this->status, function ( int $ts ) {
47
+ return Services::Request()->ts() - $ts < HOUR_IN_SECONDS;
48
+ } );
49
+ }
50
+ return $this->status;
51
+ }
52
+
53
+ private function uniqTableID( TableSchema $schema ) :string {
54
+ $data = $schema->getRawData();
55
+ ksort( $data );
56
+ return substr( md5( serialize( $data ) ), 0, 10 );
57
+ }
58
+ }
src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Rest/Exceptions/ApiException.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Core\Rest\Exceptions;
4
+
5
+ class ApiException extends \Exception {
6
+
7
+ const DEFAULT_ERROR_CODE = 500;
8
+ const DEFAULT_ERROR_SUBCODE = 1;
9
+
10
+ private $subErrorCode;
11
+
12
+ public function __construct( $message = '', $code = 0, int $subCode = 0, \Throwable $previous = null ) {
13
+ parent::__construct( $message, empty( $code ) ? static::DEFAULT_ERROR_CODE : $code, $previous );
14
+ $this->subErrorCode = $subCode;
15
+ }
16
+
17
+ public function getSubErrorCode() :int {
18
+ return empty( $this->subErrorCode ) ? static::DEFAULT_ERROR_SUBCODE : $this->subErrorCode;
19
+ }
20
+ }
src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Rest/Exceptions/ClientSideException.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Core\Rest\Exceptions;
4
+
5
+ class ClientSideException extends ApiException {
6
+
7
+ const DEFAULT_ERROR_CODE = 400;
8
+ }
src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Rest/Exceptions/CouldNotObtainLockException.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Core\Rest\Exceptions;
4
+
5
+ class CouldNotObtainLockException extends ServerSideException {
6
+
7
+ const DEFAULT_ERROR_SUBCODE = 501;
8
+ }
src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Rest/Exceptions/InvalidRequestParametersException.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Core\Rest\Exceptions;
4
+
5
+ class InvalidRequestParametersException extends ClientSideException {
6
+
7
+ const DEFAULT_ERROR_SUBCODE = 401;
8
+ }
src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Rest/Exceptions/ServerSideException.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Core\Rest\Exceptions;
4
+
5
+ class ServerSideException extends ApiException {
6
+
7
+ const DEFAULT_ERROR_CODE = 500;
8
+
9
+ }
src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Rest/Request/Process.php ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Core\Rest\Request;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Core\Rest\Exceptions\ApiException;
6
+ use FernleafSystems\Wordpress\Plugin\Core\Rest\Exceptions\CouldNotObtainLockException;
7
+ use FernleafSystems\Wordpress\Plugin\Core\Rest\Exceptions\InvalidRequestParametersException;
8
+ use FernleafSystems\Wordpress\Plugin\Core\Rest\Route\RestRequestConsumer;
9
+ use FernleafSystems\Wordpress\Plugin\Core\Rest\Route\RestRouteConsumer;
10
+ use FernleafSystems\Wordpress\Plugin\Core\Rest\Route\RouteBase;
11
+ use FernleafSystems\Wordpress\Services\Services;
12
+
13
+ abstract class Process {
14
+
15
+ use RestRouteConsumer;
16
+ use RestRequestConsumer;
17
+
18
+ /**
19
+ * @var RequestVO
20
+ */
21
+ private $reqVO;
22
+
23
+ /**
24
+ * @param RouteBase|mixed $route
25
+ */
26
+ public function __construct( $route = null, \WP_REST_Request $restRequest = null ) {
27
+ $this->setRestRoute( $route );
28
+ if ( $restRequest instanceof \WP_REST_Request ) {
29
+ $this->setWpRestRequest( $restRequest );
30
+ }
31
+ }
32
+
33
+ public function run() :array {
34
+ $route = $this->getRestRoute();
35
+
36
+ $meta = $this->getResponseMeta();
37
+
38
+ $locked = false;
39
+ try {
40
+ $this->verifyRequestParameters();
41
+
42
+ if ( $route->use_lock ) {
43
+ $locked = $this->lockStart();
44
+ }
45
+
46
+ // Begin processing.
47
+ $cacher = $route->getCacheHandler();
48
+ $cacher->setWpRestRequest( $this->getWpRestRequest() );
49
+
50
+ $data = null;
51
+ if ( $cacher->can_cache ) {
52
+ $data = $cacher->getCachedResponse();
53
+ }
54
+
55
+ if ( is_array( $data ) ) {
56
+ $meta[ 'from_cache' ] = true;
57
+ }
58
+ else {
59
+ $data = $this->process();
60
+ if ( $cacher->can_cache ) {
61
+ $cacher->storeCachedResponseData( $data );
62
+ }
63
+ }
64
+
65
+ $dataKey = $this->getResponseResultsDataKey();
66
+ $apiResponse = empty( $dataKey ) ? $data : [ $dataKey => $data ];
67
+ $apiResponse[ 'error_code' ] = 0;
68
+ $apiResponse[ 'http_status' ] = $this->getDefaultSuccessCode();
69
+ }
70
+ catch ( ApiException $e ) {
71
+ $apiResponse = [
72
+ 'error_code' => $e->getSubErrorCode(),
73
+ 'http_status' => $e->getCode(),
74
+ 'message' => $e->getMessage(),
75
+ ];
76
+ }
77
+
78
+ $apiResponse[ 'meta' ] = $meta;
79
+
80
+ if ( $locked ) {
81
+ $this->lockEnd();
82
+ }
83
+
84
+ return $apiResponse;
85
+ }
86
+
87
+ protected function getDefaultSuccessCode() :int {
88
+ return 200;
89
+ }
90
+
91
+ protected function postProcessResponseData( array $response ) :array {
92
+ return $response;
93
+ }
94
+
95
+ /**
96
+ * @throws ApiException
97
+ */
98
+ abstract protected function process() :array;
99
+
100
+ /**
101
+ * Reviews all Query parameters and determines whether there are any extra parameters no part of the provisioned
102
+ * arguments. Generally there shouldn't be extras. This will terminate the request if extras are found.
103
+ * @throws InvalidRequestParametersException
104
+ */
105
+ protected function verifyRequestParameters() :bool {
106
+ if ( $this->getRestRoute()->strict_parameters ) {
107
+
108
+ $req = $this->getWpRestRequest();
109
+ $permittedParams = array_keys( $req->get_attributes()[ 'args' ] );
110
+ if ( !Services::WpGeneral()->isPermalinksEnabled() ) {
111
+ $permittedParams[] = 'rest_route';
112
+ }
113
+
114
+ if ( count( array_diff_key( $req->get_params(), array_flip( $permittedParams ) ) ) > 0 ) {
115
+ throw new InvalidRequestParametersException(
116
+ sprintf( 'Please only supply parameters that are permitted: %s',
117
+ empty( $permittedParams ) ? 'none' : implode( ', ', $permittedParams ) )
118
+ );
119
+ }
120
+ }
121
+ return true;
122
+ }
123
+
124
+ protected function getResponseResultsDataKey() :string {
125
+ return '';
126
+ }
127
+
128
+ protected function getResponseBase() :array {
129
+ return [];
130
+ }
131
+
132
+ protected function getResponseMeta() :array {
133
+ return [
134
+ 'ts' => Services::Request()->ts(),
135
+ 'api_version' => $this->getRestRoute()->getVersion(),
136
+ 'from_cache' => false
137
+ ];
138
+ }
139
+
140
+ /**
141
+ * @return RequestVO|mixed
142
+ */
143
+ protected function getRequestVO() {
144
+ if ( !isset( $this->reqVO ) ) {
145
+ $this->reqVO = $this->newReqVO()
146
+ ->applyFromArray( $this->wpRestRequest->get_params() );
147
+ }
148
+ return $this->reqVO;
149
+ }
150
+
151
+ /**
152
+ * @return RequestVO
153
+ */
154
+ protected function newReqVO() {
155
+ return new RequestVO();
156
+ }
157
+
158
+ /**
159
+ * @throws CouldNotObtainLockException
160
+ */
161
+ protected function lockStart() :bool {
162
+ return false;
163
+ }
164
+
165
+ protected function lockEnd() {
166
+ }
167
+ }
src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Rest/Request/RequestVO.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Core\Rest\Request;
4
+
5
+ use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
6
+
7
+ /**
8
+ * @property string $action
9
+ * @property string $type
10
+ */
11
+ class RequestVO extends DynPropertiesClass {
12
+
13
+ /**
14
+ * @return string
15
+ */
16
+ public function getCacheFileSlug() {
17
+ $data = $this->getRawData();
18
+ ksort( $data );
19
+ return md5( serialize( $data ) );
20
+ }
21
+ }
src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Rest/RestHandler.php ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Core\Rest;
4
+
5
+ use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
6
+ use FernleafSystems\Wordpress\Plugin\Core\Rest\Route\RouteBase;
7
+ use FernleafSystems\Wordpress\Services\Services;
8
+
9
+ /**
10
+ * @property bool $publish
11
+ * @property string $limited_hosts - regex
12
+ * @property array $route_defs
13
+ */
14
+ abstract class RestHandler extends DynPropertiesClass {
15
+
16
+ /**
17
+ * @var RouteBase[]
18
+ */
19
+ private $routes;
20
+
21
+ public function __construct( array $config = [] ) {
22
+ $this->applyFromArray( $config );
23
+ }
24
+
25
+ public function applyFromArray( $data, array $restrictedKeys = [] ) {
26
+ return parent::applyFromArray( array_merge( $this->getConfigDefaults(), $data ), $restrictedKeys );
27
+ }
28
+
29
+ public function init() {
30
+ $this->preInit();
31
+ if ( $this->isPublishRoutes() ) {
32
+ foreach ( $this->buildRoutes() as $route ) {
33
+ $route->register_routes();
34
+ }
35
+ }
36
+ }
37
+
38
+ protected function preInit() {
39
+ }
40
+
41
+ /**
42
+ * @return RouteBase[]
43
+ */
44
+ protected function buildRoutes() :array {
45
+ $routeClasses = [];
46
+ $routes = $this->enumRoutes();
47
+ foreach ( $routes as $routeSlug => $routeClass ) {
48
+ $routeClasses[ $routeSlug ] = new $routeClass( $this->route_defs[ $routeSlug ] ?? [] );
49
+ }
50
+ return $routeClasses;
51
+ }
52
+
53
+ /**
54
+ * @return string[]
55
+ */
56
+ protected function enumRoutes() :array {
57
+ return [];
58
+ }
59
+
60
+ /**
61
+ * @return RouteBase[]
62
+ */
63
+ public function getRoutes() :array {
64
+ if ( !isset( $this->routes ) ) {
65
+ $this->routes = $this->buildRoutes();
66
+ }
67
+ return $this->routes;
68
+ }
69
+
70
+ protected function isPublishRoutes() :bool {
71
+ $publish = $this->publish ?? true;
72
+
73
+ $host = strtolower( Services::Request()->getHost() );
74
+ if ( $publish && !empty( $host ) && !empty( $this->limited_hosts ) ) {
75
+ $publish = preg_match( sprintf( '#%s#i', $this->limited_hosts ), $host );
76
+ }
77
+
78
+ return (bool)$publish;
79
+ }
80
+
81
+ protected function getConfigDefaults() :array {
82
+ return [
83
+ 'publish' => false,
84
+ 'limited_hosts' => '',
85
+ 'route_defs' => [],
86
+ ];
87
+ }
88
+ }
src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Rest/Route/RestRequestConsumer.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Core\Rest\Route;
4
+
5
+ trait RestRequestConsumer {
6
+
7
+ /**
8
+ * @var \WP_REST_Request
9
+ */
10
+ private $wpRestRequest;
11
+
12
+ public function getWpRestRequest() :\WP_REST_Request {
13
+ return $this->wpRestRequest;
14
+ }
15
+
16
+ /**
17
+ * @return $this
18
+ */
19
+ public function setWpRestRequest( \WP_REST_Request $req ) {
20
+ $this->wpRestRequest = $req;
21
+ return $this;
22
+ }
23
+ }
src/lib/{src/Modules/Base/Lib → vendor/fernleafsystems/wordpress-plugin-core/src}/Rest/Route/RestRouteConsumer.php RENAMED
@@ -1,27 +1,26 @@
1
- <?php declare( strict_types=1 );
2
-
3
- namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Rest\Route;
4
-
5
- trait RestRouteConsumer {
6
-
7
- /**
8
- * @var RouteBase|mixed
9
- */
10
- private $restRoute;
11
-
12
- /**
13
- * @return RouteBase|mixed
14
- */
15
- public function getRestRoute() {
16
- return $this->restRoute;
17
- }
18
-
19
- /**
20
- * @param RouteBase|mixed $route
21
- * @return $this
22
- */
23
- public function setRestRoute( $route ) {
24
- $this->restRoute = $route;
25
- return $this;
26
- }
27
  }
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Core\Rest\Route;
4
+
5
+ trait RestRouteConsumer {
6
+
7
+ /**
8
+ * @var RouteBase|mixed
9
+ */
10
+ private $route;
11
+
12
+ /**
13
+ * @return RouteBase|mixed
14
+ */
15
+ public function getRestRoute() {
16
+ return $this->route;
17
+ }
18
+
19
+ /**
20
+ * @param RouteBase|mixed $route
21
+ */
22
+ public function setRestRoute( $route ) {
23
+ $this->route = $route;
24
+ return $this;
25
+ }
 
26
  }
src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Rest/Route/RouteBase.php ADDED
@@ -0,0 +1,330 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Core\Rest\Route;
4
+
5
+ use FernleafSystems\Utilities\Data\Adapter\DynProperties;
6
+ use FernleafSystems\Wordpress\Plugin\Core\Rest\Request\Process;
7
+ use FernleafSystems\Wordpress\Services\Services;
8
+
9
+ /**
10
+ * @property bool $registered
11
+ * @property array $authorization
12
+ * @property bool $use_lock
13
+ * @property bool $strict_parameters
14
+ * @property string $version
15
+ * @property bool $response_include_params
16
+ * @property string[] $methods
17
+ * @property RouteCache $routeCache
18
+ */
19
+ abstract class RouteBase extends \WP_REST_Controller {
20
+
21
+ use DynProperties;
22
+
23
+ const ROUTE_METHOD = \WP_REST_Server::READABLE;
24
+
25
+ public function __construct( array $params = [] ) {
26
+ $this->applyFromArray( array_merge( $this->getConfigDefaults(), $params ) );
27
+ }
28
+
29
+ /**
30
+ * https://developer.wordpress.org/rest-api/extending-the-rest-api/adding-custom-endpoints/#examples
31
+ */
32
+ public function register_routes() {
33
+ if ( !isset( $this->registered ) ) {
34
+ $this->registered = true;
35
+ if ( $this->isReady() ) {
36
+ register_rest_route(
37
+ $this->buildNamespace(),
38
+ $this->buildRoutePath(),
39
+ [ $this->buildRouteDefs() ]
40
+ );
41
+ }
42
+ }
43
+ }
44
+
45
+ /**
46
+ * @param array[] $args
47
+ * @return array[]
48
+ */
49
+ protected function applyRouteDefaults( array $args ) :array {
50
+ return array_map(
51
+ function ( $arg ) {
52
+
53
+ $arg[ 'validate_callback' ] = function ( $value, $request, $reqArgKey ) {
54
+ return $this->validateRequestArg( $value, $request, $reqArgKey );
55
+ };
56
+
57
+ $arg[ 'sanitize_callback' ] = function ( $value, $request, $reqArgKey ) {
58
+ return $this->sanitizeRequestArg( $value, $request, $reqArgKey );
59
+ };
60
+
61
+ return $arg;
62
+ },
63
+ $args
64
+ );
65
+ }
66
+
67
+ public function buildRouteDefs() :array {
68
+ return [
69
+ 'methods' => $this->getRouteMethods(),
70
+ 'callback' => function ( \WP_REST_Request $req ) {
71
+ return $this->executeApiRequest( $req );
72
+ },
73
+ 'permission_callback' => function ( \WP_REST_Request $req ) {
74
+ return $this->verifyPermission( $req );
75
+ },
76
+ 'args' => $this->applyRouteDefaults( $this->getRouteArgs() ),
77
+ ];
78
+ }
79
+
80
+ public function getCacheHandler() :RouteCache {
81
+ if ( !isset( $this->routeCache ) ) {
82
+ $this->routeCache = new RouteCache( $this );
83
+ }
84
+ return $this->routeCache;
85
+ }
86
+
87
+ protected function buildNamespace() :string {
88
+ return sprintf( '%s/v%s', $this->getNamespace(), $this->getVersion() );
89
+ }
90
+
91
+ protected function getNamespace() :string {
92
+ return 'aptoweb';
93
+ }
94
+
95
+ public function getVersion() :string {
96
+ return $this->version ?? '1';
97
+ }
98
+
99
+ public function buildRoutePath() :string {
100
+ return '/'.trim( sprintf( '%s/%s',
101
+ trim( $this->getRoutePathPrefix(), '/' ),
102
+ trim( $this->getRoutePath(), '/' )
103
+ ), '/' );
104
+ }
105
+
106
+ abstract public function getRoutePath() :string;
107
+
108
+ public function getRoutePathPrefix() :string {
109
+ return '';
110
+ }
111
+
112
+ abstract protected function getRequestProcessorClass() :string;
113
+
114
+ /**
115
+ * @return Process|mixed
116
+ */
117
+ protected function getRequestProcessor() {
118
+ $processorClass = $this->getRequestProcessorClass();
119
+ return new $processorClass( $this );
120
+ }
121
+
122
+ /**
123
+ * @return array[]
124
+ */
125
+ protected function getRouteArgs() :array {
126
+ return array_merge( $this->getRouteArgsDefaults(), $this->getRouteArgsCustom() );
127
+ }
128
+
129
+ protected function getRouteArgSchema( string $key ) :array {
130
+ return [];
131
+ }
132
+
133
+ /**
134
+ * @return array[]
135
+ */
136
+ protected function getRouteArgsCustom() :array {
137
+ return [];
138
+ }
139
+
140
+ /**
141
+ * @return array[][]
142
+ */
143
+ protected function getRouteArgsDefaults() :array {
144
+ return [];
145
+ }
146
+
147
+ protected function getRouteSlug() :string {
148
+ return strtolower( ( new \ReflectionClass( $this ) )->getShortName() );
149
+ }
150
+
151
+ public function getRouteMethods() :array {
152
+ return $this->methods ?? array_map( 'trim', explode( ',', static::ROUTE_METHOD ) );
153
+ }
154
+
155
+ public function getWorkingDir() :string {
156
+ return '';
157
+ }
158
+
159
+ protected function isReady() :bool {
160
+ return true;
161
+ }
162
+
163
+ /**
164
+ * @return Process|mixed
165
+ */
166
+ protected function processRequest( \WP_REST_Request $req ) :array {
167
+ return $this->getRequestProcessor()
168
+ ->setWpRestRequest( $req )
169
+ ->run();
170
+ }
171
+
172
+ protected function executeApiRequest( \WP_REST_Request $req ) :\WP_REST_Response {
173
+
174
+ $data = $this->processRequest( $req );
175
+ if ( $this->response_include_params ) {
176
+ $data[ 'meta' ][ 'params' ] = $req->get_params();
177
+ }
178
+ $data = $this->adjustApiResponse( $data, $req );
179
+
180
+ $response = new \WP_REST_Response();
181
+
182
+ if ( $data[ 'error_code' ] === 0 ) {
183
+ $response->set_status( $data[ 'http_status' ] ?? 200 );
184
+ $response->header( 'Cache-Control', 'public, max-age='.$this->getCacheHandler()->expiration );
185
+ }
186
+ else {
187
+ $response->set_status( $data[ 'http_status' ] ?? 500 );
188
+ $response->header( 'Cache-Control', 'no-cache, must-revalidate' );
189
+ }
190
+ unset( $data[ 'http_status' ] );
191
+
192
+ $response->set_data( $data );
193
+
194
+ $this->finalAdjustApiResponse( $response, $req );
195
+ return $response;
196
+ }
197
+
198
+ protected function adjustApiResponse( array $response, \WP_REST_Request $req ) :array {
199
+ return $response;
200
+ }
201
+
202
+ protected function finalAdjustApiResponse( \WP_REST_Response $response, \WP_REST_Request $req ) {
203
+ }
204
+
205
+ /**
206
+ * @param string|mixed $value
207
+ * @param \WP_REST_Request $request
208
+ * @param string $reqArgKey
209
+ * @return \WP_Error|mixed
210
+ */
211
+ protected function sanitizeRequestArg( $value, \WP_REST_Request $request, string $reqArgKey ) {
212
+ try {
213
+ $value = rest_sanitize_request_arg( $value, $request, $reqArgKey );
214
+ if ( !is_wp_error( $value ) ) {
215
+ $value = $this->customSanitizeRequestArg( $value, $request, $reqArgKey );
216
+ }
217
+ }
218
+ catch ( \Exception $e ) {
219
+ $value = new \WP_Error( 400, $e->getMessage() );
220
+ }
221
+ return $value;
222
+ }
223
+
224
+ /**
225
+ * @param string|mixed $value
226
+ * @return \WP_Error|bool
227
+ */
228
+ protected function validateRequestArg( $value, \WP_REST_Request $request, string $reqArgKey ) {
229
+ try {
230
+ $valid = rest_validate_request_arg( $value, $request, $reqArgKey );
231
+ if ( $valid === true ) { // retain WP_ERROR info
232
+ $valid = $this->customValidateRequestArg( $value, $request, $reqArgKey );
233
+ }
234
+ }
235
+ catch ( \Exception $e ) {
236
+ $valid = new \WP_Error( 400, $e->getMessage() );
237
+ }
238
+ return $valid;
239
+ }
240
+
241
+ /**
242
+ * @param mixed $value
243
+ * @param \WP_REST_Request $request
244
+ * @param string $reqArgKey
245
+ * @return \WP_Error|mixed
246
+ * @throws \Exception
247
+ */
248
+ protected function customSanitizeRequestArg( $value, \WP_REST_Request $request, string $reqArgKey ) {
249
+ return $value;
250
+ }
251
+
252
+ /**
253
+ * @param string|mixed $value
254
+ * @return \WP_Error|true
255
+ * @throws \Exception
256
+ */
257
+ protected function customValidateRequestArg( $value, \WP_REST_Request $request, string $reqArgKey ) {
258
+ return true;
259
+ }
260
+
261
+ /**
262
+ * @return bool|\WP_Error
263
+ */
264
+ protected function verifyPermission( \WP_REST_Request $req ) {
265
+ $srvIP = Services::IP();
266
+ $ip = $srvIP->getRequestIp();
267
+
268
+ $authorized = true;
269
+ $auth = is_array( $this->authorization ) ? $this->authorization : [];
270
+
271
+ if ( !empty( $auth[ 'user_cap' ] ) ) {
272
+
273
+ if ( !Services::WpUsers()->isUserLoggedIn() ) {
274
+ $authorized = new \WP_Error( 403, 'You must be logged-in to access this resource.' );
275
+ }
276
+ elseif ( !current_user_can( $auth[ 'user_cap' ] ) ) {
277
+ $authorized = new \WP_Error( 403, "You don't have permission to access this resource." );
278
+ }
279
+ }
280
+
281
+ // Rest API routes may be called internally via WP-CLI. This should always be permitted and so
282
+ // IP-based restrictions should only ever be applied when there's a valid IP.
283
+ if ( !Services::WpGeneral()->isWpCli() ) {
284
+
285
+ $authIPs = $auth[ 'ips' ] ?? [];
286
+ $reverseDomains = (array)( $auth[ 'reverse_domains' ] ?? [] );
287
+
288
+ if ( !empty( $authIPs ) || !empty( $reverseDomains ) ) {
289
+
290
+ if ( !$srvIP->isValidIp( $ip ) ) {
291
+ new \WP_Error( 403, 'A valid IP address is required to access this resource.', [ 'ip' => $ip ] );
292
+ }
293
+
294
+ try {
295
+ if ( !empty( $authIPs ) && !$srvIP->checkIp( $ip, $authIPs ) ) {
296
+ $authorized = new \WP_Error( 403, "Your IP address isn't permitted to access this resource." );
297
+ }
298
+ }
299
+ catch ( \Exception $e ) {
300
+ }
301
+
302
+ if ( !empty( $reverseDomains ) ) {
303
+ $reqHost = gethostbyaddr( $ip );
304
+ if ( empty( $reqHost ) ) {
305
+ $authorized = new \WP_Error( 403, "Your IP address isn't permitted to access this resource." );
306
+ }
307
+ else {
308
+ foreach ( $reverseDomains as $rDomain ) {
309
+ if ( empty( preg_match( sprintf( '#%s$#i', preg_quote( $rDomain, '#' ) ), $reqHost ) ) ) {
310
+ $authorized = new \WP_Error( 403, "Your IP address isn't permitted to access this resource." );
311
+ break;
312
+ }
313
+ }
314
+ }
315
+ }
316
+ }
317
+ }
318
+
319
+ return $authorized;
320
+ }
321
+
322
+ protected function getConfigDefaults() :array {
323
+ return [
324
+ 'response_include_params' => false,
325
+ 'strict_parameters' => true,
326
+ 'use_lock' => false,
327
+ 'authorization' => [],
328
+ ];
329
+ }
330
+ }
src/lib/vendor/fernleafsystems/wordpress-plugin-core/src/Rest/Route/RouteCache.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Core\Rest\Route;
4
+
5
+ use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
6
+
7
+ /**
8
+ * @property bool $can_cache
9
+ * @property string $request_file
10
+ * @property bool $is_touch
11
+ * @property int $expiration
12
+ */
13
+ class RouteCache extends DynPropertiesClass {
14
+
15
+ use RestRouteConsumer;
16
+ use RestRequestConsumer;
17
+
18
+ /**
19
+ * @param RouteBase|mixed $route
20
+ */
21
+ public function __construct( $route ) {
22
+ $this->route = $route;
23
+ }
24
+
25
+ public function __get( string $key ) {
26
+ $val = parent::__get( $key );
27
+ switch ( $key ) {
28
+ case 'expiration':
29
+ $val = (int)$val;
30
+ break;
31
+ default:
32
+ break;
33
+ }
34
+ return $val;
35
+ }
36
+
37
+ /**
38
+ * @return array|null
39
+ */
40
+ public function getCachedResponse() {
41
+ return null;
42
+ }
43
+
44
+ public function storeCachedResponseData( array $data ) {
45
+ }
46
+
47
+ protected function getCacheFileFragment() :string {
48
+ $d = $this->getWpRestRequest()->get_params();
49
+ ksort( $d );
50
+ return md5( serialize( $d ) );
51
+ }
52
+ }
src/lib/vendor/fernleafsystems/wordpress-services/src/Core/Rest.php CHANGED
@@ -6,20 +6,32 @@ use FernleafSystems\Wordpress\Services\Services;
6
 
7
  class Rest {
8
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  /**
10
  * @return string|null
11
  */
12
  public function getNamespace() {
13
- $sNameSpace = null;
14
 
15
  $sRoute = $this->getRoute();
16
  if ( !empty( $sRoute ) ) {
17
  $aParts = array_filter( explode( '/', $sRoute ) );
18
  if ( !empty( $aParts ) ) {
19
- $sNameSpace = array_shift( $aParts );
20
  }
21
  }
22
- return $sNameSpace;
23
  }
24
 
25
  /**
@@ -41,21 +53,18 @@ class Rest {
41
  return $sRoute;
42
  }
43
 
44
- /**
45
- * @return bool
46
- */
47
- public function isRest() {
48
- $bIsRest = ( defined( 'REST_REQUEST' ) && REST_REQUEST ) || !empty( $_REQUEST[ 'rest_route' ] );
49
 
50
  global $wp_rewrite;
51
- if ( !$bIsRest && function_exists( 'rest_url' ) && is_object( $wp_rewrite ) ) {
52
  $sRestUrlBase = get_rest_url( get_current_blog_id(), '/' );
53
  $sRestPath = trim( parse_url( $sRestUrlBase, PHP_URL_PATH ), '/' );
54
  $sRequestPath = trim( Services::Request()->getPath(), '/' );
55
- $bIsRest = !empty( $sRequestPath ) && !empty( $sRestPath )
56
- && ( strpos( $sRequestPath, $sRestPath ) === 0 );
57
  }
58
- return $bIsRest;
59
  }
60
 
61
  /**
6
 
7
  class Rest {
8
 
9
+ public function callInternal( array $req ) :\WP_REST_Response {
10
+ $internal = new \WP_REST_Request(
11
+ $req[ 'method' ] ?? 'GET', $req[ 'route' ], $req[ 'attributes' ] ?? [] );
12
+ if ( !empty( $req[ 'query_params' ] ) ) {
13
+ $internal->set_query_params( $req[ 'query_params' ] );
14
+ }
15
+ if ( !empty( $req[ 'body_params' ] ) ) {
16
+ $internal->set_body_params( $req[ 'query_params' ] );
17
+ }
18
+ return rest_do_request( $internal );
19
+ }
20
+
21
  /**
22
  * @return string|null
23
  */
24
  public function getNamespace() {
25
+ $nameSpace = null;
26
 
27
  $sRoute = $this->getRoute();
28
  if ( !empty( $sRoute ) ) {
29
  $aParts = array_filter( explode( '/', $sRoute ) );
30
  if ( !empty( $aParts ) ) {
31
+ $nameSpace = array_shift( $aParts );
32
  }
33
  }
34
+ return $nameSpace;
35
  }
36
 
37
  /**
53
  return $sRoute;
54
  }
55
 
56
+ public function isRest() :bool {
57
+ $isRest = ( defined( 'REST_REQUEST' ) && REST_REQUEST ) || !empty( $_REQUEST[ 'rest_route' ] );
 
 
 
58
 
59
  global $wp_rewrite;
60
+ if ( !$isRest && function_exists( 'rest_url' ) && is_object( $wp_rewrite ) ) {
61
  $sRestUrlBase = get_rest_url( get_current_blog_id(), '/' );
62
  $sRestPath = trim( parse_url( $sRestUrlBase, PHP_URL_PATH ), '/' );
63
  $sRequestPath = trim( Services::Request()->getPath(), '/' );
64
+ $isRest = !empty( $sRequestPath ) && !empty( $sRestPath )
65
+ && ( strpos( $sRequestPath, $sRestPath ) === 0 );
66
  }
67
+ return $isRest;
68
  }
69
 
70
  /**
src/lib/vendor/fernleafsystems/wordpress-services/src/Core/Users.php CHANGED
@@ -8,11 +8,9 @@ use FernleafSystems\Wordpress\Services\Utilities\PluginUserMeta;
8
  class Users {
9
 
10
  /**
11
- * @param string $key
12
  * @param \WP_User|int $userID -user ID
13
- * @return bool
14
  */
15
- public function deleteUserMeta( string $key, $userID = null ) {
16
  if ( empty( $userID ) ) {
17
  $userID = $this->getCurrentWpUserId();
18
  }
@@ -20,7 +18,7 @@ class Users {
20
  $userID = $userID->ID;
21
  }
22
 
23
- return $userID > 0 ? delete_user_meta( $userID, $key ) : false;
24
  }
25
 
26
  public function exists( string $usernameOrEmail ) :bool {
@@ -29,20 +27,30 @@ class Users {
29
  }
30
 
31
  /**
32
- * @param array $aLoginUrlParams
33
  */
34
- public function forceUserRelogin( $aLoginUrlParams = [] ) {
35
  $this->logoutUser();
36
- Services::Response()->redirectToLogin( $aLoginUrlParams );
37
  }
38
 
39
  /**
40
- * @param \WP_User $u
41
- * @return string
42
  */
43
- public function getAdminUrl_ProfileEdit( $u = null ) {
44
- $path = $u instanceof \WP_User ? 'user-edit.php?user_id='.$u->ID : 'profile.php';
45
- return Services::WpGeneral()->getAdminUrl( $path );
 
 
 
 
 
 
 
 
 
 
 
46
  }
47
 
48
  /**
8
  class Users {
9
 
10
  /**
 
11
  * @param \WP_User|int $userID -user ID
 
12
  */
13
+ public function deleteUserMeta( string $key, $userID = null ) :bool {
14
  if ( empty( $userID ) ) {
15
  $userID = $this->getCurrentWpUserId();
16
  }
18
  $userID = $userID->ID;
19
  }
20
 
21
+ return $userID > 0 && delete_user_meta( $userID, $key );
22
  }
23
 
24
  public function exists( string $usernameOrEmail ) :bool {
27
  }
28
 
29
  /**
30
+ * @param array $loginUrlParams
31
  */
32
+ public function forceUserRelogin( $loginUrlParams = [] ) {
33
  $this->logoutUser();
34
+ Services::Response()->redirectToLogin( $loginUrlParams );
35
  }
36
 
37
  /**
38
+ * @param \WP_User|int $user
 
39
  */
40
+ public function getAdminUrl_ProfileEdit( $user = null ) :string {
41
+ if ( $user instanceof \WP_User ) {
42
+ $uid = $user->ID;
43
+ }
44
+ elseif ( is_numeric( $user ) ) {
45
+ $uid = $user;
46
+ }
47
+ else {
48
+ $uid = null;
49
+ }
50
+
51
+ return Services::WpGeneral()->getAdminUrl(
52
+ is_null( $uid ) ? 'profile.php' : 'user-edit.php?user_id='.$uid
53
+ );
54
  }
55
 
56
  /**
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Consumers/WpUserConsumer.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Services\Utilities\Consumers;
4
+
5
+ trait WpUserConsumer {
6
+
7
+ /**
8
+ * @var \WP_User
9
+ */
10
+ private $user;
11
+
12
+ public function getWpUser() :\WP_User {
13
+ return $this->user;
14
+ }
15
+
16
+ /**
17
+ * @return $this
18
+ */
19
+ public function setWpUser( \WP_User $user ) {
20
+ $this->user = $user;
21
+ return $this;
22
+ }
23
+ }
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Iterators/WpUserIterator.php CHANGED
@@ -2,10 +2,6 @@
2
 
3
  namespace FernleafSystems\Wordpress\Services\Utilities\Iterators;
4
 
5
- /**
6
- * Class WpUserIterator
7
- * @package FernleafSystems\Wordpress\Plugin\Shield\Users
8
- */
9
  class WpUserIterator extends \Elliotchance\Iterator\AbstractPagedIterator {
10
 
11
  const PAGE_LIMIT = 50;
2
 
3
  namespace FernleafSystems\Wordpress\Services\Utilities\Iterators;
4
 
 
 
 
 
5
  class WpUserIterator extends \Elliotchance\Iterator\AbstractPagedIterator {
6
 
7
  const PAGE_LIMIT = 50;
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Base.php CHANGED
@@ -7,8 +7,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
@@ -16,8 +14,9 @@ use FernleafSystems\Wordpress\Services\Utilities\HttpRequest;
16
  */
17
  abstract class Base extends DynPropertiesClass {
18
 
19
- const DEFAULT_URL_STUB = 'https://api.getshieldsecurity.com/wp-json/odp-eddkeyless/v1';
20
  const API_ACTION = '';
 
21
 
22
  /**
23
  * @return array|null
@@ -64,7 +63,7 @@ abstract class Base extends DynPropertiesClass {
64
  }
65
 
66
  protected function getApiRequestUrl() :string {
67
- return sprintf( '%s/%s', $this->lookup_url_stub, static::API_ACTION );
68
  }
69
 
70
  /**
7
  use FernleafSystems\Wordpress\Services\Utilities\HttpRequest;
8
 
9
  /**
 
 
10
  * @property string $lookup_url_stub
11
  * @property string $request_method
12
  * @property int $timeout
14
  */
15
  abstract class Base extends DynPropertiesClass {
16
 
17
+ const DEFAULT_URL_STUB = 'https://api.getshieldsecurity.com/wp-json/apto-keyless';
18
  const API_ACTION = '';
19
+ const API_VERSION = '2';
20
 
21
  /**
22
  * @return array|null
63
  }
64
 
65
  protected function getApiRequestUrl() :string {
66
+ return sprintf( '%s/v%s/%s', $this->lookup_url_stub, static::API_VERSION, static::API_ACTION );
67
  }
68
 
69
  /**
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Lookup.php CHANGED
@@ -6,8 +6,6 @@ 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
@@ -24,8 +22,8 @@ class Lookup extends Base {
24
  }
25
 
26
  $raw = $this->sendReq();
27
- if ( is_array( $raw ) && !empty( $raw[ 'keyless' ] ) && !empty( $raw[ 'keyless' ][ 'license' ] ) ) {
28
- $info = $raw[ 'keyless' ][ 'license' ];
29
  }
30
  else {
31
  $info = [];
6
  use FernleafSystems\Wordpress\Services\Utilities\Licenses\EddLicenseVO;
7
 
8
  /**
 
 
9
  * @property int $item_id
10
  * @property string $install_id
11
  * @property string $url
22
  }
23
 
24
  $raw = $this->sendReq();
25
+ if ( is_array( $raw ) && $raw[ 'error_code' ] === 0 ) {
26
+ $info = $raw[ 'license' ];
27
  }
28
  else {
29
  $info = [];
src/lib/vendor/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Ping.php CHANGED
@@ -1,26 +1,13 @@
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
- $pong = '';
18
-
19
  $raw = $this->sendReq();
20
- if ( is_array( $raw ) && !empty( $raw[ 'keyless' ] ) && !empty( $raw[ 'keyless' ][ self::API_ACTION ] ) ) {
21
- $pong = $raw[ 'keyless' ][ self::API_ACTION ];
22
- }
23
-
24
- return $pong === 'pong';
25
  }
26
  }
1
+ <?php declare( strict_types=1 );
2
 
3
  namespace FernleafSystems\Wordpress\Services\Utilities\Licenses\Keyless;
4
 
 
 
 
 
5
  class Ping extends Base {
6
 
7
  const API_ACTION = 'ping';
8
 
9
+ public function ping() :bool {
 
 
 
 
 
10
  $raw = $this->sendReq();
11
+ return is_array( $raw ) && ( $raw[ 'ping' ] ?? '' ) === 'pong';
 
 
 
 
12
  }
13
  }
src/lib/vendor/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php CHANGED
@@ -38,9 +38,11 @@ class JsonFormatter extends NormalizerFormatter
38
  /**
39
  * @param int $batchMode
40
  * @param bool $appendNewline
 
41
  */
42
- public function __construct($batchMode = self::BATCH_MODE_JSON, $appendNewline = true)
43
  {
 
44
  $this->batchMode = $batchMode;
45
  $this->appendNewline = $appendNewline;
46
  }
@@ -141,8 +143,8 @@ class JsonFormatter extends NormalizerFormatter
141
  */
142
  protected function normalize($data, $depth = 0)
143
  {
144
- if ($depth > 9) {
145
- return 'Over 9 levels deep, aborting normalization';
146
  }
147
 
148
  if (is_array($data)) {
38
  /**
39
  * @param int $batchMode
40
  * @param bool $appendNewline
41
+ * @param int $maxDepth
42
  */
43
+ public function __construct($batchMode = self::BATCH_MODE_JSON, $appendNewline = true, $maxDepth = 9)
44
  {
45
+ parent::__construct(null, $maxDepth);
46
  $this->batchMode = $batchMode;
47
  $this->appendNewline = $appendNewline;
48
  }
143
  */
144
  protected function normalize($data, $depth = 0)
145
  {
146
+ if ($depth > $this->maxDepth) {
147
+ return 'Over '.$this->maxDepth.' levels deep, aborting normalization';
148
  }
149
 
150
  if (is_array($data)) {
src/lib/vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php CHANGED
@@ -24,13 +24,16 @@ class NormalizerFormatter implements FormatterInterface
24
  const SIMPLE_DATE = "Y-m-d H:i:s";
25
 
26
  protected $dateFormat;
 
27
 
28
  /**
29
  * @param string $dateFormat The format of the timestamp: one supported by DateTime::format
 
30
  */
31
- public function __construct($dateFormat = null)
32
  {
33
  $this->dateFormat = $dateFormat ?: static::SIMPLE_DATE;
 
34
  if (!function_exists('json_encode')) {
35
  throw new \RuntimeException('PHP\'s json extension is required to use Monolog\'s NormalizerFormatter');
36
  }
@@ -56,10 +59,26 @@ class NormalizerFormatter implements FormatterInterface
56
  return $records;
57
  }
58
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  protected function normalize($data, $depth = 0)
60
  {
61
- if ($depth > 9) {
62
- return 'Over 9 levels deep, aborting normalization';
63
  }
64
 
65
  if (null === $data || is_scalar($data)) {
@@ -177,4 +196,4 @@ class NormalizerFormatter implements FormatterInterface
177
  {
178
  return Utils::jsonEncode($data, null, $ignoreErrors);
179
  }
180
- }
24
  const SIMPLE_DATE = "Y-m-d H:i:s";
25
 
26
  protected $dateFormat;
27
+ protected $maxDepth;
28
 
29
  /**
30
  * @param string $dateFormat The format of the timestamp: one supported by DateTime::format
31
+ * @param int $maxDepth
32
  */
33
+ public function __construct($dateFormat = null, $maxDepth = 9)
34
  {
35
  $this->dateFormat = $dateFormat ?: static::SIMPLE_DATE;
36
+ $this->maxDepth = $maxDepth;
37
  if (!function_exists('json_encode')) {
38
  throw new \RuntimeException('PHP\'s json extension is required to use Monolog\'s NormalizerFormatter');
39
  }
59
  return $records;
60
  }
61
 
62
+ /**
63
+ * @return int
64
+ */
65
+ public function getMaxDepth()
66
+ {
67
+ return $this->maxDepth;
68
+ }
69
+
70
+ /**
71
+ * @param int $maxDepth
72
+ */
73
+ public function setMaxDepth($maxDepth)
74
+ {
75
+ $this->maxDepth = $maxDepth;
76
+ }
77
+
78
  protected function normalize($data, $depth = 0)
79
  {
80
+ if ($depth > $this->maxDepth) {
81
+ return 'Over '.$this->maxDepth.' levels deep, aborting normalization';
82
  }
83
 
84
  if (null === $data || is_scalar($data)) {
196
  {
197
  return Utils::jsonEncode($data, null, $ignoreErrors);
198
  }
199
+ }
templates/twig/wpadmin_pages/insights/ips/ip_analyse/ip_audittrail.twig CHANGED
@@ -20,8 +20,11 @@
20
  <td>
21
  <span>{{ log.user }}</span>
22
  </td>
23
- <td class="w-50">{{ log.event|raw }}</td>
24
- <td>{{ log.created_at|raw }}</td>
 
 
 
25
  </tr>
26
  {% endfor %}
27
  </tbody>
20
  <td>
21
  <span>{{ log.user }}</span>
22
  </td>
23
+ <td class="w-50">{{ log.event }}</td>
24
+ <td>
25
+ {{ log.created_at_ago }}
26
+ <div class="timestamp-small">{{ log.created_at }}</div>
27
+ </td>
28
  </tr>
29
  {% endfor %}
30
  </tbody>
templates/twig/wpadmin_pages/insights/ips/ip_analyse/ip_info.twig CHANGED
@@ -40,19 +40,19 @@
40
 
41
  <div class="tab-content">
42
  <div class="tab-pane show active" id="tabIpInfoGeneral" role="tabpanel" aria-labelledby="tabIpInfoGeneral">
43
- {{ content.general|raw }}
44
  </div>
45
  <div class="tab-pane" id="tabIpInfoBotSignals" role="tabpanel" aria-labelledby="tabIpInfoBotSignals">
46
- {{ content.signals|raw }}
47
  </div>
48
  <div class="tab-pane" id="tabIpInfoSessions" role="tabpanel" aria-labelledby="tabIpInfoSessions">
49
- {{ content.sessions|raw }}
50
  </div>
51
  <div class="tab-pane" id="tabIpInfoAudit" role="tabpanel" aria-labelledby="tabIpInfoAudit">
52
- {{ content.audit_trail|raw }}
53
  </div>
54
  <div class="tab-pane" id="tabIpInfoTraffic" role="tabpanel" aria-labelledby="tabIpInfoTraffic">
55
- {{ content.traffic|raw }}
56
  </div>
57
  </div>
58
  </div>
40
 
41
  <div class="tab-content">
42
  <div class="tab-pane show active" id="tabIpInfoGeneral" role="tabpanel" aria-labelledby="tabIpInfoGeneral">
43
+ {{ content.general|default('no content')|raw }}
44
  </div>
45
  <div class="tab-pane" id="tabIpInfoBotSignals" role="tabpanel" aria-labelledby="tabIpInfoBotSignals">
46
+ {{ content.signals|default('no content')|raw }}
47
  </div>
48
  <div class="tab-pane" id="tabIpInfoSessions" role="tabpanel" aria-labelledby="tabIpInfoSessions">
49
+ {{ content.sessions|default('no content')|raw }}
50
  </div>
51
  <div class="tab-pane" id="tabIpInfoAudit" role="tabpanel" aria-labelledby="tabIpInfoAudit">
52
+ {{ content.audit_trail|default('no content')|raw }}
53
  </div>
54
  <div class="tab-pane" id="tabIpInfoTraffic" role="tabpanel" aria-labelledby="tabIpInfoTraffic">
55
+ {{ content.traffic|default('no content')|raw }}
56
  </div>
57
  </div>
58
  </div>
templates/twig/wpadmin_pages/insights/ips/ip_analyse/ip_sessions.twig CHANGED
@@ -26,8 +26,14 @@
26
  {% endif %}
27
  </span>
28
  </td>
29
- <td>{{ session.last_activity_at|raw }}</td>
30
- <td>{{ session.logged_in_at|raw }}</td>
 
 
 
 
 
 
31
  </tr>
32
  {% endfor %}
33
  </tbody>
26
  {% endif %}
27
  </span>
28
  </td>
29
+ <td>
30
+ {{ session.last_activity_at_ago }}
31
+ <div class="timestamp-small">{{ session.last_activity_at }}</div>
32
+ </td>
33
+ <td>
34
+ {{ session.logged_in_at_ago }}
35
+ <div class="timestamp-small">{{ session.logged_in_at }}</div>
36
+ </td>
37
  </tr>
38
  {% endfor %}
39
  </tbody>
templates/twig/wpadmin_pages/insights/ips/ip_analyse/ip_traffic.twig CHANGED
@@ -17,7 +17,10 @@
17
  <tbody>
18
  {% for request in vars.requests %}
19
  <tr>
20
- <td>{{ request.created_at|raw }}</td>
 
 
 
21
 
22
  <td>
23
  <div>
@@ -41,7 +44,7 @@
41
  {{ strings.path }}:<code>{{ request.path }}</code>
42
  </div>
43
  {% if request.query is not empty %}
44
- <div>{{ strings.query }}:<code>?{{ request.query|raw }}</code></div>
45
  {% endif %}
46
  </td>
47
  </tr>
17
  <tbody>
18
  {% for request in vars.requests %}
19
  <tr>
20
+ <td>
21
+ {{ request.created_at_ago }}
22
+ <div class="timestamp-small">{{ request.created_at }}</div>
23
+ </td>
24
 
25
  <td>
26
  <div>
44
  {{ strings.path }}:<code>{{ request.path }}</code>
45
  </div>
46
  {% if request.query is not empty %}
47
+ <div>{{ strings.query }}:<code>?{{ request.query }}</code></div>
48
  {% endif %}
49
  </td>
50
  </tr>
templates/twig/wpadmin_pages/insights/scans/modal/code_render.twig DELETED
@@ -1,20 +0,0 @@
1
- <div class="modal" id="CodeRenderModal" tabindex="-1" role="dialog" aria-labelledby=""
2
- style="z-index: 10000000;"
3
- aria-hidden="true">
4
- <div class="modal-dialog modal-xl modal-dialog-scrollable" role="document" style="z-index: 10000001;">
5
- <div class="modal-content">
6
- <div class="modal-header">
7
- <h5 class="modal-title">
8
- code
9
- </h5>
10
- <button type="button" class="close" data-dismiss="modal" aria-label="Close">
11
- <span aria-hidden="true">&times;</span>
12
- </button>
13
- </div>
14
- <div class="modal-body">
15
- </div>
16
- <div class="modal-footer">
17
- </div>
18
- </div>
19
- </div>
20
- </div>