Shield Security for WordPress - Version 11.1.0

Version Description

Download this release

Release Info

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

Code changes from version 11.0.3 to 11.1.0

Files changed (255) hide show
  1. cl.json +74 -2
  2. icwp-wpsf.php +1 -1
  3. plugin-spec.php +30 -8
  4. readme.txt +1 -1
  5. resources/css/plugin.css +57 -24
  6. resources/css/{mainwp-extension.css → shield/mainwp.css} +0 -0
  7. resources/images/bootstrap/arrow-down-up.svg +1 -1
  8. resources/images/bootstrap/award.svg +2 -2
  9. resources/images/bootstrap/binoculars.svg +2 -2
  10. resources/images/bootstrap/book-half.svg +2 -2
  11. resources/images/bootstrap/bug.svg +2 -2
  12. resources/images/bootstrap/chat-right-dots-fill.svg +2 -2
  13. resources/images/bootstrap/diagram-3.svg +1 -1
  14. resources/images/bootstrap/emoji-smile.svg +3 -4
  15. resources/images/bootstrap/graph-up.svg +2 -2
  16. resources/images/bootstrap/link-45deg.svg +3 -3
  17. resources/images/bootstrap/pencil-square.svg +2 -2
  18. resources/images/bootstrap/people.svg +2 -2
  19. resources/images/bootstrap/person-badge.svg +3 -3
  20. resources/images/bootstrap/person-lines-fill.svg +2 -2
  21. resources/images/bootstrap/plug-fill.svg +3 -0
  22. resources/images/bootstrap/puzzle-fill.svg +3 -0
  23. resources/images/bootstrap/search.svg +3 -0
  24. resources/images/bootstrap/shield-shaded.svg +2 -3
  25. resources/images/bootstrap/sliders.svg +1 -1
  26. resources/images/bootstrap/speedometer.svg +4 -0
  27. resources/images/bootstrap/stickies.svg +3 -4
  28. resources/images/bootstrap/sticky.svg +2 -3
  29. resources/images/bootstrap/stoplights.svg +3 -4
  30. resources/images/bootstrap/tools.svg +3 -0
  31. resources/js/global-plugin.js +33 -176
  32. resources/js/icwp-options.js +0 -70
  33. resources/js/plugin.js +28 -87
  34. resources/js/shield/mainwp-extension.js +0 -14
  35. resources/js/shield/navigation.js +61 -0
  36. resources/js/shield/options.js +304 -0
  37. resources/js/shield/scans.js +19 -22
  38. resources/js/shield/secadmin.js +118 -0
  39. resources/js/shield/tables.js +2 -2
  40. src/config/feature-admin_access_restriction.php +5 -5
  41. src/config/feature-audit_trail.php +15 -35
  42. src/config/feature-comments_filter.php +5 -8
  43. src/config/feature-events.php +1 -5
  44. src/config/feature-firewall.php +4 -1
  45. src/config/feature-hack_protect.php +49 -47
  46. src/config/feature-headers.php +1 -1
  47. src/config/feature-ips.php +1 -14
  48. src/config/feature-login_protect.php +1 -4
  49. src/config/feature-plugin.php +12 -14
  50. src/config/feature-sessions.php +1 -15
  51. src/config/feature-traffic.php +0 -10
  52. src/lib/src/Controller/Config/ConfigVO.php +0 -9
  53. src/lib/src/Controller/Controller.php +31 -59
  54. src/lib/src/Databases/AuditTrail/Handler.php +4 -8
  55. src/lib/src/Databases/Base/BaseQuery.php +1 -1
  56. src/lib/src/Databases/Base/Handler.php +19 -66
  57. src/lib/src/Databases/Base/Insert.php +2 -4
  58. src/lib/src/Databases/Base/Select.php +11 -7
  59. src/lib/src/Databases/Base/Update.php +1 -1
  60. src/lib/src/Databases/ChangeTracking/Handler.php +0 -24
  61. src/lib/src/Databases/Common/TableSchema.php +1 -30
  62. src/lib/src/Databases/Events/Handler.php +4 -4
  63. src/lib/src/Databases/Events/Select.php +4 -4
  64. src/lib/src/Databases/FileLocker/Handler.php +4 -4
  65. src/lib/src/Databases/IPs/Handler.php +2 -18
  66. src/lib/src/Databases/ScanQueue/Select.php +7 -11
  67. src/lib/src/Databases/Scanner/Select.php +5 -9
  68. src/lib/src/Databases/Session/Handler.php +4 -8
  69. src/lib/src/Databases/Traffic/Handler.php +4 -4
  70. src/lib/src/Modules/AuditTrail/Auditors/Base.php +3 -1
  71. src/lib/src/Modules/AuditTrail/Auditors/Emails.php +1 -1
  72. src/lib/src/Modules/AuditTrail/Auditors/Plugins.php +1 -1
  73. src/lib/src/Modules/AuditTrail/Auditors/Posts.php +1 -1
  74. src/lib/src/Modules/AuditTrail/Auditors/Themes.php +1 -1
  75. src/lib/src/Modules/AuditTrail/Auditors/Upgrades.php +43 -20
  76. src/lib/src/Modules/AuditTrail/Auditors/Users.php +1 -1
  77. src/lib/src/Modules/AuditTrail/Auditors/Wordpress.php +1 -1
  78. src/lib/src/Modules/AuditTrail/Lib/AuditWriter.php +17 -14
  79. src/lib/src/Modules/AuditTrail/ModCon.php +1 -2
  80. src/lib/src/Modules/AuditTrail/Processor.php +7 -7
  81. src/lib/src/Modules/AuditTrail/UI.php +0 -10
  82. src/lib/src/Modules/Base/AjaxHandler.php +1 -36
  83. src/lib/src/Modules/Base/Lib/Request/FormParams.php +48 -0
  84. src/lib/src/Modules/Base/ModCon.php +50 -84
  85. src/lib/src/Modules/Base/Options.php +1 -1
  86. src/lib/src/Modules/Base/Strings.php +5 -5
  87. src/lib/src/Modules/Base/UI.php +13 -11
  88. src/lib/src/Modules/BaseShield/ModCon.php +26 -20
  89. src/lib/src/Modules/BaseShield/UI.php +0 -7
  90. src/lib/src/Modules/CommentsFilter/Scan/Scanner.php +1 -0
  91. src/lib/src/Modules/Events/Consolidate/ConsolidateAllEvents.php +22 -22
  92. src/lib/src/Modules/Events/Lib/EventsListener.php +6 -6
  93. src/lib/src/Modules/Events/Lib/EventsService.php +7 -2
  94. src/lib/src/Modules/Events/Lib/Reports/KeyStats.php +20 -21
  95. src/lib/src/Modules/Events/Lib/StatsWriter.php +11 -5
  96. src/lib/src/Modules/Events/Strings.php +6 -0
  97. src/lib/src/Modules/Events/UI.php +113 -0
  98. src/lib/src/Modules/Firewall/Lib/Scan/CanScan.php +28 -0
  99. src/lib/src/Modules/Firewall/Lib/Scan/Checks/Base.php +38 -0
  100. src/lib/src/Modules/Firewall/Lib/Scan/Checks/ExeFiles.php +41 -0
  101. src/lib/src/Modules/Firewall/Lib/Scan/Checks/Standard.php +69 -0
  102. src/lib/src/Modules/Firewall/Lib/Scan/ParametersToScan.php +85 -0
  103. src/lib/src/Modules/Firewall/Lib/Scan/PerformScan.php +70 -0
  104. src/lib/src/Modules/Firewall/Options.php +2 -2
  105. src/lib/src/Modules/Firewall/Processor.php +19 -13
  106. src/lib/src/Modules/HackGuard/AjaxHandler.php +30 -12
  107. src/lib/src/Modules/HackGuard/Insights/OverviewCards.php +8 -8
  108. src/lib/src/Modules/HackGuard/Lib/FileLocker/File.php +15 -10
  109. src/lib/src/Modules/HackGuard/Lib/FileLocker/FileLockerController.php +30 -23
  110. src/lib/src/Modules/HackGuard/Lib/FileLocker/Ops/BaseOps.php +12 -12
  111. src/lib/src/Modules/HackGuard/Lib/FileLocker/Ops/CreateFileLocks.php +4 -4
  112. src/lib/src/Modules/HackGuard/Lib/FileLocker/Ops/DeleteFileLock.php +10 -14
  113. src/lib/src/Modules/HackGuard/Lib/FileLocker/Ops/LoadFileLocks.php +1 -1
  114. src/lib/src/Modules/HackGuard/Lib/Reports/FileLockerAlerts.php +1 -1
  115. src/lib/src/Modules/HackGuard/Lib/Reports/ScanAlerts.php +6 -1
  116. src/lib/src/Modules/HackGuard/ModCon.php +15 -14
  117. src/lib/src/Modules/HackGuard/Scan/Queue/Build/QueueBuilder.php +1 -1
  118. src/lib/src/Modules/HackGuard/Scan/Queue/IsScanEnqueued.php +4 -8
  119. src/lib/src/Modules/HackGuard/Scan/Queue/ScanInitiate.php +1 -1
  120. src/lib/src/Modules/HackGuard/Strings.php +12 -12
  121. src/lib/src/Modules/HackGuard/UI.php +32 -34
  122. src/lib/src/Modules/Headers/ModCon.php +0 -6
  123. src/lib/src/Modules/Headers/Strings.php +0 -1
  124. src/lib/src/Modules/IPs/AjaxHandler.php +5 -4
  125. src/lib/src/Modules/IPs/BotTrack/TrackLinkCheese.php +0 -15
  126. src/lib/src/Modules/IPs/Lib/AutoUnblock.php +14 -17
  127. src/lib/src/Modules/IPs/Lib/BlockRequest.php +16 -30
  128. src/lib/src/Modules/IPs/Lib/Bots/BotEventListener.php +80 -0
  129. src/lib/src/Modules/IPs/Lib/Bots/BotSignalsController.php +3 -3
  130. src/lib/src/Modules/IPs/Lib/OffenseTracker.php +22 -25
  131. src/lib/src/Modules/IPs/Lib/ProcessOffenses.php +9 -9
  132. src/lib/src/Modules/IPs/ModCon.php +1 -2
  133. src/lib/src/Modules/IPs/Options.php +2 -6
  134. src/lib/src/Modules/IPs/Strings.php +21 -21
  135. src/lib/src/Modules/IPs/UI.php +0 -21
  136. src/lib/src/Modules/Insights/AjaxHandler.php +49 -0
  137. src/lib/src/Modules/Insights/Lib/Requests/DynamicPageLoader.php +95 -0
  138. src/lib/src/Modules/Insights/Lib/SideMenuBuilder.php +477 -0
  139. src/lib/src/Modules/Insights/ModCon.php +45 -13
  140. src/lib/src/Modules/Insights/UI.php +45 -94
  141. src/lib/src/Modules/Integrations/Lib/MainWP/Server/UI/ExtensionSettingsPage.php +2 -2
  142. src/lib/src/Modules/Integrations/Lib/MainWP/Server/UI/PageRender/SitesList.php +1 -1
  143. src/lib/src/Modules/Integrations/Strings.php +1 -0
  144. src/lib/src/Modules/License/UI.php +0 -23
  145. src/lib/src/Modules/LoginGuard/Lib/AntiBot/AntibotSetup.php +14 -14
  146. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/MfaController.php +47 -1
  147. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Email.php +18 -1
  148. src/lib/src/Modules/LoginGuard/Processor.php +1 -1
  149. src/lib/src/Modules/Plugin/AjaxHandler.php +9 -30
  150. src/lib/src/Modules/Plugin/Insights/DashboardCards.php +1 -9
  151. src/lib/src/Modules/Plugin/Lib/Debug/Collate.php +9 -7
  152. src/lib/src/Modules/Plugin/Lib/ImportExport/ImportExportController.php +12 -20
  153. src/lib/src/Modules/Plugin/Lib/ImportExport/Options/BuildTransferableOptions.php +4 -4
  154. src/lib/src/Modules/Plugin/Lib/ImportExport/Options/SaveExcludedOptions.php +6 -6
  155. src/lib/src/Modules/Plugin/Lib/TourManager.php +2 -1
  156. src/lib/src/Modules/Plugin/ModCon.php +1 -26
  157. src/lib/src/Modules/Plugin/Strings.php +16 -12
  158. src/lib/src/Modules/Plugin/UI.php +10 -19
  159. src/lib/src/Modules/Reporting/AjaxHandler.php +2 -1
  160. src/lib/src/Modules/Reporting/Lib/ReportingController.php +4 -6
  161. src/lib/src/Modules/Reporting/Lib/Reports/CreateReportVO.php +13 -15
  162. src/lib/src/Modules/Reporting/Options.php +1 -1
  163. src/lib/src/Modules/SecurityAdmin/AjaxHandler.php +9 -14
  164. src/lib/src/Modules/SecurityAdmin/Insights/OverviewCards.php +5 -5
  165. src/lib/src/Modules/SecurityAdmin/Lib/{Actions → SecurityAdmin/Ops}/RemoveSecAdmin.php +3 -3
  166. src/lib/src/Modules/SecurityAdmin/Lib/{Actions → SecurityAdmin/Ops}/SetSecAdminPin.php +1 -1
  167. src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Ops/ToggleSecAdminStatus.php +50 -0
  168. src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Ops/VerifyPinRequest.php +33 -0
  169. src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/Base.php +12 -0
  170. src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/BaseCapabilitiesRestrict.php +54 -0
  171. src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/Plugins.php +44 -0
  172. src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/Posts.php +38 -0
  173. src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/Themes.php +18 -0
  174. src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/Users.php +176 -0
  175. src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/WpOptions.php +48 -0
  176. src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/SecurityAdminController.php +185 -0
  177. src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/VerifySecurityAdminList.php +39 -0
  178. src/lib/src/Modules/SecurityAdmin/Lib/WhiteLabel/ApplyLabels.php +15 -9
  179. src/lib/src/Modules/SecurityAdmin/ModCon.php +150 -202
  180. src/lib/src/Modules/SecurityAdmin/Options.php +13 -2
  181. src/lib/src/Modules/SecurityAdmin/Processor.php +30 -284
  182. src/lib/src/Modules/SecurityAdmin/Strings.php +2 -2
  183. src/lib/src/Modules/SecurityAdmin/UI.php +2 -2
  184. src/lib/src/Modules/SecurityAdmin/WpCli/Pin.php +3 -3
  185. src/lib/src/Modules/Sessions/ModCon.php +1 -2
  186. src/lib/src/Modules/Traffic/UI.php +0 -10
  187. src/lib/src/Modules/UserManagement/Lib/Registration/EmailValidate.php +4 -4
  188. src/lib/src/Modules/UserManagement/UI.php +0 -16
  189. src/lib/src/Scans/Base/Table/BaseEntryFormatter.php +8 -14
  190. src/lib/src/Scans/Base/Table/BaseFileEntryFormatter.php +19 -22
  191. src/lib/src/Scans/Mal/Table/EntryFormatter.php +19 -23
  192. src/lib/src/Scans/Ptg/Table/EntryFormatter.php +60 -66
  193. src/lib/src/Scans/Ufc/BuildScanAction.php +7 -7
  194. src/lib/src/Scans/Ufc/FileScanner.php +15 -23
  195. src/lib/src/Scans/Ufc/Table/EntryFormatter.php +6 -9
  196. src/lib/src/Scans/Wcf/Table/EntryFormatter.php +20 -23
  197. src/lib/src/Scans/Wpv/WpVulnDb/WpVulnVO.php +0 -8
  198. src/lib/src/Tables/Build/BaseBuild.php +4 -10
  199. src/lib/src/Tables/Build/ScanAggregate.php +27 -30
  200. src/lib/src/Tables/Build/ScanBase.php +12 -15
  201. src/lib/src/Tables/Render/WpListTable/ScanAggregate.php +11 -11
  202. src/lib/src/Tables/Render/WpListTable/ScanBase.php +6 -6
  203. src/lib/src/Tables/Render/WpListTable/ScanMal.php +9 -9
  204. src/lib/src/Tables/Render/WpListTable/ScanPtg.php +5 -5
  205. src/lib/src/Tables/Render/WpListTable/ScanUfc.php +7 -7
  206. src/lib/src/Tables/Render/WpListTable/ScanWcf.php +7 -7
  207. src/lib/src/Utilities/Nonce/Handler.php +26 -0
  208. src/lib/vendor/composer/autoload_classmap.php +26 -3
  209. src/lib/vendor/composer/autoload_static.php +26 -3
  210. src/lib/vendor/fernleafsystems/wordpress-services/src/Core/Request.php +9 -33
  211. src/wizards/base.php +3 -9
  212. src/wizards/base_wpsf.php +13 -16
  213. src/wizards/plugin.php +15 -16
  214. templates/php/snippets/plugin-deactivate-survey.php +0 -14
  215. templates/twig/components/events/stats/stat_box.twig +8 -0
  216. templates/twig/components/events/stats/stats_collection.twig +10 -0
  217. templates/twig/components/options_form/main.twig +21 -12
  218. templates/twig/components/search/dialog.twig +22 -0
  219. templates/twig/components/search/options.twig +21 -0
  220. templates/twig/components/security_admin/login_box.twig +68 -0
  221. templates/twig/email/lp_2fa_email_code.twig +2 -0
  222. templates/twig/pages/block/blocklist_die.twig +5 -6
  223. templates/twig/snippets/select_search_options.twig +0 -21
  224. templates/twig/wizard/slides/common/security_admin_verify.twig +1 -1
  225. templates/twig/wizard/slides/welcome/admin_access_restriction.twig +1 -1
  226. templates/twig/wpadmin_pages/base.twig +25 -1
  227. templates/twig/wpadmin_pages/components/page/nav_sidebar.twig +56 -0
  228. templates/twig/wpadmin_pages/insights/audit/audit_table.twig +61 -75
  229. templates/twig/wpadmin_pages/insights/base.twig +3 -27
  230. templates/twig/wpadmin_pages/insights/dashboard/card_settings.twig +1 -1
  231. templates/twig/wpadmin_pages/insights/docs/index.twig +1 -0
  232. templates/twig/wpadmin_pages/insights/overview/cards/shuffle.twig +7 -0
  233. templates/twig/wpadmin_pages/insights/scans/index.twig +0 -10
  234. templates/twig/wpadmin_pages/insights/scans/results/index.twig +10 -0
  235. templates/twig/wpadmin_pages/insights/scans/{realtime → results/realtime}/file_locker/file_diff.twig +7 -2
  236. templates/twig/wpadmin_pages/insights/scans/{realtime → results/realtime}/file_locker/index.twig +6 -5
  237. templates/twig/wpadmin_pages/insights/scans/results/{aggregate.twig → results/aggregate.twig} +0 -0
  238. templates/twig/wpadmin_pages/insights/scans/results/{apc.twig → results/apc.twig} +2 -2
  239. templates/twig/wpadmin_pages/insights/scans/results/{common_disabled.twig → results/common_disabled.twig} +0 -0
  240. templates/twig/wpadmin_pages/insights/scans/results/{common_unavailable.twig → results/common_unavailable.twig} +0 -0
  241. templates/twig/wpadmin_pages/insights/scans/results/{mal.twig → results/mal.twig} +2 -2
  242. templates/twig/wpadmin_pages/insights/scans/results/{ptg.twig → results/ptg.twig} +3 -3
  243. templates/twig/wpadmin_pages/insights/scans/results/{ptg_table.twig → results/ptg_table.twig} +0 -0
  244. templates/twig/wpadmin_pages/insights/scans/results/{ufc.twig → results/ufc.twig} +0 -0
  245. templates/twig/wpadmin_pages/insights/scans/results/{wcf.twig → results/wcf.twig} +16 -2
  246. templates/twig/wpadmin_pages/insights/scans/results/{wpv.twig → results/wpv.twig} +2 -2
  247. templates/twig/wpadmin_pages/insights/scans/{scan_results.twig → results/scan_results.twig} +11 -5
  248. templates/twig/wpadmin_pages/insights/scans/run/index.twig +11 -0
  249. templates/twig/wpadmin_pages/insights/scans/{scan_areas.twig → run/scan_areas.twig} +9 -7
  250. templates/twig/wpadmin_pages/insights/scans/scan_start.twig +0 -46
  251. templates/twig/wpadmin_pages/insights/settings/index.twig +0 -59
  252. templates/twig/wpadmin_pages/insights/stats/index.twig +33 -0
  253. templates/twig/wpadmin_pages/insights/traffic/traffic_table.twig +1 -1
  254. templates/twig/wpadmin_pages/security_admin/index.twig +1 -5
  255. unsupported.php +4 -4
cl.json CHANGED
@@ -1,10 +1,82 @@
1
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  "11.0": {
3
  "version": "11.0",
4
  "released_at": 1616666000,
5
  "hrefs": {
6
- "release": "https://shsec.io/shieldrelease1100",
7
- "upgrade": "https://shsec.io/shieldupgradeguide1100"
8
  },
9
  "href": "https://shsec.io/",
10
  "title": "All-New Shield AntiBot Detection Engine",
1
  {
2
+ "11.1": {
3
+ "version": "11.1",
4
+ "released_at": 1616666000,
5
+ "hrefs": {
6
+ "release": "https://shsec.io/shieldrelease111",
7
+ "upgrade": "https://shsec.io/shieldupgradeguide111"
8
+ },
9
+ "href": "https://shsec.io/",
10
+ "title": "UI Cleanup and Enhancement",
11
+ "description": [
12
+ "With Shield being such a large plugin, it's been a challenge to get a UI that everyone is happy with.",
13
+ "This release aims to improve the UI and make it easier for everyone to get their security task done as efficiently as possible."
14
+ ],
15
+ "items": [
16
+ {
17
+ "type": "new",
18
+ "pro_only": false,
19
+ "title": "Improved Dashboard UI and Navigation",
20
+ "description": [
21
+ "Detecting bad bots on your WordPress sites is a huge challenge, but it's notoriously difficult to do this.",
22
+ "We have developed an exclusive system for the detection of bad bots and the option to block requests from them."
23
+ ],
24
+ "href": "https://shsec.io/jb"
25
+ },
26
+ {
27
+ "type": "new",
28
+ "title": "A new Quick Stats screen is available to see the activity of Shield over time.",
29
+ "description": [
30
+ "The implementation is currently basic, but it forms the foundation of future development and offers users the option to offer suggestions."
31
+ ]
32
+ },
33
+ {
34
+ "type": "improved",
35
+ "title": "Code overhaul for Security Admin system to improve reliability and fix various bugs.",
36
+ "description": []
37
+ },
38
+ {
39
+ "type": "improved",
40
+ "title": "Automatic User Unblock now makes use of Shield's AntiBot Detection Engine.",
41
+ "description": []
42
+ },
43
+ {
44
+ "type": "improved",
45
+ "title": "File Locker will better handle the scenario where a site is moved/migrated.",
46
+ "description": [
47
+ "File Locker for wp-config.php files will also better detect when this file is placed 1 directory higher than the site."
48
+ ]
49
+ },
50
+ {
51
+ "type": "improved",
52
+ "title": "White Label settings that are empty aren't applied and defaults remain.",
53
+ "description": []
54
+ },
55
+ {
56
+ "type": "fixed",
57
+ "title": "Statistics in reporting emails were under-reporting the full stats.",
58
+ "description": []
59
+ },
60
+ {
61
+ "type": "fixed",
62
+ "title": "Audit Trail didn't capture all upgrades when upgrading plugins/themes in-bulk.",
63
+ "description": [
64
+ "The Audit Trial would only capture 1 upgrade when a bulk upgrade was performed."
65
+ ]
66
+ },
67
+ {
68
+ "type": "fixed",
69
+ "title": "Exclusions for unrecognised file scanner weren't stored correctly in the case of regular expressions.",
70
+ "description": []
71
+ }
72
+ ]
73
+ },
74
  "11.0": {
75
  "version": "11.0",
76
  "released_at": 1616666000,
77
  "hrefs": {
78
+ "release": "https://shsec.io/shieldrelease110",
79
+ "upgrade": "https://shsec.io/shieldupgradeguide110"
80
  },
81
  "href": "https://shsec.io/",
82
  "title": "All-New Shield AntiBot Detection Engine",
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: 11.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: 11.1.0
7
  * Text Domain: wp-simple-firewall
8
  * Domain Path: /languages
9
  * Author: Shield Security
plugin-spec.php CHANGED
@@ -1,8 +1,8 @@
1
  {
2
  "properties": {
3
- "version": "11.0.3",
4
- "release_timestamp": 1616776360,
5
- "build": "202103.2601",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
  "human_name": "Shield Security",
@@ -52,14 +52,16 @@
52
  "select2",
53
  "plugin",
54
  "featherlight",
55
- "introjs"
 
56
  ],
57
  "js": [
58
  "select2",
59
  "plugin",
60
  "featherlight",
61
  "jquery.fileDownload",
62
- "shield/tours"
 
63
  ]
64
  },
65
  "frontend": {
@@ -83,6 +85,12 @@
83
  "bootstrap"
84
  ]
85
  },
 
 
 
 
 
 
86
  "global-plugin": {},
87
  "plugin": {
88
  "deps": [
@@ -112,7 +120,8 @@
112
  "deps": [
113
  "plugin"
114
  ]
115
- }
 
116
  },
117
  "js": {
118
  "bootstrap": {
@@ -133,6 +142,12 @@
133
  "bootstrap"
134
  ]
135
  },
 
 
 
 
 
 
136
  "global-plugin": {
137
  "deps": [
138
  "wp-jquery"
@@ -142,6 +157,7 @@
142
  "deps": [
143
  "bootstrap",
144
  "global-plugin",
 
145
  "base64.min",
146
  "lz-string.min"
147
  ]
@@ -197,6 +213,12 @@
197
  "wp-jquery"
198
  ]
199
  },
 
 
 
 
 
 
200
  "shield/tables": {
201
  "deps": [
202
  "plugin"
@@ -226,7 +248,7 @@
226
  "plugin"
227
  ]
228
  },
229
- "shield/mainwp-extension": {
230
  "deps": [
231
  "wp-jquery"
232
  ]
@@ -304,7 +326,7 @@
304
  {
305
  "name": "Security Dashboard",
306
  "title": "Go To Security Dashboard",
307
- "href": "getPluginUrl_AdminMainPage",
308
  "target": "_top",
309
  "show": "always"
310
  },
1
  {
2
  "properties": {
3
+ "version": "11.1.0",
4
+ "release_timestamp": 1617870687,
5
+ "build": "202104.0801",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
  "human_name": "Shield Security",
52
  "select2",
53
  "plugin",
54
  "featherlight",
55
+ "introjs",
56
+ "bootstrap-select"
57
  ],
58
  "js": [
59
  "select2",
60
  "plugin",
61
  "featherlight",
62
  "jquery.fileDownload",
63
+ "shield/tours",
64
+ "bootstrap-select"
65
  ]
66
  },
67
  "frontend": {
85
  "bootstrap"
86
  ]
87
  },
88
+ "bootstrap-select": {
89
+ "url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.18/css/bootstrap-select.min.css",
90
+ "deps": [
91
+ "bootstrap"
92
+ ]
93
+ },
94
  "global-plugin": {},
95
  "plugin": {
96
  "deps": [
120
  "deps": [
121
  "plugin"
122
  ]
123
+ },
124
+ "shield/mainwp": {}
125
  },
126
  "js": {
127
  "bootstrap": {
142
  "bootstrap"
143
  ]
144
  },
145
+ "bootstrap-select": {
146
+ "url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.18/js/bootstrap-select.min.js",
147
+ "deps": [
148
+ "bootstrap"
149
+ ]
150
+ },
151
  "global-plugin": {
152
  "deps": [
153
  "wp-jquery"
157
  "deps": [
158
  "bootstrap",
159
  "global-plugin",
160
+ "shield/navigation",
161
  "base64.min",
162
  "lz-string.min"
163
  ]
213
  "wp-jquery"
214
  ]
215
  },
216
+ "shield/navigation": {},
217
+ "shield/secadmin": {
218
+ "deps": [
219
+ "wp-jquery"
220
+ ]
221
+ },
222
  "shield/tables": {
223
  "deps": [
224
  "plugin"
248
  "plugin"
249
  ]
250
  },
251
+ "shield/mainwp": {
252
  "deps": [
253
  "wp-jquery"
254
  ]
326
  {
327
  "name": "Security Dashboard",
328
  "title": "Go To Security Dashboard",
329
+ "href": "getPluginUrl_DashboardHome",
330
  "target": "_top",
331
  "show": "always"
332
  },
readme.txt CHANGED
@@ -8,7 +8,7 @@ Requires at least: 3.5.2
8
  Requires PHP: 7.0
9
  Recommended PHP: 7.4
10
  Tested up to: 5.7
11
- Stable tag: 11.0.3
12
  Security against hackers and brute force bots with firewall, login security hiding and hardening, Antispam, Audit Trail, Live Traffic, and much more...
13
 
14
  == Description ==
8
  Requires PHP: 7.0
9
  Recommended PHP: 7.4
10
  Tested up to: 5.7
11
+ Stable tag: 11.1.0
12
  Security against hackers and brute force bots with firewall, login security hiding and hardening, Antispam, Audit Trail, Live Traffic, and much more...
13
 
14
  == Description ==
resources/css/plugin.css CHANGED
@@ -151,17 +151,6 @@ p.code-description {
151
  .bootstrap-wpadmin .form-horizontal .form-actions {
152
  padding-left: 200px;
153
  }
154
- /** Section summaries **/
155
- a.section-help-video {
156
- text-decoration: none;
157
- margin: 0 12px 0 0;
158
- }
159
- a.section-help-video > span {
160
- font-size: 28px;
161
- color: #008000;
162
- margin-top: -2px;
163
- }
164
- /** End-Section summaries **/
165
  .wrap .icon32 {
166
  width: 32px;
167
  }
@@ -1052,7 +1041,7 @@ input[type=checkbox].form-check-input {
1052
  margin-right: 5px;
1053
  }
1054
  /** copied from bootstrap to override WP admin styles */
1055
- .content-options {
1056
  font-size: 14px;
1057
  padding-top: 10px;
1058
  }
@@ -1092,31 +1081,26 @@ input[type=checkbox].form-check-input {
1092
  font-style: italic;
1093
  font-size: 12px;
1094
  }
1095
- .content-options .tab-content {
1096
  border-top: 0 none;
1097
  padding-top: 14px;
1098
  }
1099
- .content-options .form-group.row {
1100
  /*margin-bottom: 20px;*/
1101
  padding: 15px 0 25px;
1102
  border-bottom: 1px dashed rgba(0, 0, 0, 0.08);
1103
  }
1104
- .content-options .option-description {
1105
  border-left: 1px solid rgba(0, 0, 0, 0.1);
1106
  }
1107
- .content-options .option-description p {
1108
  margin-bottom: 5px;
1109
  }
1110
- .content-options .option_label_name {
1111
  position: relative;
1112
  /*display: block;*/
1113
  }
1114
- .content-options .option_link_info {
1115
- /*position: absolute;*/
1116
- /*right: -18px;*/
1117
- /*top: -5px;*/
1118
- }
1119
- .content-options .option_link_info > .dashicons {
1120
  font-size: 16px;
1121
  text-decoration: none;
1122
  width: 1px;
@@ -1530,6 +1514,11 @@ a.card_help {
1530
  bottom: 0;
1531
  padding-left: 160px;
1532
  transition: 0.5s ease;
 
 
 
 
 
1533
  }
1534
  body.folded #FooterBannerGoPro {
1535
  padding-left: 40px;
@@ -1551,8 +1540,52 @@ body.folded #FooterBannerGoPro {
1551
  }
1552
  }
1553
  #odp-PageFoot {
1554
- height: 100px;
1555
  }
1556
  .select2-selection {
1557
  font-weight: normal;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1558
  }
151
  .bootstrap-wpadmin .form-horizontal .form-actions {
152
  padding-left: 200px;
153
  }
 
 
 
 
 
 
 
 
 
 
 
154
  .wrap .icon32 {
155
  width: 32px;
156
  }
1041
  margin-right: 5px;
1042
  }
1043
  /** copied from bootstrap to override WP admin styles */
1044
+ .icwpOptionsForm {
1045
  font-size: 14px;
1046
  padding-top: 10px;
1047
  }
1081
  font-style: italic;
1082
  font-size: 12px;
1083
  }
1084
+ .icwpOptionsForm .tab-content {
1085
  border-top: 0 none;
1086
  padding-top: 14px;
1087
  }
1088
+ .icwpOptionsForm .form-group.row {
1089
  /*margin-bottom: 20px;*/
1090
  padding: 15px 0 25px;
1091
  border-bottom: 1px dashed rgba(0, 0, 0, 0.08);
1092
  }
1093
+ .icwpOptionsForm .option-description {
1094
  border-left: 1px solid rgba(0, 0, 0, 0.1);
1095
  }
1096
+ .icwpOptionsForm .option-description p {
1097
  margin-bottom: 5px;
1098
  }
1099
+ .icwpOptionsForm .option_label_name {
1100
  position: relative;
1101
  /*display: block;*/
1102
  }
1103
+ .icwpOptionsForm .option_link_info > .dashicons {
 
 
 
 
 
1104
  font-size: 16px;
1105
  text-decoration: none;
1106
  width: 1px;
1514
  bottom: 0;
1515
  padding-left: 160px;
1516
  transition: 0.5s ease;
1517
+ z-index: 1;
1518
+ }
1519
+ #adminmenuback {
1520
+ /** To account for the promo bar at the bottom **/
1521
+ z-index: 2;
1522
  }
1523
  body.folded #FooterBannerGoPro {
1524
  padding-left: 40px;
1540
  }
1541
  }
1542
  #odp-PageFoot {
1543
+ height: 12px;
1544
  }
1545
  .select2-selection {
1546
  font-weight: normal;
1547
+ }
1548
+ #odp-PageHead {
1549
+ }
1550
+ #apto-PageMainSide {
1551
+ background-color: rgba(85, 178, 87, 0.06);
1552
+ border-color: rgba(85, 178, 87, 0.2);
1553
+ border-width: 1px 1px 1px 0;
1554
+ border-style: solid;
1555
+ }
1556
+ #NavSideBar a.nav-link:hover {
1557
+ color: black;
1558
+ }
1559
+ #NavSideBar a.nav-link.active {
1560
+ font-weight: bolder;
1561
+ }
1562
+ .primary_sub_menu {
1563
+ }
1564
+
1565
+ #SearchDialog .modal-body {
1566
+ min-height: 450px;
1567
+ }
1568
+ #SearchDialog .bootstrap-select {
1569
+ width: 100%;
1570
+ }
1571
+ #SearchDialog .bootstrap-select > .dropdown-toggle.bs-placeholder {
1572
+ color: #333333;
1573
+ }
1574
+
1575
+ #StatsNav {
1576
+ background-color: #f1f1f1;
1577
+ display: inline-block;
1578
+ position: sticky;
1579
+ top: 88px;
1580
+ z-index: 5;
1581
+ }
1582
+ .stat_box .card-header {
1583
+ text-align: center;
1584
+ }
1585
+ .stat_box .card-body {
1586
+ background-color: #c3c3d6;
1587
+ }
1588
+ .stat_box .stat_count {
1589
+ font-size: 3rem;
1590
+ line-height: 3.5rem;
1591
  }
resources/css/{mainwp-extension.css → shield/mainwp.css} RENAMED
File without changes
resources/images/bootstrap/arrow-down-up.svg CHANGED
@@ -1,3 +1,3 @@
1
- <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-arrow-down-up" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
2
  <path fill-rule="evenodd" d="M11.5 15a.5.5 0 0 0 .5-.5V2.707l3.146 3.147a.5.5 0 0 0 .708-.708l-4-4a.5.5 0 0 0-.708 0l-4 4a.5.5 0 1 0 .708.708L11 2.707V14.5a.5.5 0 0 0 .5.5zm-7-14a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L4 13.293V1.5a.5.5 0 0 1 .5-.5z"/>
3
  </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-down-up" viewBox="0 0 16 16">
2
  <path fill-rule="evenodd" d="M11.5 15a.5.5 0 0 0 .5-.5V2.707l3.146 3.147a.5.5 0 0 0 .708-.708l-4-4a.5.5 0 0 0-.708 0l-4 4a.5.5 0 1 0 .708.708L11 2.707V14.5a.5.5 0 0 0 .5.5zm-7-14a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L4 13.293V1.5a.5.5 0 0 1 .5-.5z"/>
3
  </svg>
resources/images/bootstrap/award.svg CHANGED
@@ -1,4 +1,4 @@
1
- <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-award" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
2
- <path fill-rule="evenodd" d="M9.669.864L8 0 6.331.864l-1.858.282-.842 1.68-1.337 1.32L2.6 6l-.306 1.854 1.337 1.32.842 1.68 1.858.282L8 12l1.669-.864 1.858-.282.842-1.68 1.337-1.32L13.4 6l.306-1.854-1.337-1.32-.842-1.68L9.669.864zm1.196 1.193l-1.51-.229L8 1.126l-1.355.702-1.51.229-.684 1.365-1.086 1.072L3.614 6l-.25 1.506 1.087 1.072.684 1.365 1.51.229L8 10.874l1.356-.702 1.509-.229.684-1.365 1.086-1.072L12.387 6l.248-1.506-1.086-1.072-.684-1.365z"/>
3
  <path d="M4 11.794V16l4-1 4 1v-4.206l-2.018.306L8 13.126 6.018 12.1 4 11.794z"/>
4
  </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-award" viewBox="0 0 16 16">
2
+ <path d="M9.669.864 8 0 6.331.864l-1.858.282-.842 1.68-1.337 1.32L2.6 6l-.306 1.854 1.337 1.32.842 1.68 1.858.282L8 12l1.669-.864 1.858-.282.842-1.68 1.337-1.32L13.4 6l.306-1.854-1.337-1.32-.842-1.68L9.669.864zm1.196 1.193.684 1.365 1.086 1.072L12.387 6l.248 1.506-1.086 1.072-.684 1.365-1.51.229L8 10.874l-1.355-.702-1.51-.229-.684-1.365-1.086-1.072L3.614 6l-.25-1.506 1.087-1.072.684-1.365 1.51-.229L8 1.126l1.356.702 1.509.229z"/>
3
  <path d="M4 11.794V16l4-1 4 1v-4.206l-2.018.306L8 13.126 6.018 12.1 4 11.794z"/>
4
  </svg>
resources/images/bootstrap/binoculars.svg CHANGED
@@ -1,3 +1,3 @@
1
- <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-binoculars" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
2
- <path fill-rule="evenodd" d="M3 2.5A1.5 1.5 0 0 1 4.5 1h1A1.5 1.5 0 0 1 7 2.5V5h2V2.5A1.5 1.5 0 0 1 10.5 1h1A1.5 1.5 0 0 1 13 2.5v2.382a.5.5 0 0 0 .276.447l.895.447A1.5 1.5 0 0 1 15 7.118V14.5a1.5 1.5 0 0 1-1.5 1.5h-3A1.5 1.5 0 0 1 9 14.5v-3a.5.5 0 0 1 .146-.354l.854-.853V9.5a.5.5 0 0 0-.5-.5h-3a.5.5 0 0 0-.5.5v.793l.854.853A.5.5 0 0 1 7 11.5v3A1.5 1.5 0 0 1 5.5 16h-3A1.5 1.5 0 0 1 1 14.5V7.118a1.5 1.5 0 0 1 .83-1.342l.894-.447A.5.5 0 0 0 3 4.882V2.5zM4.5 2a.5.5 0 0 0-.5.5V3h2v-.5a.5.5 0 0 0-.5-.5h-1zM6 4H4v.882a1.5 1.5 0 0 1-.83 1.342l-.894.447A.5.5 0 0 0 2 7.118V13h4v-1.293l-.854-.853A.5.5 0 0 1 5 10.5v-1A1.5 1.5 0 0 1 6.5 8h3A1.5 1.5 0 0 1 11 9.5v1a.5.5 0 0 1-.146.354l-.854.853V13h4V7.118a.5.5 0 0 0-.276-.447l-.895-.447A1.5 1.5 0 0 1 12 4.882V4h-2v1.5a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5V4zm4-1h2v-.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5V3zm4 11h-4v.5a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5V14zm-8 0H2v.5a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5V14z"/>
3
  </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-binoculars" viewBox="0 0 16 16">
2
+ <path d="M3 2.5A1.5 1.5 0 0 1 4.5 1h1A1.5 1.5 0 0 1 7 2.5V5h2V2.5A1.5 1.5 0 0 1 10.5 1h1A1.5 1.5 0 0 1 13 2.5v2.382a.5.5 0 0 0 .276.447l.895.447A1.5 1.5 0 0 1 15 7.118V14.5a1.5 1.5 0 0 1-1.5 1.5h-3A1.5 1.5 0 0 1 9 14.5v-3a.5.5 0 0 1 .146-.354l.854-.853V9.5a.5.5 0 0 0-.5-.5h-3a.5.5 0 0 0-.5.5v.793l.854.853A.5.5 0 0 1 7 11.5v3A1.5 1.5 0 0 1 5.5 16h-3A1.5 1.5 0 0 1 1 14.5V7.118a1.5 1.5 0 0 1 .83-1.342l.894-.447A.5.5 0 0 0 3 4.882V2.5zM4.5 2a.5.5 0 0 0-.5.5V3h2v-.5a.5.5 0 0 0-.5-.5h-1zM6 4H4v.882a1.5 1.5 0 0 1-.83 1.342l-.894.447A.5.5 0 0 0 2 7.118V13h4v-1.293l-.854-.853A.5.5 0 0 1 5 10.5v-1A1.5 1.5 0 0 1 6.5 8h3A1.5 1.5 0 0 1 11 9.5v1a.5.5 0 0 1-.146.354l-.854.853V13h4V7.118a.5.5 0 0 0-.276-.447l-.895-.447A1.5 1.5 0 0 1 12 4.882V4h-2v1.5a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5V4zm4-1h2v-.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5V3zm4 11h-4v.5a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5V14zm-8 0H2v.5a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5V14z"/>
3
  </svg>
resources/images/bootstrap/book-half.svg CHANGED
@@ -1,3 +1,3 @@
1
- <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-book-half" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
2
- <path fill-rule="evenodd" d="M8.5 2.687v9.746c.935-.53 2.12-.603 3.213-.493 1.18.12 2.37.461 3.287.811V2.828c-.885-.37-2.154-.769-3.388-.893-1.33-.134-2.458.063-3.112.752zM8 1.783C7.015.936 5.587.81 4.287.94c-1.514.153-3.042.672-3.994 1.105A.5.5 0 0 0 0 2.5v11a.5.5 0 0 0 .707.455c.882-.4 2.303-.881 3.68-1.02 1.409-.142 2.59.087 3.223.877a.5.5 0 0 0 .78 0c.633-.79 1.814-1.019 3.222-.877 1.378.139 2.8.62 3.681 1.02A.5.5 0 0 0 16 13.5v-11a.5.5 0 0 0-.293-.455c-.952-.433-2.48-.952-3.994-1.105C10.413.809 8.985.936 8 1.783z"/>
3
  </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-book-half" viewBox="0 0 16 16">
2
+ <path d="M8.5 2.687c.654-.689 1.782-.886 3.112-.752 1.234.124 2.503.523 3.388.893v9.923c-.918-.35-2.107-.692-3.287-.81-1.094-.111-2.278-.039-3.213.492V2.687zM8 1.783C7.015.936 5.587.81 4.287.94c-1.514.153-3.042.672-3.994 1.105A.5.5 0 0 0 0 2.5v11a.5.5 0 0 0 .707.455c.882-.4 2.303-.881 3.68-1.02 1.409-.142 2.59.087 3.223.877a.5.5 0 0 0 .78 0c.633-.79 1.814-1.019 3.222-.877 1.378.139 2.8.62 3.681 1.02A.5.5 0 0 0 16 13.5v-11a.5.5 0 0 0-.293-.455c-.952-.433-2.48-.952-3.994-1.105C10.413.809 8.985.936 8 1.783z"/>
3
  </svg>
resources/images/bootstrap/bug.svg CHANGED
@@ -1,3 +1,3 @@
1
- <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-bug" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
2
- <path fill-rule="evenodd" d="M4.355.522a.5.5 0 0 1 .623.333l.291.956A4.979 4.979 0 0 1 8 1c1.007 0 1.946.298 2.731.811l.29-.956a.5.5 0 1 1 .957.29l-.41 1.352A4.985 4.985 0 0 1 13 6h.5a.5.5 0 0 0 .5-.5V5a.5.5 0 0 1 1 0v.5A1.5 1.5 0 0 1 13.5 7H13v1h1.5a.5.5 0 0 1 0 1H13v1h.5a1.5 1.5 0 0 1 1.5 1.5v.5a.5.5 0 1 1-1 0v-.5a.5.5 0 0 0-.5-.5H13a5 5 0 0 1-10 0h-.5a.5.5 0 0 0-.5.5v.5a.5.5 0 1 1-1 0v-.5A1.5 1.5 0 0 1 2.5 10H3V9H1.5a.5.5 0 0 1 0-1H3V7h-.5A1.5 1.5 0 0 1 1 5.5V5a.5.5 0 0 1 1 0v.5a.5.5 0 0 0 .5.5H3c0-1.364.547-2.601 1.432-3.503l-.41-1.352a.5.5 0 0 1 .333-.623zM4 7v4a4 4 0 0 0 3.5 3.97V7H4zm4.5 0v7.97A4 4 0 0 0 12 11V7H8.5zM12 6H4a3.99 3.99 0 0 1 1.333-2.982A3.983 3.983 0 0 1 8 2c1.025 0 1.959.385 2.666 1.018A3.989 3.989 0 0 1 12 6z"/>
3
  </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-bug" viewBox="0 0 16 16">
2
+ <path d="M4.355.522a.5.5 0 0 1 .623.333l.291.956A4.979 4.979 0 0 1 8 1c1.007 0 1.946.298 2.731.811l.29-.956a.5.5 0 1 1 .957.29l-.41 1.352A4.985 4.985 0 0 1 13 6h.5a.5.5 0 0 0 .5-.5V5a.5.5 0 0 1 1 0v.5A1.5 1.5 0 0 1 13.5 7H13v1h1.5a.5.5 0 0 1 0 1H13v1h.5a1.5 1.5 0 0 1 1.5 1.5v.5a.5.5 0 1 1-1 0v-.5a.5.5 0 0 0-.5-.5H13a5 5 0 0 1-10 0h-.5a.5.5 0 0 0-.5.5v.5a.5.5 0 1 1-1 0v-.5A1.5 1.5 0 0 1 2.5 10H3V9H1.5a.5.5 0 0 1 0-1H3V7h-.5A1.5 1.5 0 0 1 1 5.5V5a.5.5 0 0 1 1 0v.5a.5.5 0 0 0 .5.5H3c0-1.364.547-2.601 1.432-3.503l-.41-1.352a.5.5 0 0 1 .333-.623zM4 7v4a4 4 0 0 0 3.5 3.97V7H4zm4.5 0v7.97A4 4 0 0 0 12 11V7H8.5zM12 6a3.989 3.989 0 0 0-1.334-2.982A3.983 3.983 0 0 0 8 2a3.983 3.983 0 0 0-2.667 1.018A3.989 3.989 0 0 0 4 6h8z"/>
3
  </svg>
resources/images/bootstrap/chat-right-dots-fill.svg CHANGED
@@ -1,3 +1,3 @@
1
- <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-chat-right-dots-fill" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
2
- <path fill-rule="evenodd" d="M16 2a2 2 0 0 0-2-2H2a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h9.586a1 1 0 0 1 .707.293l2.853 2.853a.5.5 0 0 0 .854-.353V2zM5 6a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm4 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 1a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/>
3
  </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chat-right-dots-fill" viewBox="0 0 16 16">
2
+ <path d="M16 2a2 2 0 0 0-2-2H2a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h9.586a1 1 0 0 1 .707.293l2.853 2.853a.5.5 0 0 0 .854-.353V2zM5 6a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm4 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm3 1a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/>
3
  </svg>
resources/images/bootstrap/diagram-3.svg CHANGED
@@ -1,3 +1,3 @@
1
- <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-diagram-3" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
2
  <path fill-rule="evenodd" d="M6 3.5A1.5 1.5 0 0 1 7.5 2h1A1.5 1.5 0 0 1 10 3.5v1A1.5 1.5 0 0 1 8.5 6v1H14a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-1 0V8h-5v.5a.5.5 0 0 1-1 0V8h-5v.5a.5.5 0 0 1-1 0v-1A.5.5 0 0 1 2 7h5.5V6A1.5 1.5 0 0 1 6 4.5v-1zM8.5 5a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1zM0 11.5A1.5 1.5 0 0 1 1.5 10h1A1.5 1.5 0 0 1 4 11.5v1A1.5 1.5 0 0 1 2.5 14h-1A1.5 1.5 0 0 1 0 12.5v-1zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1zm4.5.5A1.5 1.5 0 0 1 7.5 10h1a1.5 1.5 0 0 1 1.5 1.5v1A1.5 1.5 0 0 1 8.5 14h-1A1.5 1.5 0 0 1 6 12.5v-1zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1zm4.5.5a1.5 1.5 0 0 1 1.5-1.5h1a1.5 1.5 0 0 1 1.5 1.5v1a1.5 1.5 0 0 1-1.5 1.5h-1a1.5 1.5 0 0 1-1.5-1.5v-1zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1z"/>
3
  </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-diagram-3" viewBox="0 0 16 16">
2
  <path fill-rule="evenodd" d="M6 3.5A1.5 1.5 0 0 1 7.5 2h1A1.5 1.5 0 0 1 10 3.5v1A1.5 1.5 0 0 1 8.5 6v1H14a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-1 0V8h-5v.5a.5.5 0 0 1-1 0V8h-5v.5a.5.5 0 0 1-1 0v-1A.5.5 0 0 1 2 7h5.5V6A1.5 1.5 0 0 1 6 4.5v-1zM8.5 5a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1zM0 11.5A1.5 1.5 0 0 1 1.5 10h1A1.5 1.5 0 0 1 4 11.5v1A1.5 1.5 0 0 1 2.5 14h-1A1.5 1.5 0 0 1 0 12.5v-1zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1zm4.5.5A1.5 1.5 0 0 1 7.5 10h1a1.5 1.5 0 0 1 1.5 1.5v1A1.5 1.5 0 0 1 8.5 14h-1A1.5 1.5 0 0 1 6 12.5v-1zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1zm4.5.5a1.5 1.5 0 0 1 1.5-1.5h1a1.5 1.5 0 0 1 1.5 1.5v1a1.5 1.5 0 0 1-1.5 1.5h-1a1.5 1.5 0 0 1-1.5-1.5v-1zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1z"/>
3
  </svg>
resources/images/bootstrap/emoji-smile.svg CHANGED
@@ -1,5 +1,4 @@
1
- <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-emoji-smile" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
2
- <path fill-rule="evenodd" d="M8 15A7 7 0 1 0 8 1a7 7 0 0 0 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
3
- <path fill-rule="evenodd" d="M4.285 9.567a.5.5 0 0 1 .683.183A3.498 3.498 0 0 0 8 11.5a3.498 3.498 0 0 0 3.032-1.75.5.5 0 1 1 .866.5A4.498 4.498 0 0 1 8 12.5a4.498 4.498 0 0 1-3.898-2.25.5.5 0 0 1 .183-.683z"/>
4
- <path d="M7 6.5C7 7.328 6.552 8 6 8s-1-.672-1-1.5S5.448 5 6 5s1 .672 1 1.5zm4 0c0 .828-.448 1.5-1 1.5s-1-.672-1-1.5S9.448 5 10 5s1 .672 1 1.5z"/>
5
  </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-emoji-smile" viewBox="0 0 16 16">
2
+ <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
3
+ <path d="M4.285 9.567a.5.5 0 0 1 .683.183A3.498 3.498 0 0 0 8 11.5a3.498 3.498 0 0 0 3.032-1.75.5.5 0 1 1 .866.5A4.498 4.498 0 0 1 8 12.5a4.498 4.498 0 0 1-3.898-2.25.5.5 0 0 1 .183-.683zM7 6.5C7 7.328 6.552 8 6 8s-1-.672-1-1.5S5.448 5 6 5s1 .672 1 1.5zm4 0c0 .828-.448 1.5-1 1.5s-1-.672-1-1.5S9.448 5 10 5s1 .672 1 1.5z"/>
 
4
  </svg>
resources/images/bootstrap/graph-up.svg CHANGED
@@ -1,3 +1,3 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-graph-up" viewBox="0 0 16 16">
2
- <path fill-rule="evenodd" d="M0 0h1v15h15v1H0V0zm10 3.5a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 .5.5v4a.5.5 0 0 1-1 0V4.9l-3.613 4.417a.5.5 0 0 1-.74.037L7.06 6.767l-3.656 5.027a.5.5 0 0 1-.808-.588l4-5.5a.5.5 0 0 1 .758-.06l2.609 2.61L13.445 4H10.5a.5.5 0 0 1-.5-.5z"/>
3
  </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-graph-up" viewBox="0 0 16 16">
2
+ <path fill-rule="evenodd" d="M0 0h1v15h15v1H0V0zm10 3.5a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 .5.5v4a.5.5 0 0 1-1 0V4.9l-3.613 4.417a.5.5 0 0 1-.74.037L7.06 6.767l-3.656 5.027a.5.5 0 0 1-.808-.588l4-5.5a.5.5 0 0 1 .758-.06l2.609 2.61L13.445 4H10.5a.5.5 0 0 1-.5-.5z"/>
3
  </svg>
resources/images/bootstrap/link-45deg.svg CHANGED
@@ -1,4 +1,4 @@
1
- <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-link-45deg" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
2
- <path d="M4.715 6.542L3.343 7.914a3 3 0 1 0 4.243 4.243l1.828-1.829A3 3 0 0 0 8.586 5.5L8 6.086a1.001 1.001 0 0 0-.154.199 2 2 0 0 1 .861 3.337L6.88 11.45a2 2 0 1 1-2.83-2.83l.793-.792a4.018 4.018 0 0 1-.128-1.287z"/>
3
- <path d="M6.586 4.672A3 3 0 0 0 7.414 9.5l.775-.776a2 2 0 0 1-.896-3.346L9.12 3.55a2 2 0 0 1 2.83 2.83l-.793.792c.112.42.155.855.128 1.287l1.372-1.372a3 3 0 0 0-4.243-4.243L6.586 4.672z"/>
4
  </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-link-45deg" viewBox="0 0 16 16">
2
+ <path d="M4.715 6.542 3.343 7.914a3 3 0 1 0 4.243 4.243l1.828-1.829A3 3 0 0 0 8.586 5.5L8 6.086a1.002 1.002 0 0 0-.154.199 2 2 0 0 1 .861 3.337L6.88 11.45a2 2 0 1 1-2.83-2.83l.793-.792a4.018 4.018 0 0 1-.128-1.287z"/>
3
+ <path d="M6.586 4.672A3 3 0 0 0 7.414 9.5l.775-.776a2 2 0 0 1-.896-3.346L9.12 3.55a2 2 0 1 1 2.83 2.83l-.793.792c.112.42.155.855.128 1.287l1.372-1.372a3 3 0 1 0-4.243-4.243L6.586 4.672z"/>
4
  </svg>
resources/images/bootstrap/pencil-square.svg CHANGED
@@ -1,4 +1,4 @@
1
- <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-pencil-square" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
2
- <path d="M15.502 1.94a.5.5 0 0 1 0 .706L14.459 3.69l-2-2L13.502.646a.5.5 0 0 1 .707 0l1.293 1.293zm-1.75 2.456l-2-2L4.939 9.21a.5.5 0 0 0-.121.196l-.805 2.414a.25.25 0 0 0 .316.316l2.414-.805a.5.5 0 0 0 .196-.12l6.813-6.814z"/>
3
  <path fill-rule="evenodd" d="M1 13.5A1.5 1.5 0 0 0 2.5 15h11a1.5 1.5 0 0 0 1.5-1.5v-6a.5.5 0 0 0-1 0v6a.5.5 0 0 1-.5.5h-11a.5.5 0 0 1-.5-.5v-11a.5.5 0 0 1 .5-.5H9a.5.5 0 0 0 0-1H2.5A1.5 1.5 0 0 0 1 2.5v11z"/>
4
  </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-pencil-square" viewBox="0 0 16 16">
2
+ <path d="M15.502 1.94a.5.5 0 0 1 0 .706L14.459 3.69l-2-2L13.502.646a.5.5 0 0 1 .707 0l1.293 1.293zm-1.75 2.456-2-2L4.939 9.21a.5.5 0 0 0-.121.196l-.805 2.414a.25.25 0 0 0 .316.316l2.414-.805a.5.5 0 0 0 .196-.12l6.813-6.814z"/>
3
  <path fill-rule="evenodd" d="M1 13.5A1.5 1.5 0 0 0 2.5 15h11a1.5 1.5 0 0 0 1.5-1.5v-6a.5.5 0 0 0-1 0v6a.5.5 0 0 1-.5.5h-11a.5.5 0 0 1-.5-.5v-11a.5.5 0 0 1 .5-.5H9a.5.5 0 0 0 0-1H2.5A1.5 1.5 0 0 0 1 2.5v11z"/>
4
  </svg>
resources/images/bootstrap/people.svg CHANGED
@@ -1,3 +1,3 @@
1
- <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-people" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
2
- <path fill-rule="evenodd" d="M15 14s1 0 1-1-1-4-5-4-5 3-5 4 1 1 1 1h8zm-7.978-1h7.956a.274.274 0 0 0 .014-.002l.008-.002c-.002-.264-.167-1.03-.76-1.72C13.688 10.629 12.718 10 11 10c-1.717 0-2.687.63-3.24 1.276-.593.69-.759 1.457-.76 1.72a1.05 1.05 0 0 0 .022.004zM11 7a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm3-2a3 3 0 1 1-6 0 3 3 0 0 1 6 0zM6.936 9.28a5.88 5.88 0 0 0-1.23-.247A7.35 7.35 0 0 0 5 9c-4 0-5 3-5 4 0 .667.333 1 1 1h4.216A2.238 2.238 0 0 1 5 13c0-1.01.377-2.042 1.09-2.904.243-.294.526-.569.846-.816zM4.92 10c-1.668.02-2.615.64-3.16 1.276C1.163 11.97 1 12.739 1 13h3c0-1.045.323-2.086.92-3zM1.5 5.5a3 3 0 1 1 6 0 3 3 0 0 1-6 0zm3-2a2 2 0 1 0 0 4 2 2 0 0 0 0-4z"/>
3
  </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-people" viewBox="0 0 16 16">
2
+ <path d="M15 14s1 0 1-1-1-4-5-4-5 3-5 4 1 1 1 1h8zm-7.978-1A.261.261 0 0 1 7 12.996c.001-.264.167-1.03.76-1.72C8.312 10.629 9.282 10 11 10c1.717 0 2.687.63 3.24 1.276.593.69.758 1.457.76 1.72l-.008.002a.274.274 0 0 1-.014.002H7.022zM11 7a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm3-2a3 3 0 1 1-6 0 3 3 0 0 1 6 0zM6.936 9.28a5.88 5.88 0 0 0-1.23-.247A7.35 7.35 0 0 0 5 9c-4 0-5 3-5 4 0 .667.333 1 1 1h4.216A2.238 2.238 0 0 1 5 13c0-1.01.377-2.042 1.09-2.904.243-.294.526-.569.846-.816zM4.92 10A5.493 5.493 0 0 0 4 13H1c0-.26.164-1.03.76-1.724.545-.636 1.492-1.256 3.16-1.275zM1.5 5.5a3 3 0 1 1 6 0 3 3 0 0 1-6 0zm3-2a2 2 0 1 0 0 4 2 2 0 0 0 0-4z"/>
3
  </svg>
resources/images/bootstrap/person-badge.svg CHANGED
@@ -1,4 +1,4 @@
1
- <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-person-badge" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
2
- <path fill-rule="evenodd" d="M2 2.5A2.5 2.5 0 0 1 4.5 0h7A2.5 2.5 0 0 1 14 2.5V14a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V2.5zM4.5 1A1.5 1.5 0 0 0 3 2.5v10.795a4.2 4.2 0 0 1 .776-.492C4.608 12.387 5.937 12 8 12s3.392.387 4.224.803a4.2 4.2 0 0 1 .776.492V2.5A1.5 1.5 0 0 0 11.5 1h-7z"/>
3
- <path fill-rule="evenodd" d="M8 11a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM6 2.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5z"/>
4
  </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-person-badge" viewBox="0 0 16 16">
2
+ <path d="M6.5 2a.5.5 0 0 0 0 1h3a.5.5 0 0 0 0-1h-3zM11 8a3 3 0 1 1-6 0 3 3 0 0 1 6 0z"/>
3
+ <path d="M4.5 0A2.5 2.5 0 0 0 2 2.5V14a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V2.5A2.5 2.5 0 0 0 11.5 0h-7zM3 2.5A1.5 1.5 0 0 1 4.5 1h7A1.5 1.5 0 0 1 13 2.5v10.795a4.2 4.2 0 0 0-.776-.492C11.392 12.387 10.063 12 8 12s-3.392.387-4.224.803a4.2 4.2 0 0 0-.776.492V2.5z"/>
4
  </svg>
resources/images/bootstrap/person-lines-fill.svg CHANGED
@@ -1,3 +1,3 @@
1
- <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-person-lines-fill" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
2
- <path fill-rule="evenodd" d="M1 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H1zm5-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm7 1.5a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 0 1h-2a.5.5 0 0 1-.5-.5zm-2-3a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 0 1h-4a.5.5 0 0 1-.5-.5zm0-3a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 0 1h-4a.5.5 0 0 1-.5-.5zm2 9a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 0 1h-2a.5.5 0 0 1-.5-.5z"/>
3
  </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-person-lines-fill" viewBox="0 0 16 16">
2
+ <path d="M6 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm-5 6s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H1zM11 3.5a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 0 1h-4a.5.5 0 0 1-.5-.5zm.5 2.5a.5.5 0 0 0 0 1h4a.5.5 0 0 0 0-1h-4zm2 3a.5.5 0 0 0 0 1h2a.5.5 0 0 0 0-1h-2zm0 3a.5.5 0 0 0 0 1h2a.5.5 0 0 0 0-1h-2z"/>
3
  </svg>
resources/images/bootstrap/plug-fill.svg ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-plug-fill" viewBox="0 0 16 16">
2
+ <path d="M6 0a.5.5 0 0 1 .5.5V3h3V.5a.5.5 0 0 1 1 0V3h1a.5.5 0 0 1 .5.5v3A3.5 3.5 0 0 1 8.5 10c-.002.434-.01.845-.04 1.22-.041.514-.126 1.003-.317 1.424a2.083 2.083 0 0 1-.97 1.028C6.725 13.9 6.169 14 5.5 14c-.998 0-1.61.33-1.974.718A1.922 1.922 0 0 0 3 16H2c0-.616.232-1.367.797-1.968C3.374 13.42 4.261 13 5.5 13c.581 0 .962-.088 1.218-.219.241-.123.4-.3.514-.55.121-.266.193-.621.23-1.09.027-.34.035-.718.037-1.141A3.5 3.5 0 0 1 4 6.5v-3a.5.5 0 0 1 .5-.5h1V.5A.5.5 0 0 1 6 0z"/>
3
+ </svg>
resources/images/bootstrap/puzzle-fill.svg ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-puzzle-fill" viewBox="0 0 16 16">
2
+ <path d="M3.112 3.645A1.5 1.5 0 0 1 4.605 2H7a.5.5 0 0 1 .5.5v.382c0 .696-.497 1.182-.872 1.469a.459.459 0 0 0-.115.118.113.113 0 0 0-.012.025L6.5 4.5v.003l.003.01c.004.01.014.028.036.053a.86.86 0 0 0 .27.194C7.09 4.9 7.51 5 8 5c.492 0 .912-.1 1.19-.24a.86.86 0 0 0 .271-.194.213.213 0 0 0 .036-.054l.003-.01v-.008a.112.112 0 0 0-.012-.025.459.459 0 0 0-.115-.118c-.375-.287-.872-.773-.872-1.469V2.5A.5.5 0 0 1 9 2h2.395a1.5 1.5 0 0 1 1.493 1.645L12.645 6.5h.237c.195 0 .42-.147.675-.48.21-.274.528-.52.943-.52.568 0 .947.447 1.154.862C15.877 6.807 16 7.387 16 8s-.123 1.193-.346 1.638c-.207.415-.586.862-1.154.862-.415 0-.733-.246-.943-.52-.255-.333-.48-.48-.675-.48h-.237l.243 2.855A1.5 1.5 0 0 1 11.395 14H9a.5.5 0 0 1-.5-.5v-.382c0-.696.497-1.182.872-1.469a.459.459 0 0 0 .115-.118.113.113 0 0 0 .012-.025L9.5 11.5v-.003l-.003-.01a.214.214 0 0 0-.036-.053.859.859 0 0 0-.27-.194C8.91 11.1 8.49 11 8 11c-.491 0-.912.1-1.19.24a.859.859 0 0 0-.271.194.214.214 0 0 0-.036.054l-.003.01v.002l.001.006a.113.113 0 0 0 .012.025c.016.027.05.068.115.118.375.287.872.773.872 1.469v.382a.5.5 0 0 1-.5.5H4.605a1.5 1.5 0 0 1-1.493-1.645L3.356 9.5h-.238c-.195 0-.42.147-.675.48-.21.274-.528.52-.943.52-.568 0-.947-.447-1.154-.862C.123 9.193 0 8.613 0 8s.123-1.193.346-1.638C.553 5.947.932 5.5 1.5 5.5c.415 0 .733.246.943.52.255.333.48.48.675.48h.238l-.244-2.855z"/>
3
+ </svg>
resources/images/bootstrap/search.svg ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-search" viewBox="0 0 16 16">
2
+ <path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"/>
3
+ </svg>
resources/images/bootstrap/shield-shaded.svg CHANGED
@@ -1,4 +1,3 @@
1
- <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-shield-shaded" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
2
- <path fill-rule="evenodd" d="M5.443 1.991a60.17 60.17 0 0 0-2.725.802.454.454 0 0 0-.315.366C1.87 7.056 3.1 9.9 4.567 11.773c.736.94 1.533 1.636 2.197 2.093.333.228.626.394.857.5.116.053.21.089.282.11A.73.73 0 0 0 8 14.5c.007-.001.038-.005.097-.023.072-.022.166-.058.282-.111.23-.106.525-.272.857-.5a10.197 10.197 0 0 0 2.197-2.093C12.9 9.9 14.13 7.056 13.597 3.159a.454.454 0 0 0-.315-.366c-.626-.2-1.682-.526-2.725-.802C9.491 1.71 8.51 1.5 8 1.5c-.51 0-1.49.21-2.557.491zm-.256-.966C6.23.749 7.337.5 8 .5c.662 0 1.77.249 2.813.525a61.09 61.09 0 0 1 2.772.815c.528.168.926.623 1.003 1.184.573 4.197-.756 7.307-2.367 9.365a11.191 11.191 0 0 1-2.418 2.3 6.942 6.942 0 0 1-1.007.586c-.27.124-.558.225-.796.225s-.526-.101-.796-.225a6.908 6.908 0 0 1-1.007-.586 11.192 11.192 0 0 1-2.417-2.3C2.167 10.331.839 7.221 1.412 3.024A1.454 1.454 0 0 1 2.415 1.84a61.11 61.11 0 0 1 2.772-.815z"/>
3
- <path d="M8 2.25c.909 0 3.188.685 4.254 1.022a.94.94 0 0 1 .656.773c.814 6.424-4.13 9.452-4.91 9.452V2.25z"/>
4
  </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-shield-shaded" viewBox="0 0 16 16">
2
+ <path fill-rule="evenodd" d="M8 14.933a.615.615 0 0 0 .1-.025c.076-.023.174-.061.294-.118.24-.113.547-.29.893-.533a10.726 10.726 0 0 0 2.287-2.233c1.527-1.997 2.807-5.031 2.253-9.188a.48.48 0 0 0-.328-.39c-.651-.213-1.75-.56-2.837-.855C9.552 1.29 8.531 1.067 8 1.067v13.866zM5.072.56C6.157.265 7.31 0 8 0s1.843.265 2.928.56c1.11.3 2.229.655 2.887.87a1.54 1.54 0 0 1 1.044 1.262c.596 4.477-.787 7.795-2.465 9.99a11.775 11.775 0 0 1-2.517 2.453 7.159 7.159 0 0 1-1.048.625c-.28.132-.581.24-.829.24s-.548-.108-.829-.24a7.158 7.158 0 0 1-1.048-.625 11.777 11.777 0 0 1-2.517-2.453C1.928 10.487.545 7.169 1.141 2.692A1.54 1.54 0 0 1 2.185 1.43 62.456 62.456 0 0 1 5.072.56z"/>
 
3
  </svg>
resources/images/bootstrap/sliders.svg CHANGED
@@ -1,3 +1,3 @@
1
- <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-sliders" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
2
  <path fill-rule="evenodd" d="M11.5 2a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3zM9.05 3a2.5 2.5 0 0 1 4.9 0H16v1h-2.05a2.5 2.5 0 0 1-4.9 0H0V3h9.05zM4.5 7a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3zM2.05 8a2.5 2.5 0 0 1 4.9 0H16v1H6.95a2.5 2.5 0 0 1-4.9 0H0V8h2.05zm9.45 4a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3zm-2.45 1a2.5 2.5 0 0 1 4.9 0H16v1h-2.05a2.5 2.5 0 0 1-4.9 0H0v-1h9.05z"/>
3
  </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-sliders" viewBox="0 0 16 16">
2
  <path fill-rule="evenodd" d="M11.5 2a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3zM9.05 3a2.5 2.5 0 0 1 4.9 0H16v1h-2.05a2.5 2.5 0 0 1-4.9 0H0V3h9.05zM4.5 7a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3zM2.05 8a2.5 2.5 0 0 1 4.9 0H16v1H6.95a2.5 2.5 0 0 1-4.9 0H0V8h2.05zm9.45 4a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3zm-2.45 1a2.5 2.5 0 0 1 4.9 0H16v1h-2.05a2.5 2.5 0 0 1-4.9 0H0v-1h9.05z"/>
3
  </svg>
resources/images/bootstrap/speedometer.svg ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-speedometer" viewBox="0 0 16 16">
2
+ <path d="M8 2a.5.5 0 0 1 .5.5V4a.5.5 0 0 1-1 0V2.5A.5.5 0 0 1 8 2zM3.732 3.732a.5.5 0 0 1 .707 0l.915.914a.5.5 0 1 1-.708.708l-.914-.915a.5.5 0 0 1 0-.707zM2 8a.5.5 0 0 1 .5-.5h1.586a.5.5 0 0 1 0 1H2.5A.5.5 0 0 1 2 8zm9.5 0a.5.5 0 0 1 .5-.5h1.5a.5.5 0 0 1 0 1H12a.5.5 0 0 1-.5-.5zm.754-4.246a.389.389 0 0 0-.527-.02L7.547 7.31A.91.91 0 1 0 8.85 8.569l3.434-4.297a.389.389 0 0 0-.029-.518z"/>
3
+ <path fill-rule="evenodd" d="M6.664 15.889A8 8 0 1 1 9.336.11a8 8 0 0 1-2.672 15.78zm-4.665-4.283A11.945 11.945 0 0 1 8 10c2.186 0 4.236.585 6.001 1.606a7 7 0 1 0-12.002 0z"/>
4
+ </svg>
resources/images/bootstrap/stickies.svg CHANGED
@@ -1,5 +1,4 @@
1
- <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-stickies" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
2
- <path fill-rule="evenodd" d="M0 1.5A1.5 1.5 0 0 1 1.5 0H13a1 1 0 0 1 1 1H1.5a.5.5 0 0 0-.5.5V14a1 1 0 0 1-1-1V1.5z"/>
3
- <path fill-rule="evenodd" d="M2 3.5A1.5 1.5 0 0 1 3.5 2h11A1.5 1.5 0 0 1 16 3.5v6.086a1.5 1.5 0 0 1-.44 1.06l-4.914 4.915a1.5 1.5 0 0 1-1.06.439H3.5A1.5 1.5 0 0 1 2 14.5v-11zM3.5 3a.5.5 0 0 0-.5.5v11a.5.5 0 0 0 .5.5h6.086a.5.5 0 0 0 .353-.146l4.915-4.915A.5.5 0 0 0 15 9.586V3.5a.5.5 0 0 0-.5-.5h-11z"/>
4
- <path fill-rule="evenodd" d="M10.5 10a.5.5 0 0 0-.5.5v5H9v-5A1.5 1.5 0 0 1 10.5 9h5v1h-5z"/>
5
  </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-stickies" viewBox="0 0 16 16">
2
+ <path d="M1.5 0A1.5 1.5 0 0 0 0 1.5V13a1 1 0 0 0 1 1V1.5a.5.5 0 0 1 .5-.5H14a1 1 0 0 0-1-1H1.5z"/>
3
+ <path d="M3.5 2A1.5 1.5 0 0 0 2 3.5v11A1.5 1.5 0 0 0 3.5 16h6.086a1.5 1.5 0 0 0 1.06-.44l4.915-4.914A1.5 1.5 0 0 0 16 9.586V3.5A1.5 1.5 0 0 0 14.5 2h-11zM3 3.5a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 .5.5V9h-4.5A1.5 1.5 0 0 0 9 10.5V15H3.5a.5.5 0 0 1-.5-.5v-11zm7 11.293V10.5a.5.5 0 0 1 .5-.5h4.293L10 14.793z"/>
 
4
  </svg>
resources/images/bootstrap/sticky.svg CHANGED
@@ -1,4 +1,3 @@
1
- <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-sticky" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
2
- <path fill-rule="evenodd" d="M1 2.5A1.5 1.5 0 0 1 2.5 1h11A1.5 1.5 0 0 1 15 2.5v6.086a1.5 1.5 0 0 1-.44 1.06l-4.914 4.915a1.5 1.5 0 0 1-1.06.439H2.5A1.5 1.5 0 0 1 1 13.5v-11zM2.5 2a.5.5 0 0 0-.5.5v11a.5.5 0 0 0 .5.5h6.086a.5.5 0 0 0 .353-.146l4.915-4.915A.5.5 0 0 0 14 8.586V2.5a.5.5 0 0 0-.5-.5h-11z"/>
3
- <path fill-rule="evenodd" d="M9.5 9a.5.5 0 0 0-.5.5v5H8v-5A1.5 1.5 0 0 1 9.5 8h5v1h-5z"/>
4
  </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-sticky" viewBox="0 0 16 16">
2
+ <path d="M2.5 1A1.5 1.5 0 0 0 1 2.5v11A1.5 1.5 0 0 0 2.5 15h6.086a1.5 1.5 0 0 0 1.06-.44l4.915-4.914A1.5 1.5 0 0 0 15 8.586V2.5A1.5 1.5 0 0 0 13.5 1h-11zM2 2.5a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 .5.5V8H9.5A1.5 1.5 0 0 0 8 9.5V14H2.5a.5.5 0 0 1-.5-.5v-11zm7 11.293V9.5a.5.5 0 0 1 .5-.5h4.293L9 13.793z"/>
 
3
  </svg>
resources/images/bootstrap/stoplights.svg CHANGED
@@ -1,5 +1,4 @@
1
- <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-stoplights" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
2
- <path d="M9.5 3.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0 4a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0 4a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z"/>
3
- <path fill-rule="evenodd" d="M10 1H6a1 1 0 0 0-1 1v11a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1zM6 0a2 2 0 0 0-2 2v11a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H6z"/>
4
- <path d="M14 2h-2v2c1.2-.4 1.833-1.5 2-2zM2 2h2v2c-1.2-.4-1.833-1.5-2-2zm12 4h-2v2c1.2-.4 1.833-1.5 2-2zM2 6h2v2c-1.2-.4-1.833-1.5-2-2zm12 4h-2v2c1.2-.4 1.833-1.5 2-2zM2 10h2v2c-1.2-.4-1.833-1.5-2-2z"/>
5
  </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-stoplights" viewBox="0 0 16 16">
2
+ <path d="M8 5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zm0 4a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3zm1.5 2.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z"/>
3
+ <path d="M4 2a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2h2c-.167.5-.8 1.6-2 2v2h2c-.167.5-.8 1.6-2 2v2h2c-.167.5-.8 1.6-2 2v1a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-1c-1.2-.4-1.833-1.5-2-2h2V8c-1.2-.4-1.833-1.5-2-2h2V4c-1.2-.4-1.833-1.5-2-2h2zm2-1a1 1 0 0 0-1 1v11a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H6z"/>
 
4
  </svg>
resources/images/bootstrap/tools.svg ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-tools" viewBox="0 0 16 16">
2
+ <path d="M1 0 0 1l2.2 3.081a1 1 0 0 0 .815.419h.07a1 1 0 0 1 .708.293l2.675 2.675-2.617 2.654A3.003 3.003 0 0 0 0 13a3 3 0 1 0 5.878-.851l2.654-2.617.968.968-.305.914a1 1 0 0 0 .242 1.023l3.356 3.356a1 1 0 0 0 1.414 0l1.586-1.586a1 1 0 0 0 0-1.414l-3.356-3.356a1 1 0 0 0-1.023-.242L10.5 9.5l-.96-.96 2.68-2.643A3.005 3.005 0 0 0 16 3c0-.269-.035-.53-.102-.777l-2.14 2.141L12 4l-.364-1.757L13.777.102a3 3 0 0 0-3.675 3.68L7.462 6.46 4.793 3.793a1 1 0 0 1-.293-.707v-.071a1 1 0 0 0-.419-.814L1 0zm9.646 10.646a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1-.708.708l-3-3a.5.5 0 0 1 0-.708zM3 11l.471.242.529.026.287.445.445.287.026.529L5 13l-.242.471-.026.529-.445.287-.287.445-.529.026L3 15l-.471-.242L2 14.732l-.287-.445L1.268 14l-.026-.529L1 13l.242-.471.026-.529.445-.287.287-.445.529-.026L3 11z"/>
3
+ </svg>
resources/js/global-plugin.js CHANGED
@@ -11,33 +11,6 @@ var iCWP_WPSF_JSErrorTrack = new function () {
11
  }();
12
  iCWP_WPSF_JSErrorTrack.initialise();
13
 
14
- var iCWP_WPSF_SecurityAdmin = new function () {
15
-
16
- this.initialise = function () {
17
- jQuery( document ).ready( function () {
18
- jQuery( document ).on( "submit", '#SecurityAdminForm',
19
- function ( event ) {
20
- event.preventDefault();
21
- iCWP_WPSF_StandardAjax.send_ajax_req( jQuery( event.target ).serialize() );
22
- return false;
23
- }
24
- );
25
-
26
- if ( typeof icwp_wpsf_vars_secadmin !== 'undefined' ) {
27
- jQuery( document ).on( "click", '#SecAdminRemoveConfirmEmail',
28
- function ( event ) {
29
- event.preventDefault();
30
- if ( confirm( icwp_wpsf_vars_secadmin.strings.are_you_sure ) ) {
31
- iCWP_WPSF_StandardAjax.send_ajax_req( icwp_wpsf_vars_secadmin.ajax.req_email_remove );
32
- }
33
- return false;
34
- }
35
- );
36
- }
37
- } );
38
- };
39
- }();
40
-
41
  var iCWP_WPSF_ParseAjaxResponse = new function () {
42
  this.parseIt = function ( raw ) {
43
  var parsed = {};
@@ -68,8 +41,12 @@ var iCWP_WPSF_ParseAjaxResponse = new function () {
68
  }();
69
 
70
  var iCWP_WPSF_StandardAjax = new function () {
71
- this.send_ajax_req = function ( reqData ) {
72
- iCWP_WPSF_BodyOverlay.show();
 
 
 
 
73
 
74
  reqData.apto_wrap_response = 1;
75
 
@@ -81,14 +58,27 @@ var iCWP_WPSF_StandardAjax = new function () {
81
  success: function ( raw ) {
82
  var resp = iCWP_WPSF_ParseAjaxResponse.parseIt( raw );
83
 
84
- if ( typeof iCWP_WPSF_Toaster !== 'undefined' ) {
85
- iCWP_WPSF_Toaster.showMessage( resp.data.message, resp.success );
86
- }
87
- else {
88
- iCWP_WPSF_Growl.showMessage( resp.data.message, resp.success );
 
 
 
 
 
 
 
 
 
 
89
  }
90
 
91
- if ( resp.data.page_reload ) {
 
 
 
92
  setTimeout( function () {
93
  location.reload();
94
  }, 2000 );
@@ -99,7 +89,7 @@ var iCWP_WPSF_StandardAjax = new function () {
99
  }
100
  } ).fail( function () {
101
  alert( 'Something went wrong with the request - it was either blocked or there was an error.' );
102
- } )
103
  };
104
  }();
105
 
@@ -275,54 +265,6 @@ if ( typeof icwp_wpsf_vars_lg !== 'undefined' ) {
275
  iCWP_WPSF_LoginGuard_BackupCodes.initialise();
276
  }
277
 
278
- /** TODO: THIS AJAX IS NOT COMPLETE **/
279
- var iCWP_WPSF_Autoupdates = new function () {
280
-
281
- var bRequestCurrentlyRunning = false;
282
-
283
- var togglePluginUpdate = function ( event ) {
284
- if ( bRequestCurrentlyRunning ) {
285
- return false;
286
- }
287
-
288
- $oInput = jQuery( this );
289
-
290
- if ( $oInput.data( 'disabled' ) !== 'no' ) {
291
- iCWP_WPSF_Growl.showMessage( $oInput.data( 'disabled' ), false );
292
- return false;
293
- }
294
-
295
- return sendTogglePluginAutoupdate( $oInput.data( 'pluginfile' ), $oInput.data( 'nonce' ) );
296
- };
297
-
298
- var sendTogglePluginAutoupdate = function ( sPluginFile ) {
299
- bRequestCurrentlyRunning = true;
300
-
301
- var requestData = {
302
- 'action': 'icwp_wpsf_TogglePluginAutoupdate',
303
- 'pluginfile': sPluginFile
304
- };
305
-
306
- jQuery.post( ajaxurl, requestData,
307
- function ( oResponse ) {
308
- iCWP_WPSF_Growl.showMessage( oResponse.data.message, oResponse.success );
309
- }
310
- ).always( function () {
311
- bRequestCurrentlyRunning = false;
312
- }
313
- );
314
-
315
- return true;
316
- };
317
-
318
- this.initialise = function () {
319
- jQuery( document ).ready( function () {
320
- jQuery( document ).on( "click", "input.icwp-autoupdate-plugin", togglePluginUpdate );
321
- } );
322
- };
323
-
324
- }();
325
-
326
  var iCWP_WPSF_Growl = new function () {
327
 
328
  this.showMessage = function ( sMessage, bSuccess ) {
@@ -368,99 +310,14 @@ var iCWP_WPSF_BodyOverlay = new function () {
368
  };
369
 
370
  this.initialise = function () {
371
- jQuery( document ).ready( function () {
372
- var $oDiv = jQuery( '<div />' )
373
- .attr( 'id', 'icwp-fade-wrapper' )
374
- .html( '<div class="icwp-waiting"><div style="width: 4rem; height: 4rem;" class="spinner-grow text-success"></div></div>' )
375
- .appendTo( 'body' );
376
- } );
377
  };
378
 
379
  }();
380
 
381
- // iCWP_WPSF_Autoupdates.initialise();
382
- iCWP_WPSF_BodyOverlay.initialise();
383
- iCWP_WPSF_SecurityAdmin.initialise();
384
-
385
- if ( false && typeof icwp_wpsf_vars_plugin !== 'undefined' ) {
386
-
387
- var iCWP_WPSF_Plugin_Deactivate_Survey = new function () {
388
-
389
- this.initialise = function () {
390
- jQuery( document ).ready( function () {
391
-
392
- if ( !iCWP_WPSF_JSErrorTrack.hasError() ) {
393
- jQuery( document ).on( "click",
394
- '[data-plugin="' + icwp_wpsf_vars_plugin.file + '"] span.deactivate a',
395
- promptSurvey
396
- );
397
- }
398
-
399
- var oShareSettings = {
400
- title: 'Care To Share?',
401
- dialogClass: 'wp-dialog',
402
- autoOpen: false,
403
- draggable: false,
404
- width: 'auto',
405
- modal: true,
406
- resizable: false,
407
- closeOnEscape: true,
408
- position: {
409
- my: "center",
410
- at: "center",
411
- of: window
412
- },
413
- open: function () {
414
- // close dialog by clicking the overlay behind it
415
- jQuery( '.ui-widget-overlay' ).bind( 'click', function () {
416
- jQuery( this ).dialog( 'close' );
417
- } )
418
- },
419
- create: function () {
420
- // style fix for WordPress admin
421
- jQuery( '.ui-dialog-titlebar-close' ).addClass( 'ui-button' );
422
- },
423
- close: function () {
424
- window.location.href = icwp_wpsf_vars_plugin.hrefs.deactivate;
425
- }
426
- };
427
-
428
- var $oSurveyDialog = jQuery( '#icwpWpsfSurvey' );
429
- oShareSettings[ 'buttons' ] = {
430
- "Close (I don't want to help)": function () {
431
- jQuery( this ).dialog( "close" );
432
- },
433
- "Yes (Send my feedback)": function () {
434
- send_survey_deactivate();
435
- jQuery( this ).dialog( "close" );
436
- }
437
- };
438
- $oSurveyDialog.dialog( oShareSettings );
439
- } );
440
- };
441
-
442
- var promptSurvey = function ( event ) {
443
- event.preventDefault();
444
- iCWP_WPSF_BodyOverlay.show();
445
- jQuery( '#icwpWpsfSurvey' ).dialog( 'open' );
446
- return false;
447
- };
448
-
449
- var send_survey_deactivate = function () {
450
-
451
- var $aData = icwp_wpsf_vars_plugin.ajax.send_deactivate_survey;
452
- jQuery.each( jQuery( '#icwpWpsfSurveyForm' ).serializeArray(),
453
- function ( _, kv ) {
454
- $aData[ kv.name ] = kv.value;
455
- }
456
- );
457
-
458
- jQuery.post( ajaxurl, $aData );
459
- setTimeout( function () {
460
- }, 2000 ); // give the request time to complete
461
-
462
- return false;
463
- };
464
- }();
465
- iCWP_WPSF_Plugin_Deactivate_Survey.initialise();
466
- }
11
  }();
12
  iCWP_WPSF_JSErrorTrack.initialise();
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  var iCWP_WPSF_ParseAjaxResponse = new function () {
15
  this.parseIt = function ( raw ) {
16
  var parsed = {};
41
  }();
42
 
43
  var iCWP_WPSF_StandardAjax = new function () {
44
+
45
+ this.send_ajax_req = function ( reqData, quiet = false, triggerEvent = '' ) {
46
+
47
+ if ( !quiet ) {
48
+ iCWP_WPSF_BodyOverlay.show();
49
+ }
50
 
51
  reqData.apto_wrap_response = 1;
52
 
58
  success: function ( raw ) {
59
  var resp = iCWP_WPSF_ParseAjaxResponse.parseIt( raw );
60
 
61
+ if ( typeof resp.data.show_toast === typeof undefined || resp.data.show_toast ) {
62
+
63
+ if ( typeof resp.data.message === typeof undefined ) {
64
+ resp.data.message = resp.success ?
65
+ 'The request succeeded' : 'The request failed';
66
+ }
67
+
68
+ if ( !quiet ) {
69
+ if ( typeof iCWP_WPSF_Toaster !== 'undefined' ) {
70
+ iCWP_WPSF_Toaster.showMessage( resp.data.message, resp.success );
71
+ }
72
+ else {
73
+ iCWP_WPSF_Growl.showMessage( resp.data.message, resp.success );
74
+ }
75
+ }
76
  }
77
 
78
+ if ( triggerEvent.length > 0 ) {
79
+ jQuery( document ).trigger( 'shield-'+triggerEvent, resp );
80
+ }
81
+ else if ( resp.data.page_reload ) {
82
  setTimeout( function () {
83
  location.reload();
84
  }, 2000 );
89
  }
90
  } ).fail( function () {
91
  alert( 'Something went wrong with the request - it was either blocked or there was an error.' );
92
+ } );
93
  };
94
  }();
95
 
265
  iCWP_WPSF_LoginGuard_BackupCodes.initialise();
266
  }
267
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
268
  var iCWP_WPSF_Growl = new function () {
269
 
270
  this.showMessage = function ( sMessage, bSuccess ) {
310
  };
311
 
312
  this.initialise = function () {
313
+ jQuery( '<div />' )
314
+ .attr( 'id', 'icwp-fade-wrapper' )
315
+ .html( '<div class="icwp-waiting"><div style="width: 4rem; height: 4rem;" class="spinner-grow text-success"></div></div>' )
316
+ .appendTo( 'body' );
 
 
317
  };
318
 
319
  }();
320
 
321
+ jQuery( document ).ready( function () {
322
+ iCWP_WPSF_BodyOverlay.initialise();
323
+ } );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
resources/js/icwp-options.js DELETED
@@ -1,70 +0,0 @@
1
- jQuery( document ).ready(
2
- function () {
3
- return;
4
-
5
- var $oIcwpOptions = jQuery( 'div#icwp-options-form' );
6
-
7
- /**
8
- * Initialise the default states of sections and inputs.
9
- */
10
- jQuery( 'input:checked' ).parents( 'div.option_section' ).addClass( 'active' );
11
-
12
- /**
13
- * When the user clicks on a "section", this handler will adjust the radio/checkbox
14
- * according to the current value. If the user clicked "section" but actually clicked
15
- * on an input field within the section, this normal handler will get called, and the
16
- * "section" handler will exit immediately.
17
- */
18
- jQuery( '.option_section' ).on( 'click', onSectionClick );
19
-
20
- /**
21
- * When a checkbox, or associated label is clicked, the parent "section" style is updated.
22
- */
23
- jQuery( '.option_section input[type=checkbox],.option_section label' ).on( 'click',
24
- function ( inoEvent ) {
25
- var $this = jQuery( this );
26
- var oParent = $this.parents( 'div.option_section' );
27
-
28
- var oInput = jQuery( 'input[type=checkbox]', oParent );
29
- if ( oInput.is( ':checked' ) ) {
30
- oParent.addClass( 'active' );
31
- }
32
- else {
33
- oParent.removeClass( 'active' );
34
- }
35
- }
36
- );
37
-
38
- jQuery( 'select[name=option]', $oIcwpOptions ).trigger( 'change' );
39
- }
40
- );
41
-
42
- function onSectionClick( inoEvent ) {
43
- /**
44
- * Don't manipulate the checkboxes/radios if the actual input or linked-label was
45
- * the target of the click.
46
- */
47
- var oDiv = jQuery( inoEvent.currentTarget );
48
- if ( inoEvent.target.tagName && inoEvent.target.tagName.match( /input|label/i ) ) {
49
- return true;
50
- }
51
-
52
- var oEl = oDiv.find( 'input[type=checkbox]' );
53
- if ( oEl.length > 0 ) {
54
- if ( oEl.is( ':checked' ) ) {
55
- oEl.removeAttr( 'checked' );
56
- oDiv.removeClass( 'active' );
57
- }
58
- else {
59
- oEl.attr( 'checked', 'checked' );
60
- oDiv.addClass( 'active' );
61
- }
62
- }
63
-
64
- oEl = oDiv.find( 'input[type=radio]' );
65
- if ( oEl.length > 0 && !oEl.is( ':checked' ) ) {
66
- oEl.attr( 'checked', 'checked' );
67
- oDiv.addClass( 'active' ).siblings().removeClass( 'active' );
68
- }
69
-
70
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
resources/js/plugin.js CHANGED
@@ -102,19 +102,19 @@ iCWP_WPSF_Toaster.initialise();
102
  var iCWP_WPSF_OptionsFormSubmit = new function () {
103
 
104
  let bRequestCurrentlyRunning = false;
105
- var aAjaxReqParams = icwp_wpsf_vars_base.ajax.mod_options;
106
 
107
- this.submit = function ( sMessage, bSuccess ) {
108
- let $oDiv = createDynDiv( bSuccess ? 'success' : 'failed' );
109
- $oDiv.fadeIn().html( sMessage );
110
  setTimeout( function () {
111
  $oDiv.fadeOut( 5000 );
112
  $oDiv.remove();
113
  }, 4000 );
114
  };
115
 
116
- this.updateAjaxReqParams = function ( aParams ) {
117
- aAjaxReqParams = aParams;
118
  };
119
 
120
  /**
@@ -122,15 +122,21 @@ var iCWP_WPSF_OptionsFormSubmit = new function () {
122
  * This works around mod_security rules that even unpack b64 encoded params and look
123
  * for patterns within them.
124
  */
125
- var sendForm = function ( $oForm, useCompression = false ) {
126
 
127
- let formData = $oForm.serialize();
128
  if ( useCompression ) {
129
  formData = LZString.compress( formData );
130
  }
131
 
 
 
 
 
 
 
132
  let reqs = jQuery.extend(
133
- aAjaxReqParams,
134
  {
135
  'form_params': Base64.encode( formData ),
136
  'enc_params': useCompression ? 'lz-string' : 'b64',
@@ -154,7 +160,7 @@ var iCWP_WPSF_OptionsFormSubmit = new function () {
154
  }
155
  else {
156
  iCWP_WPSF_Toaster.showMessage( 'The request was blocked. Retrying an alternative...', false );
157
- sendForm( $oForm, true );
158
  }
159
 
160
  } ).always( function () {
@@ -188,23 +194,23 @@ var iCWP_WPSF_OptionsFormSubmit = new function () {
188
  bRequestCurrentlyRunning = true;
189
  event.preventDefault();
190
 
191
- var $oForm = jQuery( this );
192
 
193
- var $bPasswordsReady = true;
194
- jQuery( 'input[type=password]', $oForm ).each( function () {
195
  var $oPass = jQuery( this );
196
- var $oConfirm = jQuery( '#' + $oPass.attr( 'id' ) + '_confirm', $oForm );
197
  if ( typeof $oConfirm.attr( 'id' ) !== 'undefined' ) {
198
  if ( $oPass.val() && !$oConfirm.val() ) {
199
  $oConfirm.addClass( 'is-invalid' );
200
  alert( 'Form not submitted due to error: password confirmation field not provided.' );
201
- $bPasswordsReady = false;
202
  }
203
  }
204
  } );
205
 
206
- if ( $bPasswordsReady ) {
207
- sendForm( $oForm, false );
208
  }
209
  };
210
 
@@ -218,72 +224,6 @@ var iCWP_WPSF_OptionsFormSubmit = new function () {
218
  iCWP_WPSF_OptionsPages.initialise();
219
  iCWP_WPSF_OptionsFormSubmit.initialise();
220
 
221
- if ( typeof icwp_wpsf_vars_secadmin !== 'undefined' && icwp_wpsf_vars_secadmin.timeleft > 0 ) {
222
-
223
- var iCWP_WPSF_SecurityAdminCheck = new function () {
224
-
225
- var bCheckInPlace = false;
226
- var bWarningShown = false;
227
- var nIntervalTimeout = 500 * icwp_wpsf_vars_secadmin.timeleft;
228
-
229
- var checkSecAdmin = function () {
230
-
231
- bCheckInPlace = false;
232
-
233
- jQuery.post( ajaxurl, icwp_wpsf_vars_secadmin.ajax.check,
234
- function ( oResponse ) {
235
- if ( oResponse.data.success ) {
236
- var nLeft = oResponse.data.timeleft;
237
- nIntervalTimeout = Math.max( 3, (nLeft / 2) ) * 1000;
238
-
239
- if ( !bWarningShown && nLeft < 20 && nLeft > 8 ) {
240
- bWarningShown = true;
241
- iCWP_WPSF_Toaster.showMessage( icwp_wpsf_vars_secadmin.strings.nearly, false );
242
- // iCWP_WPSF_Growl.showMessage( icwp_wpsf_vars_secadmin.strings.nearly, false );
243
- }
244
-
245
- scheduleSecAdminCheck();
246
- }
247
- else {
248
- iCWP_WPSF_BodyOverlay.show();
249
- setTimeout( function () {
250
- if ( confirm( icwp_wpsf_vars_secadmin.strings.confirm ) ) {
251
- window.location.reload();
252
- }
253
- else {
254
- iCWP_WPSF_BodyOverlay.hide();
255
- // Do nothing!
256
- }
257
- }, 1500 );
258
- iCWP_WPSF_Toaster.showMessage( icwp_wpsf_vars_secadmin.strings.expired, oResponse.success );
259
- // iCWP_WPSF_Growl.showMessage( icwp_wpsf_vars_secadmin.strings.expired, oResponse.success );
260
- }
261
-
262
- }
263
- ).always( function () {
264
- }
265
- );
266
- };
267
-
268
- let scheduleSecAdminCheck = function () {
269
- if ( !bCheckInPlace ) {
270
- setTimeout( function () {
271
- checkSecAdmin();
272
- }, nIntervalTimeout );
273
- bCheckInPlace = true;
274
- }
275
- };
276
-
277
- this.initialise = function () {
278
- jQuery( document ).ready( function () {
279
- scheduleSecAdminCheck();
280
- } );
281
- };
282
- }();
283
-
284
- iCWP_WPSF_SecurityAdminCheck.initialise();
285
- }
286
-
287
  jQuery.fn.icwpWpsfAjaxTable = function ( aOptions ) {
288
 
289
  this.reloadTable = function () {
@@ -392,14 +332,14 @@ jQuery.fn.icwpWpsfAjaxTable = function ( aOptions ) {
392
  if ( typeof icwp_wpsf_vars_plugin !== 'undefined' ) {
393
 
394
  jQuery( document ).ready( function () {
395
- jQuery( document ).on( "click", "a.shield_file_download", function ( evt ) {
396
  evt.preventDefault();
397
  /** Cache busting **/
398
  let url = jQuery( this ).attr( 'href' ) + '&rand='
399
  + Math.floor( 10000 * Math.random() );
400
  jQuery.fileDownload( url, {
401
  preparingMessageHtml: icwp_wpsf_vars_plugin.strings.downloading_file,
402
- failMessageHtml: icwp_wpsf_vars_plugin.strings.problem_downloading_file
403
  } );
404
  return false;
405
  } );
@@ -408,7 +348,8 @@ if ( typeof icwp_wpsf_vars_plugin !== 'undefined' ) {
408
 
409
  jQuery( document ).ready( function () {
410
  jQuery( document ).icwpWpsfTours();
411
- jQuery( '.select2picker' ).select2({
 
412
  width: 'resolve'
413
- });
414
  } );
102
  var iCWP_WPSF_OptionsFormSubmit = new function () {
103
 
104
  let bRequestCurrentlyRunning = false;
105
+ var reqParams = icwp_wpsf_vars_base.ajax.mod_options;
106
 
107
+ this.submit = function ( msg, success ) {
108
+ let $oDiv = createDynDiv( success ? 'success' : 'failed' );
109
+ $oDiv.fadeIn().html( msg );
110
  setTimeout( function () {
111
  $oDiv.fadeOut( 5000 );
112
  $oDiv.remove();
113
  }, 4000 );
114
  };
115
 
116
+ this.updateAjaxReqParams = function ( params ) {
117
+ reqParams = params;
118
  };
119
 
120
  /**
122
  * This works around mod_security rules that even unpack b64 encoded params and look
123
  * for patterns within them.
124
  */
125
+ var sendForm = function ( $form, useCompression = false ) {
126
 
127
+ let formData = $form.serialize();
128
  if ( useCompression ) {
129
  formData = LZString.compress( formData );
130
  }
131
 
132
+ /** Required since using dynamic AJAX loaded page content **/
133
+ if ( !$form.data( 'mod_slug' ) ) {
134
+ alert( 'Missing form data' );
135
+ return false;
136
+ }
137
+ reqParams.mod_slug = $form.data( 'mod_slug' );
138
  let reqs = jQuery.extend(
139
+ reqParams,
140
  {
141
  'form_params': Base64.encode( formData ),
142
  'enc_params': useCompression ? 'lz-string' : 'b64',
160
  }
161
  else {
162
  iCWP_WPSF_Toaster.showMessage( 'The request was blocked. Retrying an alternative...', false );
163
+ sendForm( $form, true );
164
  }
165
 
166
  } ).always( function () {
194
  bRequestCurrentlyRunning = true;
195
  event.preventDefault();
196
 
197
+ var $form = jQuery( this );
198
 
199
+ var $passwordsReady = true;
200
+ jQuery( 'input[type=password]', $form ).each( function () {
201
  var $oPass = jQuery( this );
202
+ var $oConfirm = jQuery( '#' + $oPass.attr( 'id' ) + '_confirm', $form );
203
  if ( typeof $oConfirm.attr( 'id' ) !== 'undefined' ) {
204
  if ( $oPass.val() && !$oConfirm.val() ) {
205
  $oConfirm.addClass( 'is-invalid' );
206
  alert( 'Form not submitted due to error: password confirmation field not provided.' );
207
+ $passwordsReady = false;
208
  }
209
  }
210
  } );
211
 
212
+ if ( $passwordsReady ) {
213
+ sendForm( $form, false );
214
  }
215
  };
216
 
224
  iCWP_WPSF_OptionsPages.initialise();
225
  iCWP_WPSF_OptionsFormSubmit.initialise();
226
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
  jQuery.fn.icwpWpsfAjaxTable = function ( aOptions ) {
228
 
229
  this.reloadTable = function () {
332
  if ( typeof icwp_wpsf_vars_plugin !== 'undefined' ) {
333
 
334
  jQuery( document ).ready( function () {
335
+ jQuery( document ).on( 'click', 'a.shield_file_download, li.shield_file_download > a', function ( evt ) {
336
  evt.preventDefault();
337
  /** Cache busting **/
338
  let url = jQuery( this ).attr( 'href' ) + '&rand='
339
  + Math.floor( 10000 * Math.random() );
340
  jQuery.fileDownload( url, {
341
  preparingMessageHtml: icwp_wpsf_vars_plugin.strings.downloading_file,
342
+ failMessageHtml: icwp_wpsf_vars_plugin.strings.downloading_file_problem
343
  } );
344
  return false;
345
  } );
348
 
349
  jQuery( document ).ready( function () {
350
  jQuery( document ).icwpWpsfTours();
351
+ jQuery( document ).icwpWpsfPluginNavigation();
352
+ jQuery( '.select2picker' ).select2( {
353
  width: 'resolve'
354
+ } );
355
  } );
resources/js/shield/mainwp-extension.js CHANGED
@@ -112,20 +112,6 @@
112
  }
113
  );
114
 
115
- plugin.$element.on(
116
- 'click' + '.' + plugin._name,
117
- 'button.action.href-download',
118
- function ( evt ) {
119
- evt.preventDefault();
120
- var $oButt = $( this );
121
- var sHref = $oButt.data( 'href-download' );
122
- if ( sHref !== undefined ) {
123
- plugin.options[ 'working_href_download' ] = sHref;
124
- plugin.hrefDownload.call( plugin );
125
- }
126
- }
127
- );
128
-
129
  },
130
  unbindEvents: function () {
131
  /*
112
  }
113
  );
114
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  },
116
  unbindEvents: function () {
117
  /*
resources/js/shield/navigation.js ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery.fn.icwpWpsfPluginNavigation = function ( options ) {
2
+
3
+ let currentMenuClickTarget;
4
+
5
+ var handleDynamicLoad = function ( evt, response ) {
6
+ document.querySelector( '#apto-PageMainBody' ).innerHTML = response.data.html;
7
+
8
+ window.history.replaceState(
9
+ {},
10
+ response.data.page_title,
11
+ response.data.page_url
12
+ );
13
+
14
+ document.getElementById( 'PageTitle' ).innerHTML = response.data.page_title;
15
+
16
+ let activeLinks = document.querySelectorAll( '#NavSideBar a.nav-link.active' );
17
+ for ( var i = 0; i < activeLinks.length; i++ ) {
18
+ activeLinks[ i ].classList.remove( 'active' );
19
+ }
20
+ currentMenuClickTarget.classList.add( 'active' );
21
+
22
+ let parentNav = currentMenuClickTarget.closest( 'ul' ).closest( 'li.nav-item' );
23
+ if ( parentNav !== null ) {
24
+ parentNav.querySelector( 'a.nav-link' ).classList.add( 'active' );
25
+ }
26
+
27
+ iCWP_WPSF_BodyOverlay.hide();
28
+ };
29
+
30
+ var renderDynamicPageLoad = function ( params ) {
31
+ sendReq( params );
32
+ };
33
+
34
+ var sendReq = function ( params ) {
35
+ document.querySelector( '#apto-PageMainBody' ).innerHTML = 'Loading ...';
36
+ shield_vars_navigation.ajax.dynamic_load.load_params = params;
37
+ iCWP_WPSF_StandardAjax.send_ajax_req(
38
+ shield_vars_navigation.ajax.dynamic_load, false, 'dynamic_load'
39
+ );
40
+ };
41
+
42
+ var initialise = function () {
43
+
44
+ jQuery( document ).ready( function () {
45
+
46
+ jQuery( document ).on( 'click', 'li.dynamic_body_load > a', function ( evt ) {
47
+ evt.preventDefault();
48
+ currentMenuClickTarget = evt.currentTarget;
49
+ renderDynamicPageLoad( jQuery( currentMenuClickTarget ).data() );
50
+ return false;
51
+ } );
52
+
53
+ jQuery( document ).on( 'shield-dynamic_load', handleDynamicLoad );
54
+ } );
55
+ };
56
+
57
+ var opts = jQuery.extend( {}, options );
58
+ initialise();
59
+
60
+ return this;
61
+ };
resources/js/shield/options.js ADDED
@@ -0,0 +1,304 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery.fn.icwpWpsfTableWithFilter = function ( aOptions ) {
2
+
3
+ var resetFilters = function ( evt ) {
4
+ jQuery( 'input[type=text]', $oForm ).each( function () {
5
+ jQuery( this ).val( '' );
6
+ } );
7
+ jQuery( 'select', $oForm ).each( function () {
8
+ jQuery( this ).prop( 'selectedIndex', 0 );
9
+ } );
10
+ jQuery( 'input[type=checkbox]', $oForm ).each( function () {
11
+ jQuery( this ).prop( 'checked', false );
12
+ } );
13
+ aOpts[ 'table' ].renderTableFromForm( $oForm );
14
+ };
15
+
16
+ var submitFilters = function ( evt ) {
17
+ evt.preventDefault();
18
+ aOpts[ 'table' ].renderTableFromForm( $oForm );
19
+ return false;
20
+ };
21
+
22
+ var initialise = function () {
23
+ jQuery( document ).ready( function () {
24
+ $oForm = jQuery( aOpts[ 'selector_filter_form' ] );
25
+ $oForm.on( 'submit', submitFilters );
26
+ $oForm.on( 'click', 'a#ClearForm', resetFilters );
27
+ } );
28
+ };
29
+
30
+ var $oThis = this;
31
+ var aOpts = jQuery.extend( {}, aOptions );
32
+ var $oForm;
33
+ initialise();
34
+
35
+ return this;
36
+ };
37
+
38
+ /**
39
+ * Add ajax actions to table buttons, and automatically refreshes the table.
40
+ */
41
+ (function ( $, window, document, undefined ) {
42
+
43
+ var pluginName = 'icwpWpsfTableActions';
44
+
45
+ function Ob_TableActions( element, options ) {
46
+ this.element = element;
47
+ this._name = pluginName;
48
+ this._defaults = $.fn.icwpWpsfTableActions.defaults;
49
+ this.options = $.extend(
50
+ {
51
+ 'forms': {
52
+ 'insert': ''
53
+ }
54
+ },
55
+ this._defaults,
56
+ options
57
+ );
58
+ this.init();
59
+ }
60
+
61
+ $.extend(
62
+ Ob_TableActions.prototype,
63
+ {
64
+ init: function () {
65
+ this.buildCache();
66
+ this.bindEvents();
67
+ },
68
+ destroy: function () {
69
+ this.unbindEvents();
70
+ this.$element.removeData();
71
+ },
72
+ buildCache: function () {
73
+ this.$element = $( this.element );
74
+ this.$oFormInsert = this.options[ 'forms' ][ 'insert' ];
75
+ },
76
+ bindEvents: function () {
77
+ var plugin = this;
78
+
79
+ plugin.$element.on(
80
+ 'click' + '.' + plugin._name,
81
+ 'button.action.delete',
82
+ function ( evt ) {
83
+ evt.preventDefault();
84
+ if ( confirm( icwp_wpsf_vars_insights.strings.are_you_sure ) ) {
85
+ plugin.options[ 'working_rid' ] = $( this ).data( 'rid' );
86
+ plugin.deleteEntry.call( plugin );
87
+ }
88
+ }
89
+ );
90
+
91
+ plugin.$element.on(
92
+ 'click' + '.' + plugin._name,
93
+ 'button.action.ignore',
94
+ function ( evt ) {
95
+ evt.preventDefault();
96
+ plugin.options[ 'working_rid' ] = $( this ).data( 'rid' );
97
+ plugin.ignoreEntry.call( plugin );
98
+ }
99
+ );
100
+
101
+ if ( typeof this.$oFormInsert !== 'undefined' && this.$oFormInsert.length ) {
102
+ this.$oFormInsert.on(
103
+ 'submit' + '.' + plugin._name,
104
+ function ( evt ) {
105
+ evt.preventDefault();
106
+ plugin.insertEntry.call( plugin );
107
+ }
108
+ );
109
+ }
110
+
111
+ plugin.$element.on(
112
+ 'click' + '.' + plugin._name,
113
+ 'button.action.repair',
114
+ function ( evt ) {
115
+ evt.preventDefault();
116
+ plugin.options[ 'working_rid' ] = $( this ).data( 'rid' );
117
+ plugin.repairEntry.call( plugin );
118
+ }
119
+ );
120
+
121
+ plugin.$element.on(
122
+ 'click' + '.' + plugin._name,
123
+ 'button.action.item_action',
124
+ function ( evt ) {
125
+ evt.preventDefault();
126
+ plugin.options[ 'working_rid' ] = $( this ).data( 'rid' );
127
+ plugin.options[ 'working_item_action' ] = $( this ).data( 'item_action' );
128
+ plugin.itemAction.call( plugin );
129
+ }
130
+ );
131
+
132
+ plugin.$element.on(
133
+ 'click' + '.' + plugin._name,
134
+ '.tablenav.top input[type=submit].button.action',
135
+ function ( evt ) {
136
+ evt.preventDefault();
137
+ var sAction = $( '#bulk-action-selector-top', plugin.$element ).find( ":selected" ).val();
138
+
139
+ if ( sAction === "-1" ) {
140
+ alert( icwp_wpsf_vars_insights.strings.select_action );
141
+ }
142
+ else {
143
+ var aCheckedIds = $( "input:checkbox[name=ids]:checked", plugin.$element ).map(
144
+ function () {
145
+ return $( this ).val()
146
+ } ).get();
147
+
148
+ if ( aCheckedIds.length < 1 ) {
149
+ alert( 'No rows currently selected' );
150
+ }
151
+ else {
152
+ plugin.options[ 'req_params' ][ 'bulk_action' ] = sAction;
153
+ plugin.options[ 'req_params' ][ 'ids' ] = aCheckedIds;
154
+ plugin.bulkAction.call( plugin );
155
+ }
156
+ }
157
+ return false;
158
+ }
159
+ );
160
+
161
+ plugin.$element.on(
162
+ 'click' + '.' + plugin._name,
163
+ 'button.action.custom-action',
164
+ function ( evt ) {
165
+ evt.preventDefault();
166
+ var $oButt = $( this );
167
+ var sCustomAction = $oButt.data( 'custom-action' );
168
+ if ( sCustomAction in plugin.options[ 'custom_actions_ajax' ] ) {
169
+ plugin.options[ 'working_custom_action' ] = plugin.options[ 'custom_actions_ajax' ][ sCustomAction ];
170
+ plugin.options[ 'working_custom_action' ][ 'rid' ] = $oButt.data( 'rid' );
171
+ plugin.customAction.call( plugin );
172
+ }
173
+ else {
174
+ /** This should never be reached live: **/
175
+ alert( 'custom action not supported: ' + sCustomAction );
176
+ }
177
+ }
178
+ );
179
+
180
+ plugin.$element.on(
181
+ 'click' + '.' + plugin._name,
182
+ 'button.action.href-download',
183
+ function ( evt ) {
184
+ evt.preventDefault();
185
+ var $oButt = $( this );
186
+ var sHref = $oButt.data( 'href-download' );
187
+ if ( sHref !== undefined ) {
188
+ plugin.options[ 'working_href_download' ] = sHref;
189
+ plugin.hrefDownload.call( plugin );
190
+ }
191
+ }
192
+ );
193
+
194
+ },
195
+ unbindEvents: function () {
196
+ /*
197
+ Unbind all events in our plugin's namespace that are attached
198
+ to "this.$element".
199
+ */
200
+ this.$element.off( '.' + this._name );
201
+ },
202
+
203
+ bulkAction: function () {
204
+ let aRequestData = this.options[ 'ajax_bulk_action' ];
205
+ this.sendReq( aRequestData );
206
+ },
207
+
208
+ deleteEntry: function () {
209
+ let aRequestData = this.options[ 'ajax_item_delete' ];
210
+ aRequestData[ 'rid' ] = this.options[ 'working_rid' ];
211
+ this.sendReq( aRequestData );
212
+ },
213
+
214
+ insertEntry: function () {
215
+ let requestData = this.options[ 'ajax_item_insert' ];
216
+ requestData[ 'form_params' ] = this.$oFormInsert.serialize();
217
+ this.sendReq( requestData );
218
+ this.$oFormInsert[ 0 ].reset();
219
+ },
220
+
221
+ ignoreEntry: function () {
222
+ let aRequestData = this.options[ 'ajax_item_ignore' ];
223
+ aRequestData[ 'rid' ] = this.options[ 'working_rid' ];
224
+ this.sendReq( aRequestData );
225
+ },
226
+
227
+ repairEntry: function () {
228
+ let aRequestData = this.options[ 'ajax_item_repair' ];
229
+ aRequestData[ 'rid' ] = this.options[ 'working_rid' ];
230
+ this.sendReq( aRequestData );
231
+ },
232
+
233
+ itemAction: function () {
234
+ let aRequestData = this.options[ 'ajax_item_action' ];
235
+ aRequestData[ 'rid' ] = this.options[ 'working_rid' ];
236
+ aRequestData[ 'item_action' ] = this.options[ 'working_item_action' ];
237
+ this.sendReq( aRequestData );
238
+ },
239
+
240
+ customAction: function () {
241
+ this.sendReq( this.options[ 'working_custom_action' ] );
242
+ },
243
+
244
+ hrefDownload: function () {
245
+ $.fileDownload( this.options[ 'working_href_download' ], {
246
+ preparingMessageHtml: icwp_wpsf_vars_plugin.strings.downloading_file,
247
+ failMessageHtml: icwp_wpsf_vars_plugin.strings.downloading_file_problem
248
+ } );
249
+ return false;
250
+ },
251
+
252
+ sendReq: function ( aRequestData ) {
253
+ iCWP_WPSF_BodyOverlay.show();
254
+
255
+ var plugin = this;
256
+
257
+ $.post( ajaxurl, $.extend( aRequestData, plugin.options[ 'req_params' ] ),
258
+ function ( oResponse ) {
259
+
260
+ if ( oResponse.success ) {
261
+ iCWP_WPSF_Toaster.showMessage( oResponse.data.message, oResponse.success );
262
+ if ( oResponse.data.page_reload ) {
263
+ location.reload();
264
+ }
265
+ else {
266
+ plugin.options[ 'table' ].reloadTable();
267
+ iCWP_WPSF_Toaster.showMessage( oResponse.data.message, oResponse.success );
268
+ iCWP_WPSF_BodyOverlay.hide();
269
+ }
270
+ }
271
+ else {
272
+ let sMessage = 'Communications error with site.';
273
+ if ( oResponse.data.message !== undefined ) {
274
+ sMessage = oResponse.data.message;
275
+ }
276
+ alert( sMessage );
277
+ iCWP_WPSF_BodyOverlay.hide();
278
+ }
279
+ }
280
+ ).always( function () {
281
+ }
282
+ );
283
+ },
284
+ callback: function () {
285
+ }
286
+ }
287
+ );
288
+
289
+ $.fn.icwpWpsfTableActions = function ( aOptions ) {
290
+ return this.each(
291
+ function () {
292
+ if ( !$.data( this, "plugin_" + pluginName ) ) {
293
+ $.data( this, "plugin_" + pluginName, new Ob_TableActions( this, aOptions ) );
294
+ }
295
+ }
296
+ );
297
+ };
298
+
299
+ $.fn.icwpWpsfTableActions.defaults = {
300
+ 'custom_actions_ajax': {},
301
+ 'req_params': {}
302
+ };
303
+
304
+ })( jQuery );
resources/js/shield/scans.js CHANGED
@@ -6,38 +6,37 @@ jQuery.fn.icwpWpsfScansStart = function ( aOptions ) {
6
  return false;
7
  };
8
 
9
- let sendReq = function ( aParams ) {
 
 
 
 
10
  iCWP_WPSF_BodyOverlay.show();
11
 
12
- let aReqData = aOpts[ 'ajax_scans_start' ];
13
- jQuery.post( ajaxurl, jQuery.extend( aReqData, aParams ),
14
- function ( oResponse ) {
15
 
16
- if ( oResponse.success ) {
17
- iCWP_WPSF_Toaster.showMessage( oResponse.data.message, oResponse.success );
18
- if ( oResponse.data.page_reload ) {
19
- location.reload();
20
  }
21
- else if ( oResponse.data.scans_running ) {
22
  setTimeout( function () {
23
- jQuery( document ).icwpWpsfScansCheck(
24
- {
25
- 'ajax_scans_check': aOpts[ 'ajax_scans_check' ]
26
- }
27
- );
28
  }, 1000 );
29
  }
30
  else {
31
  plugin.options[ 'table' ].reloadTable();
32
- iCWP_WPSF_Toaster.showMessage( oResponse.data.message, oResponse.success );
33
  }
34
  }
35
  else {
36
- let sMessage = 'Communications error with site.';
37
- if ( oResponse.data.message !== undefined ) {
38
- sMessage = oResponse.data.message;
39
  }
40
- alert( sMessage );
41
  iCWP_WPSF_BodyOverlay.hide();
42
  }
43
 
@@ -65,8 +64,6 @@ jQuery.fn.icwpWpsfScansStart = function ( aOptions ) {
65
  return this;
66
  };
67
 
68
- /**
69
- */
70
  jQuery.fn.icwpWpsfScansCheck = function ( aOptions ) {
71
 
72
  let bFoundRunning = false;
@@ -103,7 +100,7 @@ jQuery.fn.icwpWpsfScansCheck = function ( aOptions ) {
103
  }
104
  else {
105
  setTimeout( function () {
106
- location.reload();
107
  }, 1000 );
108
  }
109
  }
6
  return false;
7
  };
8
 
9
+ let loadResultsPage = function ( evt ) {
10
+ window.location.href = aOpts[ 'href_scans_results' ];
11
+ };
12
+
13
+ let sendReq = function ( param ) {
14
  iCWP_WPSF_BodyOverlay.show();
15
 
16
+ jQuery.post( ajaxurl, jQuery.extend( aOpts[ 'ajax_scans_start' ], param ),
17
+ function ( response ) {
 
18
 
19
+ if ( response.success ) {
20
+ iCWP_WPSF_Toaster.showMessage( response.data.message, response.success );
21
+ if ( response.data.page_reload ) {
22
+ loadResultsPage();
23
  }
24
+ else if ( response.data.scans_running ) {
25
  setTimeout( function () {
26
+ jQuery( document ).icwpWpsfScansCheck( aOpts );
 
 
 
 
27
  }, 1000 );
28
  }
29
  else {
30
  plugin.options[ 'table' ].reloadTable();
31
+ iCWP_WPSF_Toaster.showMessage( response.data.message, response.success );
32
  }
33
  }
34
  else {
35
+ let msg = 'Communications error with site.';
36
+ if ( response.data.message !== undefined ) {
37
+ msg = response.data.message;
38
  }
39
+ alert( msg );
40
  iCWP_WPSF_BodyOverlay.hide();
41
  }
42
 
64
  return this;
65
  };
66
 
 
 
67
  jQuery.fn.icwpWpsfScansCheck = function ( aOptions ) {
68
 
69
  let bFoundRunning = false;
100
  }
101
  else {
102
  setTimeout( function () {
103
+ window.location.href = aOpts[ 'href_scans_results' ];
104
  }, 1000 );
105
  }
106
  }
resources/js/shield/secadmin.js ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var iCWP_WPSF_SecurityAdmin = new function () {
2
+
3
+ var hasCheckInPlace = false;
4
+ var isWarningShown = false;
5
+ var timeoutInterval = 500 * shield_vars_secadmin.vars.time_remaining;
6
+
7
+ var checkSecAdmin = function () {
8
+ iCWP_WPSF_StandardAjax.send_ajax_req(
9
+ shield_vars_secadmin.ajax.sec_admin_check, true, 'sec_admin_check'
10
+ );
11
+ };
12
+
13
+ var handleSecAdminCheck = function ( evt, response ) {
14
+ if ( response.data.success ) {
15
+ var nLeft = response.data.time_remaining;
16
+ timeoutInterval = Math.abs( Math.max( 3, (nLeft / 2) ) * 1000 );
17
+
18
+ if ( !isWarningShown && nLeft < 20 && nLeft > 8 ) {
19
+ isWarningShown = true;
20
+ iCWP_WPSF_Toaster.showMessage( shield_vars_secadmin.strings.nearly, false );
21
+ // iCWP_WPSF_Growl.showMessage( shield_vars_secadmin.strings.nearly, false );
22
+ }
23
+
24
+ hasCheckInPlace = false;
25
+ scheduleSecAdminCheck();
26
+ }
27
+ else {
28
+ iCWP_WPSF_BodyOverlay.show();
29
+ setTimeout( function () {
30
+ alert( shield_vars_secadmin.strings.confirm )
31
+ window.location.reload();
32
+ }, 1500 );
33
+ iCWP_WPSF_Toaster.showMessage( shield_vars_secadmin.strings.expired, response.success );
34
+ // iCWP_WPSF_Growl.showMessage( shield_vars_secadmin.strings.expired, response.success );
35
+ }
36
+ };
37
+
38
+ let scheduleSecAdminCheck = function () {
39
+ if ( !hasCheckInPlace ) {
40
+ setTimeout( function () {
41
+ checkSecAdmin();
42
+ }, timeoutInterval );
43
+ hasCheckInPlace = true;
44
+ }
45
+ };
46
+
47
+ let restrictWPOptions = function () {
48
+ if ( shield_vars_secadmin.flags.restrict_options ) {
49
+ shield_vars_secadmin.vars.wp_options_to_restrict.forEach( function ( element ) {
50
+ let $element = jQuery( 'input[name=' + element + ']' );
51
+ $element.prop( 'disabled', true );
52
+ $element.parents( 'tr' ).addClass( 'restricted-option-row' );
53
+ $element.parents( 'td' ).append(
54
+ '<div style="clear:both"></div><div class="restricted-option">' +
55
+ '<span class="dashicons dashicons-lock"></span>' +
56
+ shield_vars_secadmin.strings.editing_restricted +
57
+ ' ' + shield_vars_secadmin.strings.unlock_link +
58
+ '</div>' );
59
+ } );
60
+ }
61
+ };
62
+
63
+ let performSecAdminDialogLogin = function () {
64
+
65
+ let pinInput = document.getElementById( 'SecAdminPinInput' );
66
+ shield_vars_secadmin.ajax.sec_admin_login.sec_admin_key = pinInput.value;
67
+ console.log( shield_vars_secadmin.ajax.sec_admin_login );
68
+
69
+ let inputContainer = document.getElementById( 'SecAdminPinInputContainer' );
70
+ inputContainer.innerHTML = '<div class="spinner"></div>';
71
+
72
+ jQuery.post( ajaxurl, shield_vars_secadmin.ajax.sec_admin_login, function ( response ) {
73
+ if ( response.success ) {
74
+ location.reload();
75
+ }
76
+ if ( response.data ) {
77
+ inputContainer.innerHTML = response.data.html;
78
+ }
79
+ else {
80
+ inputContainer.innerHTML = 'There was an unknown error';
81
+ }
82
+ } );
83
+ };
84
+
85
+ this.initialise = function () {
86
+
87
+ restrictWPOptions();
88
+
89
+ if ( shield_vars_secadmin.flags.run_checks ) {
90
+ scheduleSecAdminCheck();
91
+ jQuery( document ).on( 'shield-sec_admin_check', handleSecAdminCheck );
92
+ }
93
+
94
+ jQuery( document ).on( 'submit', '#SecurityAdminForm',
95
+ function ( evt ) {
96
+ evt.preventDefault();
97
+ iCWP_WPSF_StandardAjax.send_ajax_req( jQuery( evt.target ).serialize() );
98
+ return false;
99
+ }
100
+ );
101
+
102
+ jQuery( document ).on( 'click', '#SecAdminRemoveConfirmEmail',
103
+ function ( evt ) {
104
+ evt.preventDefault();
105
+ if ( confirm( shield_vars_secadmin.strings.are_you_sure ) ) {
106
+ iCWP_WPSF_StandardAjax.send_ajax_req( shield_vars_secadmin.ajax.req_email_remove );
107
+ }
108
+ return false;
109
+ }
110
+ );
111
+
112
+ jQuery( document ).on( 'click', '#SecAdminDialog button', performSecAdminDialogLogin );
113
+ };
114
+ }();
115
+
116
+ jQuery( document ).ready( function () {
117
+ iCWP_WPSF_SecurityAdmin.initialise();
118
+ } );
resources/js/shield/tables.js CHANGED
@@ -243,8 +243,8 @@ jQuery.fn.icwpWpsfTableWithFilter = function ( aOptions ) {
243
 
244
  hrefDownload: function () {
245
  $.fileDownload( this.options[ 'working_href_download' ], {
246
- preparingMessageHtml: icwp_wpsf_vars_insights.strings.downloading_file,
247
- failMessageHtml: icwp_wpsf_vars_insights.strings.downloading_file_problem
248
  } );
249
  return false;
250
  },
243
 
244
  hrefDownload: function () {
245
  $.fileDownload( this.options[ 'working_href_download' ], {
246
+ preparingMessageHtml: icwp_wpsf_vars_plugin.strings.downloading_file,
247
+ failMessageHtml: icwp_wpsf_vars_plugin.strings.downloading_file_problem
248
  } );
249
  return false;
250
  },
src/config/feature-admin_access_restriction.php CHANGED
@@ -37,7 +37,7 @@
37
  },
38
  "sections": [
39
  {
40
- "slug": "section_admin_access_restriction_settings",
41
  "primary": true,
42
  "title": "Security Admin Restriction Settings",
43
  "title_short": "Security Admin Settings",
@@ -95,7 +95,7 @@
95
  },
96
  {
97
  "key": "admin_access_key",
98
- "section": "section_admin_access_restriction_settings",
99
  "sensitive": true,
100
  "default": "",
101
  "type": "password",
@@ -107,7 +107,7 @@
107
  },
108
  {
109
  "key": "sec_admin_users",
110
- "section": "section_admin_access_restriction_settings",
111
  "advanced": true,
112
  "sensitive": true,
113
  "premium": true,
@@ -121,7 +121,7 @@
121
  },
122
  {
123
  "key": "admin_access_timeout",
124
- "section": "section_admin_access_restriction_settings",
125
  "advanced": true,
126
  "default": 30,
127
  "type": "integer",
@@ -134,7 +134,7 @@
134
  },
135
  {
136
  "key": "allow_email_override",
137
- "section": "section_admin_access_restriction_settings",
138
  "advanced": true,
139
  "default": "Y",
140
  "type": "checkbox",
37
  },
38
  "sections": [
39
  {
40
+ "slug": "section_security_admin_settings",
41
  "primary": true,
42
  "title": "Security Admin Restriction Settings",
43
  "title_short": "Security Admin Settings",
95
  },
96
  {
97
  "key": "admin_access_key",
98
+ "section": "section_security_admin_settings",
99
  "sensitive": true,
100
  "default": "",
101
  "type": "password",
107
  },
108
  {
109
  "key": "sec_admin_users",
110
+ "section": "section_security_admin_settings",
111
  "advanced": true,
112
  "sensitive": true,
113
  "premium": true,
121
  },
122
  {
123
  "key": "admin_access_timeout",
124
+ "section": "section_security_admin_settings",
125
  "advanced": true,
126
  "default": 30,
127
  "type": "integer",
134
  },
135
  {
136
  "key": "allow_email_override",
137
+ "section": "section_security_admin_settings",
138
  "advanced": true,
139
  "default": "Y",
140
  "type": "checkbox",
src/config/feature-audit_trail.php CHANGED
@@ -18,8 +18,8 @@
18
  },
19
  "menu_items": [
20
  {
21
- "title": "Audit Trail",
22
- "slug": "audit-redirect"
23
  }
24
  ],
25
  "custom_redirects": [
@@ -162,14 +162,13 @@
162
  }
163
  ],
164
  "definitions": {
165
- "db_classes": {
166
- "audit_trail": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\AuditTrail\\Handler",
167
- "audit": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\AuditTrail\\Handler"
168
  },
169
- "db_table_audit_trail": {
170
- "slug": "audit_trail",
171
- "has_updated_at": true,
172
- "cols_custom": {
173
  "rid": "varchar(10) NOT NULL DEFAULT '' COMMENT 'Request ID'",
174
  "ip": "varchar(40) NOT NULL DEFAULT 0 COMMENT 'Visitor IP Address'",
175
  "wp_username": "varchar(255) NOT NULL DEFAULT '-' COMMENT 'WP User'",
@@ -180,30 +179,9 @@
180
  "count": "SMALLINT(5) UNSIGNED NOT NULL DEFAULT 1 COMMENT 'Repeat Count'"
181
  }
182
  },
183
- "audit_trail_free_max_entries": 100,
184
- "audit_trail_table_name": "audit_trail",
185
- "audit_trail_table_columns": {
186
- "rid": "varchar(10) NOT NULL DEFAULT '' COMMENT 'Request ID'",
187
- "ip": "varchar(40) NOT NULL DEFAULT 0 COMMENT 'Visitor IP Address'",
188
- "wp_username": "varchar(255) NOT NULL DEFAULT '-' COMMENT 'WP User'",
189
- "context": "varchar(32) NOT NULL DEFAULT 'none' COMMENT 'Audit Context'",
190
- "event": "varchar(50) NOT NULL DEFAULT 'none' COMMENT 'Specific Audit Event'",
191
- "category": "int(3) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Severity'",
192
- "meta": "text COMMENT 'Audit Event Data'",
193
- "count": "SMALLINT(5) UNSIGNED NOT NULL DEFAULT 1 COMMENT 'Repeat Count'"
194
- },
195
- "audittrail_table_timestamp_columns": {
196
- "updated_at": "Updated"
197
- },
198
- "table_name_changetracking": "changetracking",
199
- "table_columns_changetracking": [
200
- "id",
201
- "data",
202
- "meta",
203
- "created_at",
204
- "deleted_at"
205
- ],
206
- "events": {
207
  "plugin_activated": {
208
  "context": "plugins",
209
  "audit_multiple": true
@@ -216,7 +194,8 @@
216
  "context": "plugins"
217
  },
218
  "plugin_upgraded": {
219
- "context": "plugins"
 
220
  },
221
  "theme_activated": {
222
  "context": "themes"
@@ -225,7 +204,8 @@
225
  "context": "themes"
226
  },
227
  "theme_upgraded": {
228
- "context": "themes"
 
229
  },
230
  "core_updated": {
231
  "context": "wordpress"
18
  },
19
  "menu_items": [
20
  {
21
+ "title": "Audit Trail",
22
+ "slug": "audit-redirect"
23
  }
24
  ],
25
  "custom_redirects": [
162
  }
163
  ],
164
  "definitions": {
165
+ "db_classes": {
166
+ "audit_trail": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\AuditTrail\\Handler"
 
167
  },
168
+ "db_table_audit_trail": {
169
+ "slug": "audit_trail",
170
+ "has_updated_at": true,
171
+ "cols_custom": {
172
  "rid": "varchar(10) NOT NULL DEFAULT '' COMMENT 'Request ID'",
173
  "ip": "varchar(40) NOT NULL DEFAULT 0 COMMENT 'Visitor IP Address'",
174
  "wp_username": "varchar(255) NOT NULL DEFAULT '-' COMMENT 'WP User'",
179
  "count": "SMALLINT(5) UNSIGNED NOT NULL DEFAULT 1 COMMENT 'Repeat Count'"
180
  }
181
  },
182
+ "audit_trail_free_max_entries": 100,
183
+ "audit_trail_table_name": "audit_trail",
184
+ "events": {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
  "plugin_activated": {
186
  "context": "plugins",
187
  "audit_multiple": true
194
  "context": "plugins"
195
  },
196
  "plugin_upgraded": {
197
+ "context": "plugins",
198
+ "audit_multiple": true
199
  },
200
  "theme_activated": {
201
  "context": "themes"
204
  "context": "themes"
205
  },
206
  "theme_upgraded": {
207
+ "context": "themes",
208
+ "audit_multiple": true
209
  },
210
  "core_updated": {
211
  "context": "wordpress"
src/config/feature-comments_filter.php CHANGED
@@ -314,21 +314,18 @@
314
  "comments_expire": 1800,
315
  "url_spam_blacklist_terms": "https://raw.githubusercontent.com/splorp/wordpress-comment-blacklist/master/blacklist.txt",
316
  "events": {
317
- "spam_block_antibot": {
318
- "recent": true,
 
319
  "offense": true
320
  },
 
 
321
  "spam_block_bot": {
322
- "recent": true,
323
- "offense": true
324
  },
325
  "spam_block_recaptcha": {
326
- "recent": true,
327
- "offense": true
328
  },
329
  "spam_block_human": {
330
- "recent": true,
331
- "offense": true
332
  }
333
  }
334
  }
314
  "comments_expire": 1800,
315
  "url_spam_blacklist_terms": "https://raw.githubusercontent.com/splorp/wordpress-comment-blacklist/master/blacklist.txt",
316
  "events": {
317
+ "comment_spam_block": {
318
+ "audit": false,
319
+ "stat": false,
320
  "offense": true
321
  },
322
+ "spam_block_antibot": {
323
+ },
324
  "spam_block_bot": {
 
 
325
  },
326
  "spam_block_recaptcha": {
 
 
327
  },
328
  "spam_block_human": {
 
 
329
  }
330
  }
331
  }
src/config/feature-events.php CHANGED
@@ -56,10 +56,6 @@
56
  "count": "int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Total'"
57
  }
58
  },
59
- "events_table_name": "events",
60
- "events_table_columns": {
61
- "event": "varchar(50) NOT NULL DEFAULT 'none' COMMENT 'Event ID'",
62
- "count": "int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Total'"
63
- }
64
  }
65
  }
56
  "count": "int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Total'"
57
  }
58
  },
59
+ "events_table_name": "events"
 
 
 
 
60
  }
61
  }
src/config/feature-firewall.php CHANGED
@@ -320,7 +320,10 @@
320
  "appId",
321
  "/^et_.*/",
322
  "ping_sites",
323
- "aioseo-post-settings"
 
 
 
324
  ]
325
  },
326
  "firewall_patterns": {
320
  "appId",
321
  "/^et_.*/",
322
  "ping_sites",
323
+ "aioseo-post-settings",
324
+ "joe-chnlcustid",
325
+ "spd-custhash",
326
+ "joe-custinfo"
327
  ]
328
  },
329
  "firewall_patterns": {
src/config/feature-hack_protect.php CHANGED
@@ -21,8 +21,8 @@
21
  },
22
  "menu_items": [
23
  {
24
- "title": "Scans",
25
- "slug": "scans-redirect"
26
  }
27
  ],
28
  "custom_redirects": [
@@ -30,7 +30,7 @@
30
  "source_mod_page": "scans-redirect",
31
  "target_mod_page": "insights",
32
  "query_args": {
33
- "inav": "scans"
34
  }
35
  }
36
  ],
@@ -331,7 +331,9 @@
331
  "php.ini",
332
  "web.config",
333
  "php_mail.log",
334
- "mail.log"
 
 
335
  ],
336
  "type": "array",
337
  "link_info": "https://shsec.io/9z",
@@ -406,13 +408,12 @@
406
  }
407
  ],
408
  "definitions": {
409
- "db_classes": {
410
- "file_protect": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\FileLocker\\Handler",
411
- "filelocker": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\FileLocker\\Handler",
412
- "scanner": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Scanner\\Handler",
413
- "scanq": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\ScanQueue\\Handler"
414
  },
415
- "db_table_filelocker": {
416
  "slug": "filelocker",
417
  "has_updated_at": true,
418
  "cols_custom": {
@@ -428,7 +429,7 @@
428
  "notified_at": "Notification Sent"
429
  }
430
  },
431
- "db_table_scanner": {
432
  "slug": "scanner",
433
  "cols_custom": {
434
  "hash": "varchar(32) NOT NULL DEFAULT '' COMMENT 'Unique Item Hash'",
@@ -441,7 +442,7 @@
441
  "notified_at": "Scan Notifiation Sent"
442
  }
443
  },
444
- "db_table_scanq": {
445
  "slug": "scanq",
446
  "cols_custom": {
447
  "scan": "varchar(3) NOT NULL DEFAULT '' COMMENT 'Scan Slug'",
@@ -454,7 +455,7 @@
454
  "finished_at": "Scan Completed"
455
  }
456
  },
457
- "all_scan_slugs": [
458
  "apc",
459
  "mal",
460
  "ptg",
@@ -462,38 +463,27 @@
462
  "wcf",
463
  "ufc"
464
  ],
465
- "table_name_filelocker": "filelocker",
466
- "table_columns_filelocker": {
467
- "file": "varchar(256) NOT NULL COMMENT 'File Path relative to ABSPATH'",
468
- "hash_original": "varchar(40) NOT NULL COMMENT 'SHA1 File Hash Original'",
469
- "hash_current": "varchar(40) NOT NULL COMMENT 'SHA1 File Hash Current'",
470
- "content": "MEDIUMBLOB COMMENT 'Content'",
471
- "public_key_id": "TINYINT(2) UNSIGNED NOT NULL COMMENT 'Public Key ID'",
472
- "detected_at": "int(15) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'TS Change Last Detected'",
473
- "reverted_at": "int(15) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'TS Reverted To Backup'",
474
- "notified_at": "int(15) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'TS Notification Sent'",
475
- "updated_at": "int(15) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'TS Updated'"
476
- },
477
- "url_mal_sigs_simple": "https://raw.githubusercontent.com/scr34m/php-malware-scanner/master/definitions/patterns_raw.txt",
478
- "url_mal_sigs_regex": "https://raw.githubusercontent.com/scr34m/php-malware-scanner/master/definitions/patterns_re.txt",
479
- "malware_whitelist_paths": [
480
  "wp-content/wflogs/",
481
  "wp-content/cache/",
482
  "wp-content/icwp/rollback/"
483
  ],
484
- "cron_all_scans": "all-scans",
485
- "wcf_exclusions": [
486
  "readme.html",
487
  "license.txt",
488
  "licens-sv_SE.txt",
489
  "wp-config-sample.php",
490
  "wp-content/"
491
  ],
492
- "wcf_exclusions_missing_only": [
493
  "wp-admin/install.php",
494
  "xmlrpc.php"
495
  ],
496
- "events": {
497
  "apc_alert_sent": {
498
  },
499
  "mal_alert_sent": {
@@ -531,53 +521,65 @@
531
  "recent": true
532
  },
533
  "apc_scan_found": {
534
- "cat": 2,
535
- "recent": true
 
536
  },
537
  "mal_scan_found": {
538
- "cat": 3,
539
- "recent": true
 
540
  },
541
  "ptg_scan_found": {
542
- "cat": 3,
543
- "recent": true
 
544
  },
545
  "ufc_scan_found": {
546
- "cat": 3,
547
- "recent": true
 
548
  },
549
  "wcf_scan_found": {
550
- "cat": 3,
551
- "recent": true
 
552
  },
553
  "wpv_scan_found": {
554
- "cat": 3,
555
- "recent": true
 
556
  },
557
  "apc_item_repair_success": {
 
558
  },
559
  "apc_item_repair_fail": {
560
  },
561
  "mal_item_repair_success": {
562
- "recent": true
 
563
  },
564
  "mal_item_repair_fail": {
565
  },
566
  "ptg_item_repair_success": {
 
567
  },
568
  "ptg_item_repair_fail": {
569
  },
570
  "ufc_item_repair_success": {
571
- "recent": true
 
572
  },
573
  "ufc_item_repair_fail": {
574
  },
575
  "wcf_item_repair_success": {
576
- "recent": true
 
577
  },
578
  "wcf_item_repair_fail": {
579
  },
580
  "wpv_item_repair_success": {
 
581
  },
582
  "wpv_item_repair_fail": {
583
  }
21
  },
22
  "menu_items": [
23
  {
24
+ "title": "Scans",
25
+ "slug": "scans-redirect"
26
  }
27
  ],
28
  "custom_redirects": [
30
  "source_mod_page": "scans-redirect",
31
  "target_mod_page": "insights",
32
  "query_args": {
33
+ "inav": "scans_results"
34
  }
35
  }
36
  ],
331
  "php.ini",
332
  "web.config",
333
  "php_mail.log",
334
+ "mail.log",
335
+ "wp-content/uploads/bb-plugin/cache/",
336
+ "wp-content/uploads/cache/wpml/twig/"
337
  ],
338
  "type": "array",
339
  "link_info": "https://shsec.io/9z",
408
  }
409
  ],
410
  "definitions": {
411
+ "db_classes": {
412
+ "filelocker": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\FileLocker\\Handler",
413
+ "scanner": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Scanner\\Handler",
414
+ "scanq": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\ScanQueue\\Handler"
 
415
  },
416
+ "db_table_filelocker": {
417
  "slug": "filelocker",
418
  "has_updated_at": true,
419
  "cols_custom": {
429
  "notified_at": "Notification Sent"
430
  }
431
  },
432
+ "db_table_scanner": {
433
  "slug": "scanner",
434
  "cols_custom": {
435
  "hash": "varchar(32) NOT NULL DEFAULT '' COMMENT 'Unique Item Hash'",
442
  "notified_at": "Scan Notifiation Sent"
443
  }
444
  },
445
+ "db_table_scanq": {
446
  "slug": "scanq",
447
  "cols_custom": {
448
  "scan": "varchar(3) NOT NULL DEFAULT '' COMMENT 'Scan Slug'",
455
  "finished_at": "Scan Completed"
456
  }
457
  },
458
+ "all_scan_slugs": [
459
  "apc",
460
  "mal",
461
  "ptg",
463
  "wcf",
464
  "ufc"
465
  ],
466
+ "table_name_filelocker": "filelocker",
467
+ "url_mal_sigs_simple": "https://raw.githubusercontent.com/scr34m/php-malware-scanner/master/definitions/patterns_raw.txt",
468
+ "url_mal_sigs_regex": "https://raw.githubusercontent.com/scr34m/php-malware-scanner/master/definitions/patterns_re.txt",
469
+ "malware_whitelist_paths": [
 
 
 
 
 
 
 
 
 
 
 
470
  "wp-content/wflogs/",
471
  "wp-content/cache/",
472
  "wp-content/icwp/rollback/"
473
  ],
474
+ "cron_all_scans": "all-scans",
475
+ "wcf_exclusions": [
476
  "readme.html",
477
  "license.txt",
478
  "licens-sv_SE.txt",
479
  "wp-config-sample.php",
480
  "wp-content/"
481
  ],
482
+ "wcf_exclusions_missing_only": [
483
  "wp-admin/install.php",
484
  "xmlrpc.php"
485
  ],
486
+ "events": {
487
  "apc_alert_sent": {
488
  },
489
  "mal_alert_sent": {
521
  "recent": true
522
  },
523
  "apc_scan_found": {
524
+ "cat": 2,
525
+ "audit_multiple": true,
526
+ "recent": true
527
  },
528
  "mal_scan_found": {
529
+ "cat": 3,
530
+ "audit_multiple": true,
531
+ "recent": true
532
  },
533
  "ptg_scan_found": {
534
+ "cat": 3,
535
+ "audit_multiple": true,
536
+ "recent": true
537
  },
538
  "ufc_scan_found": {
539
+ "cat": 3,
540
+ "audit_multiple": true,
541
+ "recent": true
542
  },
543
  "wcf_scan_found": {
544
+ "cat": 3,
545
+ "audit_multiple": true,
546
+ "recent": true
547
  },
548
  "wpv_scan_found": {
549
+ "cat": 3,
550
+ "audit_multiple": true,
551
+ "recent": true
552
  },
553
  "apc_item_repair_success": {
554
+ "audit_multiple": true
555
  },
556
  "apc_item_repair_fail": {
557
  },
558
  "mal_item_repair_success": {
559
+ "audit_multiple": true,
560
+ "recent": true
561
  },
562
  "mal_item_repair_fail": {
563
  },
564
  "ptg_item_repair_success": {
565
+ "audit_multiple": true
566
  },
567
  "ptg_item_repair_fail": {
568
  },
569
  "ufc_item_repair_success": {
570
+ "audit_multiple": true,
571
+ "recent": true
572
  },
573
  "ufc_item_repair_fail": {
574
  },
575
  "wcf_item_repair_success": {
576
+ "audit_multiple": true,
577
+ "recent": true
578
  },
579
  "wcf_item_repair_fail": {
580
  },
581
  "wpv_item_repair_success": {
582
+ "audit_multiple": true
583
  },
584
  "wpv_item_repair_fail": {
585
  }
src/config/feature-headers.php CHANGED
@@ -186,7 +186,7 @@
186
  "link_blog": "",
187
  "name": "Manual Rules",
188
  "summary": "Manual CSP Rules",
189
- "description": "Manual CSP rules which are not covered by the rules above."
190
  }
191
  ]
192
  }
186
  "link_blog": "",
187
  "name": "Manual Rules",
188
  "summary": "Manual CSP Rules",
189
+ "description": "Manual CSP rules."
190
  }
191
  ]
192
  }
src/config/feature-ips.php CHANGED
@@ -551,22 +551,9 @@
551
  "definitions": {
552
  "db_classes": {
553
  "botsignals": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\BotSignals\\Handler",
554
- "ip_lists": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\IPs\\Handler",
555
- "ips": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\IPs\\Handler"
556
  },
557
  "ip_lists_table_name": "ip_lists",
558
- "ip_list_table_columns": {
559
- "ip": "varchar(60) NOT NULL DEFAULT '' COMMENT 'Human readable IP address or range'",
560
- "label": "varchar(255) NOT NULL DEFAULT '' COMMENT 'Description'",
561
- "list": "varchar(4) NOT NULL DEFAULT '' COMMENT 'Block or Bypass'",
562
- "ip6": "tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Is IPv6'",
563
- "is_range": "tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Is Range'",
564
- "transgressions": "int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Total Offenses'"
565
- },
566
- "ip_list_table_timestamp_columns": {
567
- "last_access_at": "Last Access By IP",
568
- "blocked_at": "IP Blocked"
569
- },
570
  "db_table_ip_lists": {
571
  "slug": "ip_lists",
572
  "cols_custom": {
551
  "definitions": {
552
  "db_classes": {
553
  "botsignals": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\BotSignals\\Handler",
554
+ "ip_lists": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\IPs\\Handler"
 
555
  },
556
  "ip_lists_table_name": "ip_lists",
 
 
 
 
 
 
 
 
 
 
 
 
557
  "db_table_ip_lists": {
558
  "slug": "ip_lists",
559
  "cols_custom": {
src/config/feature-login_protect.php CHANGED
@@ -501,18 +501,15 @@
501
  "2fa_email_send_fail": {
502
  },
503
  "cooldown_fail": {
504
- "offense": true
505
  },
506
  "honeypot_fail": {
507
- "offense": true
508
  },
509
  "botbox_fail": {
510
- "offense": true
511
  },
512
  "login_block": {
513
  "audit": false,
514
  "recent": true,
515
- "offense": false
516
  },
517
  "hide_login_url": {
518
  "audit": false
501
  "2fa_email_send_fail": {
502
  },
503
  "cooldown_fail": {
 
504
  },
505
  "honeypot_fail": {
 
506
  },
507
  "botbox_fail": {
 
508
  },
509
  "login_block": {
510
  "audit": false,
511
  "recent": true,
512
+ "offense": true
513
  },
514
  "hide_login_url": {
515
  "audit": false
src/config/feature-plugin.php CHANGED
@@ -246,17 +246,6 @@
246
  "summary": "Display Plugin Specific Notices",
247
  "description": "Disable this option to hide certain plugin admin notices about available updates and post-update notices."
248
  },
249
- {
250
- "key": "display_plugin_badge",
251
- "section": "section_general_plugin_options",
252
- "default": "N",
253
- "type": "checkbox",
254
- "link_info": "https://shsec.io/5v",
255
- "link_blog": "https://shsec.io/wpsf20",
256
- "name": "Show Plugin Badge",
257
- "summary": "Display Plugin Badge On Your Site",
258
- "description": "Enabling this option helps support the plugin by spreading the word about it on your website. The plugin badge also demonstrates to visitors that you take your website security seriously."
259
- },
260
  {
261
  "key": "enable_wpcli",
262
  "section": "section_general_plugin_options",
@@ -270,6 +259,17 @@
270
  "summary": "Allow Access And Control Of This Plugin Via WP-CLI",
271
  "description": "Turn off this option to disable this plugin's WP-CLI integration."
272
  },
 
 
 
 
 
 
 
 
 
 
 
273
  {
274
  "key": "enable_xmlrpc_compatibility",
275
  "section": "section_defaults",
@@ -529,7 +529,6 @@
529
  }
530
  ],
531
  "definitions": {
532
- "survey_email": "c3VwcG9ydEBvbmVkb2xsYXJwbHVnaW4uY29t",
533
  "help_video_id": "",
534
  "tracking_cron_handle": "plugin_tracking_cron",
535
  "tracking_post_url": "https://tracking.icontrolwp.com/track/plugin/shield",
@@ -668,8 +667,7 @@
668
  "audit": false
669
  },
670
  "recaptcha_fail": {
671
- "offense": false,
672
- "audit": true
673
  },
674
  "antibot_pass": {
675
  "stat": true,
246
  "summary": "Display Plugin Specific Notices",
247
  "description": "Disable this option to hide certain plugin admin notices about available updates and post-update notices."
248
  },
 
 
 
 
 
 
 
 
 
 
 
249
  {
250
  "key": "enable_wpcli",
251
  "section": "section_general_plugin_options",
259
  "summary": "Allow Access And Control Of This Plugin Via WP-CLI",
260
  "description": "Turn off this option to disable this plugin's WP-CLI integration."
261
  },
262
+ {
263
+ "key": "display_plugin_badge",
264
+ "section": "section_general_plugin_options",
265
+ "default": "N",
266
+ "type": "checkbox",
267
+ "link_info": "https://shsec.io/5v",
268
+ "link_blog": "https://shsec.io/wpsf20",
269
+ "name": "Show Plugin Badge",
270
+ "summary": "Display Plugin Badge On Your Site",
271
+ "description": "Enabling this option helps support the plugin by spreading the word about it on your website. The plugin badge also demonstrates to visitors that you take your website security seriously."
272
+ },
273
  {
274
  "key": "enable_xmlrpc_compatibility",
275
  "section": "section_defaults",
529
  }
530
  ],
531
  "definitions": {
 
532
  "help_video_id": "",
533
  "tracking_cron_handle": "plugin_tracking_cron",
534
  "tracking_post_url": "https://tracking.icontrolwp.com/track/plugin/shield",
667
  "audit": false
668
  },
669
  "recaptcha_fail": {
670
+ "audit": true
 
671
  },
672
  "antibot_pass": {
673
  "stat": true,
src/config/feature-sessions.php CHANGED
@@ -56,23 +56,9 @@
56
  ],
57
  "definitions": {
58
  "db_classes": {
59
- "sessions": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Session\\Handler",
60
- "session": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Session\\Handler"
61
  },
62
  "sessions_table_name": "sessions",
63
- "sessions_table_columns": {
64
- "session_id": "varchar(32) NOT NULL DEFAULT ''",
65
- "wp_username": "varchar(255) NOT NULL DEFAULT ''",
66
- "ip": "varchar(60) NOT NULL DEFAULT '0'",
67
- "browser": "varchar(32) NOT NULL DEFAULT ''",
68
- "last_activity_uri": "text NOT NULL DEFAULT ''"
69
- },
70
- "sessions_table_timestamp_columns": {
71
- "logged_in_at": "Session Started",
72
- "last_activity_at": "Last Seen At",
73
- "login_intent_expires_at": "2FA Window Expires",
74
- "secadmin_at": "Security Admin Authenticated"
75
- },
76
  "db_table_sessions": {
77
  "slug": "sessions",
78
  "cols_custom": {
56
  ],
57
  "definitions": {
58
  "db_classes": {
59
+ "sessions": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Session\\Handler"
 
60
  },
61
  "sessions_table_name": "sessions",
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  "db_table_sessions": {
63
  "slug": "sessions",
64
  "cols_custom": {
src/config/feature-traffic.php CHANGED
@@ -231,16 +231,6 @@
231
  }
232
  },
233
  "traffic_table_name": "traffic",
234
- "traffic_table_columns": {
235
- "rid": "varchar(10) NOT NULL DEFAULT '' COMMENT 'Request ID'",
236
- "uid": "int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'User ID'",
237
- "ip": "varbinary(16) DEFAULT NULL COMMENT 'Visitor IP Address'",
238
- "path": "text NOT NULL DEFAULT '' COMMENT 'Request Path or URI'",
239
- "code": "int(5) NOT NULL DEFAULT '200' COMMENT 'HTTP Response Code'",
240
- "verb": "varchar(10) NOT NULL DEFAULT 'get' COMMENT 'HTTP Method'",
241
- "ua": "text COMMENT 'Browser User Agent String'",
242
- "trans": "tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Trangression'"
243
- },
244
  "events": {
245
  "request_limit_exceeded": {
246
  "cat": 3,
231
  }
232
  },
233
  "traffic_table_name": "traffic",
 
 
 
 
 
 
 
 
 
 
234
  "events": {
235
  "request_limit_exceeded": {
236
  "cat": 3,
src/lib/src/Controller/Config/ConfigVO.php CHANGED
@@ -66,13 +66,4 @@ class ConfigVO extends DynPropertiesClass {
66
 
67
  return $val;
68
  }
69
-
70
- /**
71
- * @param $key
72
- * @return mixed|null
73
- * @deprecated 10.3
74
- */
75
- private function __adapterGet( $key ) {
76
- return $this->getRawData()[ $key ] ?? null;
77
- }
78
  }
66
 
67
  return $val;
68
  }
 
 
 
 
 
 
 
 
 
69
  }
src/lib/src/Controller/Controller.php CHANGED
@@ -26,6 +26,7 @@ use FernleafSystems\Wordpress\Services\Utilities\Options\Transient;
26
  * @property string $base_file
27
  * @property string $root_file
28
  * @property bool $is_my_upgrade
 
29
  * @property bool $user_can_base_permissions
30
  * @property Shield\Modules\Events\Lib\EventsService $service_events
31
  * @property mixed[]|Shield\Modules\Base\ModCon[] $modules
@@ -178,6 +179,14 @@ class Controller extends DynPropertiesClass {
178
  }
179
  break;
180
 
 
 
 
 
 
 
 
 
181
  default:
182
  break;
183
  }
@@ -185,15 +194,6 @@ class Controller extends DynPropertiesClass {
185
  return $val;
186
  }
187
 
188
- /**
189
- * @param $key
190
- * @return mixed|null
191
- * @deprecated 10.3
192
- */
193
- private function __adapterGet( $key ) {
194
- return $this->getRawData()[ $key ] ?? null;
195
- }
196
-
197
  /**
198
  * @throws \Exception
199
  */
@@ -454,11 +454,26 @@ class Controller extends DynPropertiesClass {
454
  if ( $this->isModulePage() ) {
455
  add_filter( 'nocache_headers', [ $this, 'adjustNocacheHeaders' ] );
456
  }
 
457
  ( new Ajax\Init() )
458
  ->setCon( $this )
459
  ->execute();
460
  }
461
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
462
  /**
463
  * Only set to rebuild as required if you're doing so at the same point in the WordPress load each time.
464
  * Certain plugins can modify the ID at different points in the load.
@@ -871,17 +886,6 @@ class Controller extends DynPropertiesClass {
871
  return $this->cfg;
872
  }
873
 
874
- /**
875
- * @return array
876
- * @deprecated 10.2
877
- */
878
- public function getPluginSpec() {
879
- if ( isset( $this->cfg ) ) {
880
- return $this->cfg->getRawData();
881
- }
882
- return $this->getPluginControllerOptions()->plugin_spec;
883
- }
884
-
885
  /**
886
  * @param string $key
887
  * @return string|null
@@ -998,18 +1002,8 @@ class Controller extends DynPropertiesClass {
998
  return add_query_arg( [ 'ver' => $this->getVersion() ], plugins_url( $path, $this->getRootFile() ) );
999
  }
1000
 
1001
- /**
1002
- * @deprecated 10.2
1003
- */
1004
- public function getPluginUrl_Image( string $asset ) :string {
1005
- return $this->urls->forImage( $asset );
1006
- }
1007
-
1008
- /**
1009
- * @deprecated 10.3
1010
- */
1011
- public function getPluginUrl_Js( string $asset ) :string {
1012
- return $this->urls->forJs( $asset );
1013
  }
1014
 
1015
  public function getPluginUrl_AdminMainPage() :string {
@@ -1021,33 +1015,6 @@ class Controller extends DynPropertiesClass {
1021
  return empty( $asset ) ? $base : path_join( $base, ltrim( $asset, '/' ) );
1022
  }
1023
 
1024
- /**
1025
- * @param string $flag
1026
- * @return string
1027
- * @deprecated 10.3
1028
- */
1029
- public function getPath_Flags( string $flag = '' ) :string {
1030
- if ( isset( $this->paths ) ) {
1031
- return $this->paths->forFlag( $flag );
1032
- }
1033
- $base = path_join( $this->getRootDir(), $this->getPluginSpec_Path( 'flags' ) );
1034
- return empty( $flag ) ? $base : path_join( $base, $flag );
1035
- }
1036
-
1037
- /**
1038
- * @param string $sTmpFile
1039
- * @return string
1040
- */
1041
- public function getPath_Temp( $sTmpFile = '' ) {
1042
- $sTempPath = null;
1043
-
1044
- $sBase = path_join( $this->getRootDir(), $this->getPluginSpec_Path( 'temp' ) );
1045
- if ( Services::WpFs()->mkdir( $sBase ) ) {
1046
- $sTempPath = $sBase;
1047
- }
1048
- return empty( $sTmpFile ) ? $sTempPath : path_join( $sTempPath, $sTmpFile );
1049
- }
1050
-
1051
  public function getPath_AssetCss( string $asset = '' ) :string {
1052
  return $this->getPath_Assets( 'css/'.$asset );
1053
  }
@@ -1160,6 +1127,11 @@ class Controller extends DynPropertiesClass {
1160
  return empty( $action ) ? '' : $action;
1161
  }
1162
 
 
 
 
 
 
1163
  /**
1164
  * @return \stdClass
1165
  */
26
  * @property string $base_file
27
  * @property string $root_file
28
  * @property bool $is_my_upgrade
29
+ * @property Shield\Utilities\Nonce\Handler $nonce_handler
30
  * @property bool $user_can_base_permissions
31
  * @property Shield\Modules\Events\Lib\EventsService $service_events
32
  * @property mixed[]|Shield\Modules\Base\ModCon[] $modules
179
  }
180
  break;
181
 
182
+ case 'nonce_handler':
183
+ if ( is_null( $val ) ) {
184
+ $val = ( new Shield\Utilities\Nonce\Handler() )
185
+ ->setCon( $this );
186
+ $this->nonce_handler = $val;
187
+ }
188
+ break;
189
+
190
  default:
191
  break;
192
  }
194
  return $val;
195
  }
196
 
 
 
 
 
 
 
 
 
 
197
  /**
198
  * @throws \Exception
199
  */
454
  if ( $this->isModulePage() ) {
455
  add_filter( 'nocache_headers', [ $this, 'adjustNocacheHeaders' ] );
456
  }
457
+ $this->processShieldNonceActions();
458
  ( new Ajax\Init() )
459
  ->setCon( $this )
460
  ->execute();
461
  }
462
 
463
+ private function processShieldNonceActions() {
464
+ $shieldNonceAction = $this->getShieldNonceAction();
465
+ $shieldNonce = Services::Request()->request( 'shield_nonce' );
466
+ if ( !empty( $shieldNonceAction ) && !empty( $shieldNonce ) ) {
467
+ $shieldNonce = Services::Request()->request( 'shield_nonce' );
468
+ if ( $this->nonce_handler->verify( $shieldNonceAction, $shieldNonce ) ) {
469
+ do_action( $this->prefix( 'shield_nonce_action' ), $shieldNonceAction );
470
+ }
471
+ else {
472
+ wp_die( 'It appears that this action and nonce has expired. Please retry the action.' );
473
+ }
474
+ }
475
+ }
476
+
477
  /**
478
  * Only set to rebuild as required if you're doing so at the same point in the WordPress load each time.
479
  * Certain plugins can modify the ID at different points in the load.
886
  return $this->cfg;
887
  }
888
 
 
 
 
 
 
 
 
 
 
 
 
889
  /**
890
  * @param string $key
891
  * @return string|null
1002
  return add_query_arg( [ 'ver' => $this->getVersion() ], plugins_url( $path, $this->getRootFile() ) );
1003
  }
1004
 
1005
+ public function getPluginUrl_DashboardHome() :string {
1006
+ return $this->getModule_Insights()->getUrl_SubInsightsPage( 'overview' );
 
 
 
 
 
 
 
 
 
 
1007
  }
1008
 
1009
  public function getPluginUrl_AdminMainPage() :string {
1015
  return empty( $asset ) ? $base : path_join( $base, ltrim( $asset, '/' ) );
1016
  }
1017
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1018
  public function getPath_AssetCss( string $asset = '' ) :string {
1019
  return $this->getPath_Assets( 'css/'.$asset );
1020
  }
1127
  return empty( $action ) ? '' : $action;
1128
  }
1129
 
1130
+ public function getShieldNonceAction() :string {
1131
+ $action = sanitize_key( Services::Request()->query( 'shield_nonce_action', '' ) );
1132
+ return empty( $action ) ? '' : $action;
1133
+ }
1134
+
1135
  /**
1136
  * @return \stdClass
1137
  */
src/lib/src/Databases/AuditTrail/Handler.php CHANGED
@@ -14,15 +14,11 @@ class Handler extends Base\Handler {
14
  $this->tableTrimExcess( $opts->getMaxEntries() );
15
  }
16
 
17
- public function getCustomColumns() :array {
18
- return $this->getOptions()->getDef( 'audit_trail_table_columns' );
19
- }
20
-
21
  protected function getDefaultTableName() :string {
22
  return $this->getOptions()->getDef( 'audit_trail_table_name' );
23
  }
24
-
25
- protected function getTimestampColumns() :array {
26
- return $this->getOptions()->getDef( 'audittrail_table_timestamp_columns' );
27
- }
28
  }
14
  $this->tableTrimExcess( $opts->getMaxEntries() );
15
  }
16
 
17
+ /**
18
+ * @return string
19
+ * @deprecated 11.1
20
+ */
21
  protected function getDefaultTableName() :string {
22
  return $this->getOptions()->getDef( 'audit_trail_table_name' );
23
  }
 
 
 
 
24
  }
src/lib/src/Databases/Base/BaseQuery.php CHANGED
@@ -408,7 +408,7 @@ abstract class BaseQuery {
408
  if ( empty( $sGroupByColumn ) ) {
409
  $this->sGroupBy = '';
410
  }
411
- elseif ( $this->getDbH()->hasColumn( $sGroupByColumn ) ) {
412
  $this->sGroupBy = $sGroupByColumn;
413
  }
414
  return $this;
408
  if ( empty( $sGroupByColumn ) ) {
409
  $this->sGroupBy = '';
410
  }
411
+ elseif ( $this->getDbH()->getTableSchema()->hasColumn( $sGroupByColumn ) ) {
412
  $this->sGroupBy = $sGroupByColumn;
413
  }
414
  return $this;
src/lib/src/Databases/Base/Handler.php CHANGED
@@ -71,32 +71,22 @@ abstract class Handler {
71
  private function setupTableSchema() :TableSchema {
72
  $this->schema = new TableSchema();
73
 
74
- $spec = $this->getOptions()->getDef( 'db_table_'.$this->slug );
75
-
76
- if ( empty( $spec ) ) {
77
- $this->schema->slug = $this->slug;
78
- $this->schema->primary_key = 'id';
79
- $this->schema->cols_custom = $this->getCustomColumns();
80
- $this->schema->cols_timestamps = $this->getTimestampColumns();
81
- $this->schema->autoexpire = 0;
82
- }
83
- else {
84
- $this->schema->applyFromArray( array_merge(
85
- [
86
- 'slug' => $this->slug,
87
- 'primary_key' => 'id',
88
- 'cols_custom' => [],
89
- 'cols_timestamps' => [],
90
- 'has_updated_at' => false,
91
- 'col_older_than' => 'created_at',
92
- 'autoexpire' => 0,
93
- 'has_ip_col' => false,
94
- ],
95
- $spec
96
- ) );
97
- }
98
 
99
  $this->schema->table = $this->getTable();
 
100
  return $this->schema;
101
  }
102
 
@@ -126,15 +116,7 @@ abstract class Handler {
126
 
127
  public function getTable() :string {
128
  return Services::WpDb()->getPrefix()
129
- .esc_sql( $this->getCon()->prefixOption( $this->getDefaultTableName() ) );
130
- }
131
-
132
- /**
133
- * @return string
134
- * @deprecated 10.3
135
- */
136
- protected function getTableSlug() {
137
- return empty( $this->sTable ) ? $this->getDefaultTableName() : $this->sTable;
138
  }
139
 
140
  /**
@@ -194,15 +176,6 @@ abstract class Handler {
194
  return new $class();
195
  }
196
 
197
- /**
198
- * @param string $col
199
- * @return bool
200
- * @deprecated 10.3 - moved to schema
201
- */
202
- public function hasColumn( string $col ) :bool {
203
- return in_array( strtolower( $col ), $this->getTableSchema()->getColumnNames() );
204
- }
205
-
206
  /**
207
  * @return $this
208
  * @throws \Exception
@@ -261,35 +234,15 @@ abstract class Handler {
261
  return $this->bIsReady;
262
  }
263
 
264
- protected function getDefaultTableName() :string {
265
- return $this->getTableSchema()->slug;
266
- }
267
-
268
- /**
269
- * @return string[]
270
- * @deprecated 10.3
271
- */
272
- protected function getCustomColumns() :array {
273
- return [];
274
- }
275
-
276
  /**
277
- * @return string[]
278
- * @deprecated 10.3
279
  */
280
- protected function getTimestampColumns() :array {
281
- return [];
282
  }
283
 
284
  public function getTableSchema() :TableSchema {
285
- if ( empty( $this->schema ) ) { // TODO: Delete empty test after 10.3
286
- $sch = new TableSchema();
287
- $sch->table = $this->getTable();
288
- $sch->col_older_than = 'created_at';
289
- $sch->cols_custom = $this->getCustomColumns();
290
- $sch->cols_timestamps = $this->getTimestampColumns();
291
- return $sch;
292
- }
293
  return $this->schema;
294
  }
295
 
71
  private function setupTableSchema() :TableSchema {
72
  $this->schema = new TableSchema();
73
 
74
+ $this->schema->applyFromArray( array_merge(
75
+ [
76
+ 'slug' => $this->slug,
77
+ 'primary_key' => 'id',
78
+ 'cols_custom' => [],
79
+ 'cols_timestamps' => [],
80
+ 'has_updated_at' => false,
81
+ 'col_older_than' => 'created_at',
82
+ 'autoexpire' => 0,
83
+ 'has_ip_col' => false,
84
+ ],
85
+ $this->getOptions()->getDef( 'db_table_'.$this->slug )
86
+ ) );
 
 
 
 
 
 
 
 
 
 
 
87
 
88
  $this->schema->table = $this->getTable();
89
+
90
  return $this->schema;
91
  }
92
 
116
 
117
  public function getTable() :string {
118
  return Services::WpDb()->getPrefix()
119
+ .esc_sql( $this->getCon()->prefixOption( $this->getTableSchema()->slug ) );
 
 
 
 
 
 
 
 
120
  }
121
 
122
  /**
176
  return new $class();
177
  }
178
 
 
 
 
 
 
 
 
 
 
179
  /**
180
  * @return $this
181
  * @throws \Exception
234
  return $this->bIsReady;
235
  }
236
 
 
 
 
 
 
 
 
 
 
 
 
 
237
  /**
238
+ * @return string
239
+ * @deprecated 11.1
240
  */
241
+ protected function getDefaultTableName() :string {
242
+ return $this->getTableSchema()->slug;
243
  }
244
 
245
  public function getTableSchema() :TableSchema {
 
 
 
 
 
 
 
 
246
  return $this->schema;
247
  }
248
 
src/lib/src/Databases/Base/Insert.php CHANGED
@@ -23,9 +23,7 @@ class Insert extends BaseQuery {
23
  * @return bool
24
  */
25
  public function insert( $entry ) :bool {
26
- // @deprecated 10.3- get rid of casting after moving filelockerVO to normal VO
27
- $data = (array)$entry->getRawData();
28
- return $this->setInsertData( $data )->query() === 1;
29
  }
30
 
31
  /**
@@ -47,7 +45,7 @@ class Insert extends BaseQuery {
47
  */
48
  protected function verifyInsertData() {
49
  $baseData = [ 'created_at' => Services::Request()->ts() ];
50
- if ( $this->getDbH()->hasColumn( 'updated_at' ) ) {
51
  $baseData[ 'updated_at' ] = Services::Request()->ts();
52
  }
53
  return $this->setInsertData( array_merge( $baseData, $this->getInsertData() ) );
23
  * @return bool
24
  */
25
  public function insert( $entry ) :bool {
26
+ return $this->setInsertData( $entry->getRawData() )->query() === 1;
 
 
27
  }
28
 
29
  /**
45
  */
46
  protected function verifyInsertData() {
47
  $baseData = [ 'created_at' => Services::Request()->ts() ];
48
+ if ( $this->getDbH()->getTableSchema()->hasColumn( 'updated_at' ) ) {
49
  $baseData[ 'updated_at' ] = Services::Request()->ts();
50
  }
51
  return $this->setInsertData( array_merge( $baseData, $this->getInsertData() ) );
src/lib/src/Databases/Base/Select.php CHANGED
@@ -14,7 +14,7 @@ class Select extends BaseQuery {
14
  /**
15
  * @var bool
16
  */
17
- protected $bIsCount = false;
18
 
19
  /**
20
  * @var bool
@@ -85,19 +85,19 @@ class Select extends BaseQuery {
85
  * @return string
86
  */
87
  protected function buildSelect() {
88
- $aCols = $this->getColumnsToSelect();
89
 
90
  if ( $this->isCount() ) {
91
  $sSubstitute = 'COUNT(*)';
92
  }
93
  elseif ( $this->isSum() ) {
94
- $sSubstitute = sprintf( 'SUM(%s)', array_shift( $aCols ) );
95
  }
96
  elseif ( $this->isDistinct() && $this->hasColumnsToSelect() ) {
97
- $sSubstitute = sprintf( 'DISTINCT %s', implode( ',', $aCols ) );
98
  }
99
  elseif ( $this->hasColumnsToSelect() ) {
100
- $sSubstitute = implode( ',', $aCols );
101
  }
102
  elseif ( $this->isCustomSelect() ) {
103
  $sSubstitute = $this->sCustomSelect;
@@ -108,6 +108,10 @@ class Select extends BaseQuery {
108
  return $sSubstitute;
109
  }
110
 
 
 
 
 
111
  public function count() :int {
112
  return (int)$this->setIsCount( true )->query();
113
  }
@@ -163,7 +167,7 @@ class Select extends BaseQuery {
163
  }
164
 
165
  public function isCount() :bool {
166
- return (bool)$this->bIsCount;
167
  }
168
 
169
  public function isSum() :bool {
@@ -286,7 +290,7 @@ class Select extends BaseQuery {
286
  }
287
 
288
  public function setIsCount( bool $isCount ) :self {
289
- $this->bIsCount = $isCount;
290
  return $this;
291
  }
292
 
14
  /**
15
  * @var bool
16
  */
17
+ protected $isCount = false;
18
 
19
  /**
20
  * @var bool
85
  * @return string
86
  */
87
  protected function buildSelect() {
88
+ $cols = $this->getColumnsToSelect();
89
 
90
  if ( $this->isCount() ) {
91
  $sSubstitute = 'COUNT(*)';
92
  }
93
  elseif ( $this->isSum() ) {
94
+ $sSubstitute = sprintf( 'SUM(%s)', array_shift( $cols ) );
95
  }
96
  elseif ( $this->isDistinct() && $this->hasColumnsToSelect() ) {
97
+ $sSubstitute = sprintf( 'DISTINCT %s', implode( ',', $cols ) );
98
  }
99
  elseif ( $this->hasColumnsToSelect() ) {
100
+ $sSubstitute = implode( ',', $cols );
101
  }
102
  elseif ( $this->isCustomSelect() ) {
103
  $sSubstitute = $this->sCustomSelect;
108
  return $sSubstitute;
109
  }
110
 
111
+ public function sumColumn() :int {
112
+ return (int)$this->setIsCount( true )->query();
113
+ }
114
+
115
  public function count() :int {
116
  return (int)$this->setIsCount( true )->query();
117
  }
167
  }
168
 
169
  public function isCount() :bool {
170
+ return (bool)$this->isCount;
171
  }
172
 
173
  public function isSum() :bool {
290
  }
291
 
292
  public function setIsCount( bool $isCount ) :self {
293
+ $this->isCount = $isCount;
294
  return $this;
295
  }
296
 
src/lib/src/Databases/Base/Update.php CHANGED
@@ -71,7 +71,7 @@ class Update extends Insert {
71
  $success = true;
72
  }
73
  else {
74
- if ( $this->getDbH()->hasColumn( 'updated_at' ) && !isset( $updateData[ 'updated_at' ] ) ) {
75
  $updateData[ 'updated_at' ] = Services::Request()->ts();
76
  }
77
  if ( $this->updateById( $entry->id, $updateData ) ) {
71
  $success = true;
72
  }
73
  else {
74
+ if ( $this->getDbH()->getTableSchema()->hasColumn( 'updated_at' ) && !isset( $updateData[ 'updated_at' ] ) ) {
75
  $updateData[ 'updated_at' ] = Services::Request()->ts();
76
  }
77
  if ( $this->updateById( $entry->id, $updateData ) ) {
src/lib/src/Databases/ChangeTracking/Handler.php CHANGED
@@ -3,31 +3,7 @@
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\ChangeTracking;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
6
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\Options;
7
 
8
  class Handler extends Base\Handler {
9
 
10
- /**
11
- * @return string[]
12
- */
13
- public function getColumns() :array {
14
- return $this->getOptions()->getDef( 'table_columns_changetracking' );
15
- }
16
-
17
- protected function getDefaultTableName() :string {
18
- /** @var Options $opts */
19
- $opts = $this->getOptions();
20
- return $opts->getDbTable_ChangeTracking();
21
- }
22
-
23
- protected function getDefaultCreateTableSql() :string {
24
- return "CREATE TABLE %s (
25
- id int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
26
- data BLOB NOT NULL DEFAULT '' COMMENT 'Snapshot Data',
27
- meta TEXT NOT NULL DEFAULT '' COMMENT 'Snapshot Meta',
28
- created_at int(15) UNSIGNED NOT NULL DEFAULT 0,
29
- deleted_at int(15) UNSIGNED NOT NULL DEFAULT 0,
30
- PRIMARY KEY (id)
31
- ) %s;";
32
- }
33
  }
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\ChangeTracking;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
 
6
 
7
  class Handler extends Base\Handler {
8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  }
src/lib/src/Databases/Common/TableSchema.php CHANGED
@@ -70,7 +70,7 @@ class TableSchema extends DynPropertiesClass {
70
  return array_merge(
71
  $this->getColumn_ID(),
72
  $this->cols_custom ?? [],
73
- method_exists( $this, 'getColumns_Timestamps' ) ? $this->getColumns_Timestamps() : $this->getColumnns_Timestamps()
74
  );
75
  }
76
 
@@ -111,35 +111,6 @@ class TableSchema extends DynPropertiesClass {
111
  );
112
  }
113
 
114
- /**
115
- * @return string[]
116
- * @deprecated 10.3
117
- */
118
- protected function getColumnns_Timestamps() :array {
119
-
120
- $standardTsCols = [
121
- 'created_at' => 'Created At',
122
- 'deleted_at' => 'Soft Deleted At',
123
- ];
124
-
125
- if ( $this->has_updated_at && !array_key_exists( 'updated_at', $this->cols_timestamps ) ) {
126
- $standardTsCols = array_merge(
127
- [ 'updated_at' => 'Updated At', ],
128
- $standardTsCols
129
- );
130
- }
131
-
132
- return array_map(
133
- function ( $comment ) {
134
- return $this->getTimestampColDef( $comment );
135
- },
136
- array_merge(
137
- $this->cols_timestamps ?? [],
138
- $standardTsCols
139
- )
140
- );
141
- }
142
-
143
  protected function getPrimaryKeyDef() :string {
144
  return sprintf( 'PRIMARY KEY (%s)', $this->getPrimaryKeyColumnName() );
145
  }
70
  return array_merge(
71
  $this->getColumn_ID(),
72
  $this->cols_custom ?? [],
73
+ $this->getColumns_Timestamps()
74
  );
75
  }
76
 
111
  );
112
  }
113
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  protected function getPrimaryKeyDef() :string {
115
  return sprintf( 'PRIMARY KEY (%s)', $this->getPrimaryKeyColumnName() );
116
  }
src/lib/src/Databases/Events/Handler.php CHANGED
@@ -37,10 +37,10 @@ class Handler extends Base\Handler {
37
  return $QI->insert( $oEvt );
38
  }
39
 
40
- public function getCustomColumns() :array {
41
- return $this->getOptions()->getDef( 'events_table_columns' );
42
- }
43
-
44
  protected function getDefaultTableName() :string {
45
  return $this->getOptions()->getDef( 'events_table_name' );
46
  }
37
  return $QI->insert( $oEvt );
38
  }
39
 
40
+ /**
41
+ * @return string
42
+ * @deprecated 11.1
43
+ */
44
  protected function getDefaultTableName() :string {
45
  return $this->getOptions()->getDef( 'events_table_name' );
46
  }
src/lib/src/Databases/Events/Select.php CHANGED
@@ -9,11 +9,11 @@ class Select extends Base\Select {
9
  use Common;
10
 
11
  /**
12
- * @param string $sEvent
13
  * @return int
14
  */
15
- public function sumEvent( $sEvent ) {
16
- return $this->sumEvents( [ $sEvent ] );
17
  }
18
 
19
  /**
@@ -77,7 +77,7 @@ class Select extends Base\Select {
77
  /**
78
  * @return string[]
79
  */
80
- public function getAllEvents() {
81
  return $this->reset()->getDistinctForColumn( 'event' );
82
  }
83
 
9
  use Common;
10
 
11
  /**
12
+ * @param string $event
13
  * @return int
14
  */
15
+ public function sumEvent( $event ) :int {
16
+ return $this->sumEvents( [ $event ] );
17
  }
18
 
19
  /**
77
  /**
78
  * @return string[]
79
  */
80
+ public function getAllEvents() :array {
81
  return $this->reset()->getDistinctForColumn( 'event' );
82
  }
83
 
src/lib/src/Databases/FileLocker/Handler.php CHANGED
@@ -6,10 +6,10 @@ use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
6
 
7
  class Handler extends Base\Handler {
8
 
9
- public function getCustomColumns() :array {
10
- return $this->getOptions()->getDef( 'table_columns_filelocker' );
11
- }
12
-
13
  protected function getDefaultTableName() :string {
14
  return $this->getOptions()->getDef( 'table_name_filelocker' );
15
  }
6
 
7
  class Handler extends Base\Handler {
8
 
9
+ /**
10
+ * @return string
11
+ * @deprecated 11.1
12
+ */
13
  protected function getDefaultTableName() :string {
14
  return $this->getOptions()->getDef( 'table_name_filelocker' );
15
  }
src/lib/src/Databases/IPs/Handler.php CHANGED
@@ -31,26 +31,10 @@ class Handler extends Base\Handler {
31
  }
32
 
33
  /**
34
- * @return string[]
35
- * @deprecated 10.3
36
- */
37
- protected function getCustomColumns() :array {
38
- return $this->getOptions()->getDef( 'ip_list_table_columns' );
39
- }
40
-
41
- /**
42
- * @return string[]
43
- * @deprecated 10.3
44
  */
45
  protected function getDefaultTableName() :string {
46
  return $this->getOptions()->getDef( 'ip_lists_table_name' );
47
  }
48
-
49
- /**
50
- * @return string[]
51
- * @deprecated 10.3
52
- */
53
- protected function getTimestampColumns() :array {
54
- return $this->getOptions()->getDef( 'ip_list_table_timestamp_columns' );
55
- }
56
  }
31
  }
32
 
33
  /**
34
+ * @return string
35
+ * @deprecated 11.1
 
 
 
 
 
 
 
 
36
  */
37
  protected function getDefaultTableName() :string {
38
  return $this->getOptions()->getDef( 'ip_lists_table_name' );
39
  }
 
 
 
 
 
 
 
 
40
  }
src/lib/src/Databases/ScanQueue/Select.php CHANGED
@@ -36,21 +36,17 @@ class Select extends Base\Select {
36
  ->setColumnsToSelect( [ 'scan' ] )
37
  ->filterByNotFinished()
38
  ->query();
39
- $aScans = [];
40
- /** @var EntryVO $oEntry */
41
- foreach ( $aResults as $oEntry ) {
42
- $aScans[ $oEntry->scan ] = 1;
43
  }
44
- return array_keys( $aScans );
45
  }
46
 
47
- /**
48
- * @param string $sScan
49
- * @return int
50
- */
51
- public function countForScan( $sScan ) {
52
  return $this->reset()
53
- ->filterByScan( $sScan )
54
  ->count();
55
  }
56
  }
36
  ->setColumnsToSelect( [ 'scan' ] )
37
  ->filterByNotFinished()
38
  ->query();
39
+ $scans = [];
40
+ /** @var EntryVO $entry */
41
+ foreach ( $aResults as $entry ) {
42
+ $scans[ $entry->scan ] = 1;
43
  }
44
+ return array_keys( $scans );
45
  }
46
 
47
+ public function countForScan( string $scan ) :int {
 
 
 
 
48
  return $this->reset()
49
+ ->filterByScan( $scan )
50
  ->count();
51
  }
52
  }
src/lib/src/Databases/Scanner/Select.php CHANGED
@@ -8,24 +8,20 @@ class Select extends Base\Select {
8
 
9
  use Common;
10
 
11
- /**
12
- * @param string $sScan
13
- * @return int
14
- */
15
- public function countForScan( $sScan ) {
16
  return $this->reset()
17
  ->filterByNotIgnored()
18
- ->filterByScan( $sScan )
19
  ->count();
20
  }
21
 
22
  /**
23
- * @param string $sScan
24
  * @return EntryVO[]
25
  */
26
- public function forScan( $sScan ) {
27
  return $this->reset()
28
- ->filterByScan( $sScan )
29
  ->query();
30
  }
31
  }
8
 
9
  use Common;
10
 
11
+ public function countForScan( string $scan ) :int {
 
 
 
 
12
  return $this->reset()
13
  ->filterByNotIgnored()
14
+ ->filterByScan( $scan )
15
  ->count();
16
  }
17
 
18
  /**
19
+ * @param string $scan
20
  * @return EntryVO[]
21
  */
22
+ public function forScan( $scan ) {
23
  return $this->reset()
24
+ ->filterByScan( $scan )
25
  ->query();
26
  }
27
  }
src/lib/src/Databases/Session/Handler.php CHANGED
@@ -10,15 +10,11 @@ class Handler extends Base\Handler {
10
  $this->tableCleanExpired( 30 );
11
  }
12
 
13
- protected function getCustomColumns() :array {
14
- return $this->getOptions()->getDef( 'sessions_table_columns' );
15
- }
16
-
17
  protected function getDefaultTableName() :string {
18
  return $this->getOptions()->getDef( 'sessions_table_name' );
19
  }
20
-
21
- protected function getTimestampColumns() :array {
22
- return $this->getOptions()->getDef( 'sessions_table_timestamp_columns' );
23
- }
24
  }
10
  $this->tableCleanExpired( 30 );
11
  }
12
 
13
+ /**
14
+ * @return string
15
+ * @deprecated 11.1
16
+ */
17
  protected function getDefaultTableName() :string {
18
  return $this->getOptions()->getDef( 'sessions_table_name' );
19
  }
 
 
 
 
20
  }
src/lib/src/Databases/Traffic/Handler.php CHANGED
@@ -14,11 +14,11 @@ class Handler extends Base\Handler {
14
  $this->tableTrimExcess( $opts->getMaxEntries() );
15
  }
16
 
 
 
 
 
17
  protected function getDefaultTableName() :string {
18
  return $this->getOptions()->getDef( 'traffic_table_name' );
19
  }
20
-
21
- protected function getCustomColumns() :array {
22
- return $this->getOptions()->getDef( 'traffic_table_columns' );
23
- }
24
  }
14
  $this->tableTrimExcess( $opts->getMaxEntries() );
15
  }
16
 
17
+ /**
18
+ * @return string
19
+ * @deprecated 11.1
20
+ */
21
  protected function getDefaultTableName() :string {
22
  return $this->getOptions()->getDef( 'traffic_table_name' );
23
  }
 
 
 
 
24
  }
src/lib/src/Modules/AuditTrail/Auditors/Base.php CHANGED
@@ -1,10 +1,12 @@
1
- <?php
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\Auditors;
4
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules;
6
 
7
  class Base {
8
 
9
  use Modules\ModConsumer;
 
10
  }
1
+ <?php declare( strict_types=1 );
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\Auditors;
4
 
5
+ use FernleafSystems\Utilities\Logic\ExecOnce;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules;
7
 
8
  class Base {
9
 
10
  use Modules\ModConsumer;
11
+ use ExecOnce;
12
  }
src/lib/src/Modules/AuditTrail/Auditors/Emails.php CHANGED
@@ -6,7 +6,7 @@ use FernleafSystems\Wordpress\Services\Services;
6
 
7
  class Emails extends Base {
8
 
9
- public function run() {
10
  add_filter( 'wp_mail', [ $this, 'auditEmailSend' ], PHP_INT_MAX );
11
  }
12
 
6
 
7
  class Emails extends Base {
8
 
9
+ protected function run() {
10
  add_filter( 'wp_mail', [ $this, 'auditEmailSend' ], PHP_INT_MAX );
11
  }
12
 
src/lib/src/Modules/AuditTrail/Auditors/Plugins.php CHANGED
@@ -4,7 +4,7 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\Auditors;
4
 
5
  class Plugins extends Base {
6
 
7
- public function run() {
8
  add_action( 'deactivated_plugin', [ $this, 'auditDeactivatedPlugin' ] );
9
  add_action( 'activated_plugin', [ $this, 'auditActivatedPlugin' ] );
10
  add_action( 'check_admin_referer', [ $this, 'auditEditedFile' ], 10, 2 );
4
 
5
  class Plugins extends Base {
6
 
7
+ protected function run() {
8
  add_action( 'deactivated_plugin', [ $this, 'auditDeactivatedPlugin' ] );
9
  add_action( 'activated_plugin', [ $this, 'auditActivatedPlugin' ] );
10
  add_action( 'check_admin_referer', [ $this, 'auditEditedFile' ], 10, 2 );
src/lib/src/Modules/AuditTrail/Auditors/Posts.php CHANGED
@@ -6,7 +6,7 @@ use FernleafSystems\Wordpress\Services\Services;
6
 
7
  class Posts extends Base {
8
 
9
- public function run() {
10
  add_action( 'deleted_post', [ $this, 'auditDeletedPost' ] );
11
  add_action( 'transition_post_status', [ $this, 'auditPostStatus' ], 30, 3 );
12
  }
6
 
7
  class Posts extends Base {
8
 
9
+ protected function run() {
10
  add_action( 'deleted_post', [ $this, 'auditDeletedPost' ] );
11
  add_action( 'transition_post_status', [ $this, 'auditPostStatus' ], 30, 3 );
12
  }
src/lib/src/Modules/AuditTrail/Auditors/Themes.php CHANGED
@@ -4,7 +4,7 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\Auditors;
4
 
5
  class Themes extends Base {
6
 
7
- public function run() {
8
  add_action( 'switch_theme', [ $this, 'auditSwitchTheme' ] );
9
  add_action( 'check_admin_referer', [ $this, 'auditEditedThemeFile' ], 10, 2 );
10
  }
4
 
5
  class Themes extends Base {
6
 
7
+ protected function run() {
8
  add_action( 'switch_theme', [ $this, 'auditSwitchTheme' ] );
9
  add_action( 'check_admin_referer', [ $this, 'auditEditedThemeFile' ], 10, 2 );
10
  }
src/lib/src/Modules/AuditTrail/Auditors/Upgrades.php CHANGED
@@ -16,10 +16,24 @@ class Upgrades extends Base {
16
  */
17
  private $themes;
18
 
19
- public function run() {
20
  $this->init();
21
  add_action( 'upgrader_process_complete', [ $this, 'auditUpgrades' ], 10, 2 );
22
- /* add_action( 'upgrader_post_install', [ $this, 'auditUpgrade' ], 10, 3 ); */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  }
24
 
25
  private function init() {
@@ -59,30 +73,39 @@ class Upgrades extends Base {
59
  private function handlePlugin( string $item ) {
60
  $WPP = Services::WpPlugins();
61
  $VO = $WPP->getPluginAsVo( $item, true );
62
- $this->getCon()->fireEvent(
63
- 'plugin_upgraded',
64
- [
65
- 'audit' => [
66
- 'file' => $VO->Name,
67
- 'from' => $this->plugins[ $item ],
68
- 'to' => $VO->Version,
 
 
69
  ]
70
- ]
71
- );
72
  }
73
 
 
 
 
 
 
74
  private function handleTheme( string $item ) {
75
  $WPT = Services::WpThemes();
76
  $VO = $WPT->getThemeAsVo( $item, true );
77
- $this->getCon()->fireEvent(
78
- 'theme_upgraded',
79
- [
80
- 'audit' => [
81
- 'file' => $VO->Name,
82
- 'from' => $this->themes[ $item ],
83
- 'to' => $VO->Version,
 
 
84
  ]
85
- ]
86
- );
87
  }
88
  }
16
  */
17
  private $themes;
18
 
19
+ protected function run() {
20
  $this->init();
21
  add_action( 'upgrader_process_complete', [ $this, 'auditUpgrades' ], 10, 2 );
22
+ add_filter( 'upgrader_post_install', [ $this, 'auditUpgrade2' ], 10, 2 );
23
+ }
24
+
25
+ public function auditUpgrade2( $true, $hooksExtra ) {
26
+ add_action( $this->getCon()->prefix( 'pre_plugin_shutdown' ),
27
+ function () use ( $hooksExtra ) {
28
+ if ( !empty( $hooksExtra[ 'plugin' ] ) ) {
29
+ $this->handlePlugin( $hooksExtra[ 'plugin' ] );
30
+ }
31
+ elseif ( !empty( $hooksExtra[ 'theme' ] ) ) {
32
+ $this->handleTheme( $hooksExtra[ 'theme' ] );
33
+ }
34
+ }
35
+ );
36
+ return $true;
37
  }
38
 
39
  private function init() {
73
  private function handlePlugin( string $item ) {
74
  $WPP = Services::WpPlugins();
75
  $VO = $WPP->getPluginAsVo( $item, true );
76
+ if ( !empty( $VO ) ) {
77
+ $this->getCon()->fireEvent(
78
+ 'plugin_upgraded',
79
+ [
80
+ 'audit' => [
81
+ 'file' => $VO->Name,
82
+ 'from' => $this->plugins[ $item ],
83
+ 'to' => $VO->Version,
84
+ ]
85
  ]
86
+ );
87
+ }
88
  }
89
 
90
+ /**
91
+ * Hooked into 'shutdown' to ensure that the latest theme data is avaiable
92
+ * so that we can get the "upgraded to" version correctly.
93
+ * @param string $item
94
+ */
95
  private function handleTheme( string $item ) {
96
  $WPT = Services::WpThemes();
97
  $VO = $WPT->getThemeAsVo( $item, true );
98
+ if ( !empty( $VO ) ) {
99
+ $this->getCon()->fireEvent(
100
+ 'theme_upgraded',
101
+ [
102
+ 'audit' => [
103
+ 'file' => $VO->Name,
104
+ 'from' => $this->themes[ $item ],
105
+ 'to' => $VO->Version,
106
+ ]
107
  ]
108
+ );
109
+ }
110
  }
111
  }
src/lib/src/Modules/AuditTrail/Auditors/Users.php CHANGED
@@ -9,7 +9,7 @@ class Users extends Base {
9
 
10
  use WpLoginCapture;
11
 
12
- public function run() {
13
  $this->setupLoginCaptureHooks();
14
  $this->setToCaptureApplicationLogin( true );
15
 
9
 
10
  use WpLoginCapture;
11
 
12
+ protected function run() {
13
  $this->setupLoginCaptureHooks();
14
  $this->setToCaptureApplicationLogin( true );
15
 
src/lib/src/Modules/AuditTrail/Auditors/Wordpress.php CHANGED
@@ -6,7 +6,7 @@ use FernleafSystems\Wordpress\Services\Services;
6
 
7
  class Wordpress extends Base {
8
 
9
- public function run() {
10
  add_action( '_core_updated_successfully', [ $this, 'auditCoreUpdated' ] );
11
  add_action( 'update_option_permalink_structure', [ $this, 'auditPermalinkStructure' ], 10, 2 );
12
  }
6
 
7
  class Wordpress extends Base {
8
 
9
+ protected function run() {
10
  add_action( '_core_updated_successfully', [ $this, 'auditCoreUpdated' ] );
11
  add_action( 'update_option_permalink_structure', [ $this, 'auditPermalinkStructure' ], 10, 2 );
12
  }
src/lib/src/Modules/AuditTrail/Lib/AuditWriter.php CHANGED
@@ -18,27 +18,30 @@ class AuditWriter extends EventsListener {
18
 
19
  /**
20
  * @param string $evt
21
- * @param array $aMeta
 
22
  */
23
- protected function captureEvent( $evt, $aMeta = [] ) {
24
- $oCon = $this->getCon();
25
- $aDef = $oCon->loadEventsService()->getEventDef( $evt );
26
- if ( $aDef[ 'audit' ] && empty( $aMeta[ 'suppress_audit' ] ) ) { // only audit if it's an auditable event
27
- $oEntry = new AuditTrail\EntryVO();
28
- $oEntry->rid = $this->getCon()->getShortRequestId();
29
- $oEntry->event = $evt;
30
- $oEntry->category = $aDef[ 'cat' ];
31
- $oEntry->context = $aDef[ 'context' ];
32
- $oEntry->meta = isset( $aMeta[ 'audit' ] ) ? $aMeta[ 'audit' ] : [];
 
 
33
 
34
  $aLogs = $this->getLogs();
35
 
36
  // cater for where certain events may happen more than once in the same request
37
- if ( !empty( $aDef[ 'audit_multiple' ] ) ) {
38
- $aLogs[] = $oEntry;
39
  }
40
  else {
41
- $aLogs[ $evt ] = $oEntry;
42
  }
43
 
44
  $this->setLogs( $aLogs );
18
 
19
  /**
20
  * @param string $evt
21
+ * @param array $meta
22
+ * @param array $def
23
  */
24
+ protected function captureEvent( string $evt, $meta = [], $def = [] ) {
25
+ $con = $this->getCon();
26
+ if ( empty( $def ) ) { // TODO: @deprecated 11.1 - remove this if
27
+ $def = $con->loadEventsService()->getEventDef( $evt );
28
+ }
29
+ if ( $def[ 'audit' ] && empty( $meta[ 'suppress_audit' ] ) ) { // only audit if it's an auditable event
30
+ $entry = new AuditTrail\EntryVO();
31
+ $entry->rid = $con->getShortRequestId();
32
+ $entry->event = $evt;
33
+ $entry->category = $def[ 'cat' ];
34
+ $entry->context = $def[ 'context' ];
35
+ $entry->meta = isset( $meta[ 'audit' ] ) ? $meta[ 'audit' ] : [];
36
 
37
  $aLogs = $this->getLogs();
38
 
39
  // cater for where certain events may happen more than once in the same request
40
+ if ( !empty( $def[ 'audit_multiple' ] ) ) {
41
+ $aLogs[] = $entry;
42
  }
43
  else {
44
+ $aLogs[ $evt ] = $entry;
45
  }
46
 
47
  $this->setLogs( $aLogs );
src/lib/src/Modules/AuditTrail/ModCon.php CHANGED
@@ -10,8 +10,7 @@ use FernleafSystems\Wordpress\Services\Services;
10
  class ModCon extends BaseShield\ModCon {
11
 
12
  public function getDbHandler_AuditTrail() :Shield\Databases\AuditTrail\Handler {
13
- $new = $this->getDbH( 'audit_trail' );
14
- return empty( $new ) ? $this->getDbH( 'audit' ) : $new;
15
  }
16
 
17
  protected function handleFileDownload( string $downloadID ) {
10
  class ModCon extends BaseShield\ModCon {
11
 
12
  public function getDbHandler_AuditTrail() :Shield\Databases\AuditTrail\Handler {
13
+ return $this->getDbH( 'audit_trail' );
 
14
  }
15
 
16
  protected function handleFileDownload( string $downloadID ) {
src/lib/src/Modules/AuditTrail/Processor.php CHANGED
@@ -35,25 +35,25 @@ class Processor extends BaseShield\Processor {
35
 
36
  ( new Auditors\Users() )
37
  ->setMod( $this->getMod() )
38
- ->run();
39
  ( new Auditors\Plugins() )
40
  ->setMod( $this->getMod() )
41
- ->run();
42
  ( new Auditors\Themes() )
43
  ->setMod( $this->getMod() )
44
- ->run();
45
  ( new Auditors\Wordpress() )
46
  ->setMod( $this->getMod() )
47
- ->run();
48
  ( new Auditors\Posts() )
49
  ->setMod( $this->getMod() )
50
- ->run();
51
  ( new Auditors\Emails() )
52
  ->setMod( $this->getMod() )
53
- ->run();
54
  ( new Auditors\Upgrades() )
55
  ->setMod( $this->getMod() )
56
- ->run();
57
  }
58
 
59
  /**
35
 
36
  ( new Auditors\Users() )
37
  ->setMod( $this->getMod() )
38
+ ->execute();
39
  ( new Auditors\Plugins() )
40
  ->setMod( $this->getMod() )
41
+ ->execute();
42
  ( new Auditors\Themes() )
43
  ->setMod( $this->getMod() )
44
+ ->execute();
45
  ( new Auditors\Wordpress() )
46
  ->setMod( $this->getMod() )
47
+ ->execute();
48
  ( new Auditors\Posts() )
49
  ->setMod( $this->getMod() )
50
+ ->execute();
51
  ( new Auditors\Emails() )
52
  ->setMod( $this->getMod() )
53
+ ->execute();
54
  ( new Auditors\Upgrades() )
55
  ->setMod( $this->getMod() )
56
+ ->execute();
57
  }
58
 
59
  /**
src/lib/src/Modules/AuditTrail/UI.php CHANGED
@@ -50,14 +50,4 @@ class UI extends BaseShield\UI {
50
  true
51
  );
52
  }
53
-
54
- protected function getSettingsRelatedLinks() :array {
55
- $modInsights = $this->getCon()->getModule_Insights();
56
- return [
57
- [
58
- 'href' => $modInsights->getUrl_SubInsightsPage( 'audit' ),
59
- 'title' => __( 'View Audit Trail', 'wp-simple-firewall' ),
60
- ]
61
- ];
62
- }
63
  }
50
  true
51
  );
52
  }
 
 
 
 
 
 
 
 
 
 
53
  }
src/lib/src/Modules/Base/AjaxHandler.php CHANGED
@@ -2,8 +2,8 @@
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 AjaxHandler {
9
 
@@ -32,41 +32,6 @@ abstract class AjaxHandler {
32
  return $ajaxResponse;
33
  }
34
 
35
- /**
36
- * @param string $encoding
37
- * @return array
38
- */
39
- protected function getAjaxFormParams( $encoding = 'none' ) {
40
- $req = Services::Request();
41
- $aFormParams = [];
42
- $sRaw = $req->post( 'form_params', '' );
43
-
44
- if ( !empty( $sRaw ) ) {
45
-
46
- $sMaybeEncoding = $req->post( 'enc_params' );
47
- if ( in_array( $sMaybeEncoding, [ 'none', 'lz-string', 'b64' ] ) ) {
48
- $encoding = $sMaybeEncoding;
49
- }
50
-
51
- switch ( $encoding ) {
52
- case 'lz-string':
53
- $sRaw = \LZCompressor\LZString::decompress( base64_decode( $sRaw ) );
54
- break;
55
-
56
- case 'b64':
57
- $sRaw = base64_decode( $sRaw );
58
- break;
59
-
60
- case 'none':
61
- default:
62
- break;
63
- }
64
-
65
- parse_str( $sRaw, $aFormParams );
66
- }
67
- return $aFormParams;
68
- }
69
-
70
  protected function processAjaxAction( string $action ) :array {
71
  return [];
72
  }
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Request\FormParams;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
 
7
 
8
  abstract class AjaxHandler {
9
 
32
  return $ajaxResponse;
33
  }
34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  protected function processAjaxAction( string $action ) :array {
36
  return [];
37
  }
src/lib/src/Modules/Base/Lib/Request/FormParams.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Request;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
+
8
+ class FormParams {
9
+
10
+ const ENC_NONE = 'none';
11
+ const ENC_LZ = 'lz-string';
12
+ const ENC_BASE64 = 'b64';
13
+ use ModConsumer;
14
+
15
+ public static function Retrieve( string $encoding = self::ENC_NONE ) :array {
16
+ $req = Services::Request();
17
+ $formParams = [];
18
+ $raw = $req->post( 'form_params', '' );
19
+
20
+ if ( empty( $raw ) ) {
21
+ $formParams = $req->post;
22
+ }
23
+ else {
24
+ $maybeEncoding = $req->post( 'enc_params' );
25
+ if ( in_array( $maybeEncoding, [ 'none', 'lz-string', 'b64' ] ) ) {
26
+ $encoding = $maybeEncoding;
27
+ }
28
+
29
+ switch ( $encoding ) {
30
+ case 'lz-string':
31
+ $raw = \LZCompressor\LZString::decompress( base64_decode( $raw ) );
32
+ break;
33
+
34
+ case 'b64':
35
+ $raw = base64_decode( $raw );
36
+ break;
37
+
38
+ case 'none':
39
+ default:
40
+ break;
41
+ }
42
+
43
+ parse_str( $raw, $formParams );
44
+ }
45
+
46
+ return is_array( $formParams ) ? $formParams : [];
47
+ }
48
+ }
src/lib/src/Modules/Base/ModCon.php CHANGED
@@ -4,6 +4,7 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules;
 
7
  use FernleafSystems\Wordpress\Services\Services;
8
 
9
  /**
@@ -67,27 +68,27 @@ abstract class ModCon {
67
 
68
  /**
69
  * @param Shield\Controller\Controller $pluginCon
70
- * @param array $aMod
71
  * @throws \Exception
72
  */
73
- public function __construct( $pluginCon, $aMod = [] ) {
74
  if ( !$pluginCon instanceof Shield\Controller\Controller ) {
75
  throw new \Exception( 'Plugin controller not supplied to Module' );
76
  }
77
  $this->setCon( $pluginCon );
78
 
79
- if ( empty( $aMod[ 'storage_key' ] ) && empty( $aMod[ 'slug' ] ) ) {
80
  throw new \Exception( 'Module storage key AND slug are undefined' );
81
  }
82
 
83
- $this->sOptionsStoreKey = empty( $aMod[ 'storage_key' ] ) ? $aMod[ 'slug' ] : $aMod[ 'storage_key' ];
84
- if ( isset( $aMod[ 'slug' ] ) ) {
85
- $this->sModSlug = $aMod[ 'slug' ];
86
  }
87
 
88
  if ( $this->verifyModuleMeetRequirements() ) {
89
  $this->handleAutoPageRedirects();
90
- $this->setupHooks( $aMod );
91
  $this->doPostConstruction();
92
  }
93
  }
@@ -205,41 +206,6 @@ abstract class ModCon {
205
  return $this->loadModElement( 'Upgrade' );
206
  }
207
 
208
- /**
209
- * @param string $sEncoding
210
- * @return array
211
- */
212
- public function getAjaxFormParams( $sEncoding = 'none' ) {
213
- $oReq = Services::Request();
214
- $aFormParams = [];
215
- $sRaw = $oReq->post( 'form_params', '' );
216
-
217
- if ( !empty( $sRaw ) ) {
218
-
219
- $sMaybeEncoding = $oReq->post( 'enc_params' );
220
- if ( in_array( $sMaybeEncoding, [ 'none', 'lz-string', 'b64' ] ) ) {
221
- $sEncoding = $sMaybeEncoding;
222
- }
223
-
224
- switch ( $sEncoding ) {
225
- case 'lz-string':
226
- $sRaw = \LZCompressor\LZString::decompress( base64_decode( $sRaw ) );
227
- break;
228
-
229
- case 'b64':
230
- $sRaw = base64_decode( $sRaw );
231
- break;
232
-
233
- case 'none':
234
- default:
235
- break;
236
- }
237
-
238
- parse_str( $sRaw, $aFormParams );
239
- }
240
- return $aFormParams;
241
- }
242
-
243
  /**
244
  * @param array $aAdminNotices
245
  * @return array
@@ -521,14 +487,14 @@ abstract class ModCon {
521
  }
522
 
523
  public function isModuleEnabled() :bool {
524
- /** @var Shield\Modules\Plugin\Options $oPluginOpts */
525
- $oPluginOpts = $this->getCon()->getModule_Plugin()->getOptions();
526
 
527
  if ( $this->getOptions()->getFeatureProperty( 'auto_enabled' ) === true ) {
528
  // Auto enabled modules always run regardless
529
  $enabled = true;
530
  }
531
- elseif ( $oPluginOpts->isPluginGloballyDisabled() ) {
532
  $enabled = false;
533
  }
534
  elseif ( $this->getCon()->getIfForceOffActive() ) {
@@ -652,54 +618,51 @@ abstract class ModCon {
652
  );
653
  }
654
 
655
- /**
656
- * @return array
657
- */
658
- public function buildSummaryData() {
659
  $opts = $this->getOptions();
660
- $sMenuTitle = $opts->getFeatureProperty( 'menu_title' );
661
 
662
- $aSections = $opts->getSections();
663
- foreach ( $aSections as $sSlug => $aSection ) {
664
  try {
665
- $aStrings = $this->getStrings()->getSectionStrings( $aSection[ 'slug' ] );
666
- foreach ( $aStrings as $sKey => $sVal ) {
667
- unset( $aSection[ $sKey ] );
668
- $aSection[ $sKey ] = $sVal;
669
  }
670
  }
671
  catch ( \Exception $e ) {
672
  }
673
  }
674
 
675
- $aSum = [
676
  'slug' => $this->getSlug(),
677
  'enabled' => $this->getUIHandler()->isEnabledForUiSummary(),
678
  'active' => $this->isThisModulePage() || $this->isPage_InsightsThisModule(),
679
  'name' => $this->getMainFeatureName(),
680
  'sidebar_name' => $opts->getFeatureProperty( 'sidebar_name' ),
681
- 'menu_title' => empty( $sMenuTitle ) ? $this->getMainFeatureName() : __( $sMenuTitle, 'wp-simple-firewall' ),
682
  'href' => network_admin_url( 'admin.php?page='.$this->getModSlug() ),
683
- 'sections' => $aSections,
684
  'options' => [],
685
  'show_mod_opts' => $this->getIfShowModuleOpts(),
686
  ];
687
 
688
- foreach ( $opts->getVisibleOptionsKeys() as $sOptKey ) {
689
  try {
690
- $aOptData = $this->getStrings()->getOptionStrings( $sOptKey );
691
- $aOptData[ 'href' ] = $this->getUrl_DirectLinkToOption( $sOptKey );
692
- $aSum[ 'options' ][ $sOptKey ] = $aOptData;
693
  }
694
  catch ( \Exception $e ) {
695
  }
696
  }
697
 
698
- $aSum[ 'tooltip' ] = sprintf(
699
  '%s',
700
- empty( $aSum[ 'sidebar_name' ] ) ? $aSum[ 'name' ] : __( $aSum[ 'sidebar_name' ], 'wp-simple-firewall' )
701
  );
702
- return $aSum;
703
  }
704
 
705
  public function getIfShowModuleMenuItem() :bool {
@@ -893,9 +856,9 @@ abstract class ModCon {
893
  }
894
 
895
  public function onPluginDelete() {
896
- foreach ( $this->getDbHandlers( true ) as $oDbh ) {
897
- if ( !empty( $oDbh ) ) {
898
- $oDbh->tableDelete();
899
  }
900
  }
901
  $this->getOptions()->deleteStorage();
@@ -980,8 +943,17 @@ abstract class ModCon {
980
  return $this;
981
  }
982
 
 
 
 
 
 
 
 
 
983
  protected function isAdminOptionsPage() :bool {
984
- return is_admin() && !Services::WpGeneral()->isAjax() && $this->isThisModulePage();
 
985
  }
986
 
987
  public function isPremium() :bool {
@@ -992,11 +964,12 @@ abstract class ModCon {
992
  * @throws \Exception
993
  */
994
  private function doSaveStandardOptions() {
995
- $aForm = $this->getAjaxFormParams( 'b64' ); // standard options use b64 and failover to lz-string
 
996
 
997
  foreach ( $this->getAllFormOptionsAndTypes() as $sKey => $sOptType ) {
998
 
999
- $sOptionValue = isset( $aForm[ $sKey ] ) ? $aForm[ $sKey ] : null;
1000
  if ( is_null( $sOptionValue ) ) {
1001
 
1002
  if ( in_array( $sOptType, [ 'text', 'email' ] ) ) { //text box, and it's null, don't update
@@ -1026,7 +999,7 @@ abstract class ModCon {
1026
  continue;
1027
  }
1028
 
1029
- $sConfirm = isset( $aForm[ $sKey.'_confirm' ] ) ? $aForm[ $sKey.'_confirm' ] : null;
1030
  if ( $sTempValue !== $sConfirm ) {
1031
  throw new \Exception( __( 'Password values do not match.', 'wp-simple-firewall' ) );
1032
  }
@@ -1052,7 +1025,7 @@ abstract class ModCon {
1052
  if ( $this->isPremium() ) {
1053
  ( new Shield\Modules\Plugin\Lib\ImportExport\Options\SaveExcludedOptions() )
1054
  ->setMod( $this )
1055
- ->save( $aForm );
1056
  }
1057
  }
1058
 
@@ -1213,16 +1186,16 @@ abstract class ModCon {
1213
  public function renderOptionsForm() {
1214
 
1215
  if ( $this->canDisplayOptionsForm() ) {
1216
- $sTemplate = 'components/options_form/main.twig';
1217
  }
1218
  else {
1219
- $sTemplate = 'subfeature-access_restricted';
1220
  }
1221
 
1222
  try {
1223
  return $this->getCon()
1224
  ->getRenderer()
1225
- ->setTemplate( $sTemplate )
1226
  ->setRenderVars( $this->getUIHandler()->getBaseDisplayData() )
1227
  ->setTemplateEngineTwig()
1228
  ->render();
@@ -1255,13 +1228,6 @@ abstract class ModCon {
1255
  return [];
1256
  }
1257
 
1258
- /**
1259
- * Override this with custom JS vars for your particular module.
1260
- * @deprecated 10.2
1261
- */
1262
- public function insertCustomJsVars_Admin() {
1263
- }
1264
-
1265
  /**
1266
  * @param array $aData
1267
  * @param string $sSubView
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Request\FormParams;
8
  use FernleafSystems\Wordpress\Services\Services;
9
 
10
  /**
68
 
69
  /**
70
  * @param Shield\Controller\Controller $pluginCon
71
+ * @param array $mod
72
  * @throws \Exception
73
  */
74
+ public function __construct( $pluginCon, $mod = [] ) {
75
  if ( !$pluginCon instanceof Shield\Controller\Controller ) {
76
  throw new \Exception( 'Plugin controller not supplied to Module' );
77
  }
78
  $this->setCon( $pluginCon );
79
 
80
+ if ( empty( $mod[ 'storage_key' ] ) && empty( $mod[ 'slug' ] ) ) {
81
  throw new \Exception( 'Module storage key AND slug are undefined' );
82
  }
83
 
84
+ $this->sOptionsStoreKey = empty( $mod[ 'storage_key' ] ) ? $mod[ 'slug' ] : $mod[ 'storage_key' ];
85
+ if ( isset( $mod[ 'slug' ] ) ) {
86
+ $this->sModSlug = $mod[ 'slug' ];
87
  }
88
 
89
  if ( $this->verifyModuleMeetRequirements() ) {
90
  $this->handleAutoPageRedirects();
91
+ $this->setupHooks( $mod );
92
  $this->doPostConstruction();
93
  }
94
  }
206
  return $this->loadModElement( 'Upgrade' );
207
  }
208
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
  /**
210
  * @param array $aAdminNotices
211
  * @return array
487
  }
488
 
489
  public function isModuleEnabled() :bool {
490
+ /** @var Shield\Modules\Plugin\Options $pluginOpts */
491
+ $pluginOpts = $this->getCon()->getModule_Plugin()->getOptions();
492
 
493
  if ( $this->getOptions()->getFeatureProperty( 'auto_enabled' ) === true ) {
494
  // Auto enabled modules always run regardless
495
  $enabled = true;
496
  }
497
+ elseif ( $pluginOpts->isPluginGloballyDisabled() ) {
498
  $enabled = false;
499
  }
500
  elseif ( $this->getCon()->getIfForceOffActive() ) {
618
  );
619
  }
620
 
621
+ public function buildSummaryData() :array {
 
 
 
622
  $opts = $this->getOptions();
623
+ $menuTitle = $opts->getFeatureProperty( 'menu_title' );
624
 
625
+ $sections = $opts->getSections();
626
+ foreach ( $sections as $slug => $section ) {
627
  try {
628
+ $strings = $this->getStrings()->getSectionStrings( $section[ 'slug' ] );
629
+ foreach ( $strings as $key => $val ) {
630
+ unset( $section[ $key ] );
631
+ $section[ $key ] = $val;
632
  }
633
  }
634
  catch ( \Exception $e ) {
635
  }
636
  }
637
 
638
+ $summary = [
639
  'slug' => $this->getSlug(),
640
  'enabled' => $this->getUIHandler()->isEnabledForUiSummary(),
641
  'active' => $this->isThisModulePage() || $this->isPage_InsightsThisModule(),
642
  'name' => $this->getMainFeatureName(),
643
  'sidebar_name' => $opts->getFeatureProperty( 'sidebar_name' ),
644
+ 'menu_title' => empty( $menuTitle ) ? $this->getMainFeatureName() : __( $menuTitle, 'wp-simple-firewall' ),
645
  'href' => network_admin_url( 'admin.php?page='.$this->getModSlug() ),
646
+ 'sections' => $sections,
647
  'options' => [],
648
  'show_mod_opts' => $this->getIfShowModuleOpts(),
649
  ];
650
 
651
+ foreach ( $opts->getVisibleOptionsKeys() as $optKey ) {
652
  try {
653
+ $optData = $this->getStrings()->getOptionStrings( $optKey );
654
+ $optData[ 'href' ] = $this->getUrl_DirectLinkToOption( $optKey );
655
+ $summary[ 'options' ][ $optKey ] = $optData;
656
  }
657
  catch ( \Exception $e ) {
658
  }
659
  }
660
 
661
+ $summary[ 'tooltip' ] = sprintf(
662
  '%s',
663
+ empty( $summary[ 'sidebar_name' ] ) ? $summary[ 'name' ] : __( $summary[ 'sidebar_name' ], 'wp-simple-firewall' )
664
  );
665
+ return $summary;
666
  }
667
 
668
  public function getIfShowModuleMenuItem() :bool {
856
  }
857
 
858
  public function onPluginDelete() {
859
+ foreach ( $this->getDbHandlers( true ) as $dbh ) {
860
+ if ( !empty( $dbh ) ) {
861
+ $dbh->tableDelete();
862
  }
863
  }
864
  $this->getOptions()->deleteStorage();
943
  return $this;
944
  }
945
 
946
+ protected function isThisModAdminPage() :bool {
947
+ return is_admin() && !Services::WpGeneral()->isAjax()
948
+ && Services::Request()->isGet() && $this->isThisModulePage();
949
+ }
950
+
951
+ /**
952
+ * @deprecated 11.1
953
+ */
954
  protected function isAdminOptionsPage() :bool {
955
+ return is_admin() && !Services::WpGeneral()->isAjax()
956
+ && Services::Request()->isGet() && $this->isThisModulePage();
957
  }
958
 
959
  public function isPremium() :bool {
964
  * @throws \Exception
965
  */
966
  private function doSaveStandardOptions() {
967
+ // standard options use b64 and fail-over to lz-string
968
+ $form = FormParams::Retrieve( FormParams::ENC_BASE64 );
969
 
970
  foreach ( $this->getAllFormOptionsAndTypes() as $sKey => $sOptType ) {
971
 
972
+ $sOptionValue = isset( $form[ $sKey ] ) ? $form[ $sKey ] : null;
973
  if ( is_null( $sOptionValue ) ) {
974
 
975
  if ( in_array( $sOptType, [ 'text', 'email' ] ) ) { //text box, and it's null, don't update
999
  continue;
1000
  }
1001
 
1002
+ $sConfirm = isset( $form[ $sKey.'_confirm' ] ) ? $form[ $sKey.'_confirm' ] : null;
1003
  if ( $sTempValue !== $sConfirm ) {
1004
  throw new \Exception( __( 'Password values do not match.', 'wp-simple-firewall' ) );
1005
  }
1025
  if ( $this->isPremium() ) {
1026
  ( new Shield\Modules\Plugin\Lib\ImportExport\Options\SaveExcludedOptions() )
1027
  ->setMod( $this )
1028
+ ->save( $form );
1029
  }
1030
  }
1031
 
1186
  public function renderOptionsForm() {
1187
 
1188
  if ( $this->canDisplayOptionsForm() ) {
1189
+ $template = 'components/options_form/main.twig';
1190
  }
1191
  else {
1192
+ $template = 'subfeature-access_restricted';
1193
  }
1194
 
1195
  try {
1196
  return $this->getCon()
1197
  ->getRenderer()
1198
+ ->setTemplate( $template )
1199
  ->setRenderVars( $this->getUIHandler()->getBaseDisplayData() )
1200
  ->setTemplateEngineTwig()
1201
  ->render();
1228
  return [];
1229
  }
1230
 
 
 
 
 
 
 
 
1231
  /**
1232
  * @param array $aData
1233
  * @param string $sSubView
src/lib/src/Modules/Base/Options.php CHANGED
@@ -955,7 +955,7 @@ class Options {
955
  if ( !$this->getConfigFileExists() ) {
956
  throw new \Exception( sprintf( 'Configuration file "%s" does not exist.', $this->getPathToConfig() ) );
957
  }
958
- return Services::Data()->readFileContentsUsingInclude( $this->getPathToConfig() );
959
  }
960
 
961
  public function getConfigStorageKey() :string {
955
  if ( !$this->getConfigFileExists() ) {
956
  throw new \Exception( sprintf( 'Configuration file "%s" does not exist.', $this->getPathToConfig() ) );
957
  }
958
+ return Services::Data()->readFileWithInclude( $this->getPathToConfig() );
959
  }
960
 
961
  public function getConfigStorageKey() :string {
src/lib/src/Modules/Base/Strings.php CHANGED
@@ -169,12 +169,12 @@ class Strings {
169
  * @throws \Exception
170
  */
171
  public function getOptionStrings( string $key ) :array {
172
- $aOpt = $this->getOptions()->getOptDefinition( $key );
173
- if ( is_array( $aOpt ) && !empty( $aOpt[ 'name' ] ) && !empty( $aOpt[ 'summary' ] ) && !empty( $aOpt[ 'description' ] ) ) {
174
  return [
175
- 'name' => __( $aOpt[ 'name' ], 'wp-simple-firewall' ),
176
- 'summary' => __( $aOpt[ 'summary' ], 'wp-simple-firewall' ),
177
- 'description' => __( $aOpt[ 'description' ], 'wp-simple-firewall' ),
178
  ];
179
  }
180
  throw new \Exception( sprintf( 'An option has been defined but without strings assigned to it. Option key: "%s".', $key ) );
169
  * @throws \Exception
170
  */
171
  public function getOptionStrings( string $key ) :array {
172
+ $opt = $this->getOptions()->getOptDefinition( $key );
173
+ if ( is_array( $opt ) && !empty( $opt[ 'name' ] ) && !empty( $opt[ 'summary' ] ) && !empty( $opt[ 'description' ] ) ) {
174
  return [
175
+ 'name' => __( $opt[ 'name' ], 'wp-simple-firewall' ),
176
+ 'summary' => __( $opt[ 'summary' ], 'wp-simple-firewall' ),
177
+ 'description' => __( $opt[ 'description' ], 'wp-simple-firewall' ),
178
  ];
179
  }
180
  throw new \Exception( sprintf( 'An option has been defined but without strings assigned to it. Option key: "%s".', $key ) );
src/lib/src/Modules/Base/UI.php CHANGED
@@ -207,26 +207,28 @@ class UI {
207
  ->build(),
208
  'hidden_options' => $this->getOptions()->getHiddenOptions()
209
  ],
 
 
 
210
  'ajax' => [
211
  'mod_options' => $mod->getAjaxActionData( 'mod_options', true ),
212
  'mod_opts_form_render' => $mod->getAjaxActionData( 'mod_opts_form_render', true ),
213
- // 'mod_options' => $mod->getAjaxActionData( 'mod_options' ),
214
  ],
215
  'vendors' => [
216
  'widget_freshdesk' => '3000000081' /* TODO: plugin spec config */
217
  ],
218
  'strings' => $mod->getStrings()->getDisplayStrings(),
219
  'flags' => [
220
- 'access_restricted' => !$mod->canDisplayOptionsForm(),
221
- 'show_ads' => $mod->getIsShowMarketing(),
222
- 'wrap_page_content' => true,
223
- 'show_standard_options' => true,
224
- 'show_content_help' => true,
225
- 'show_alt_content' => false,
226
- 'has_wizard' => $mod->hasWizard(),
227
- 'is_premium' => $con->isPremiumActive(),
228
- 'show_transfer_switch' => $con->isPremiumActive(),
229
- 'is_wpcli' => $pluginOptions->isEnabledWpcli(),
230
  ],
231
  'hrefs' => [
232
  'go_pro' => 'https://shsec.io/shieldgoprofeature',
207
  ->build(),
208
  'hidden_options' => $this->getOptions()->getHiddenOptions()
209
  ],
210
+ 'vars' => [
211
+ 'mod_slug' => $mod->getModSlug( true ),
212
+ ],
213
  'ajax' => [
214
  'mod_options' => $mod->getAjaxActionData( 'mod_options', true ),
215
  'mod_opts_form_render' => $mod->getAjaxActionData( 'mod_opts_form_render', true ),
 
216
  ],
217
  'vendors' => [
218
  'widget_freshdesk' => '3000000081' /* TODO: plugin spec config */
219
  ],
220
  'strings' => $mod->getStrings()->getDisplayStrings(),
221
  'flags' => [
222
+ 'access_restricted' => !$mod->canDisplayOptionsForm(),
223
+ 'show_ads' => $mod->getIsShowMarketing(),
224
+ 'wrap_page_content' => true,
225
+ 'show_standard_options' => true,
226
+ 'show_content_help' => true,
227
+ 'show_alt_content' => false,
228
+ 'has_wizard' => $mod->hasWizard(),
229
+ 'is_premium' => $con->isPremiumActive(),
230
+ 'show_transfer_switch' => $con->isPremiumActive(),
231
+ 'is_wpcli' => $pluginOptions->isEnabledWpcli(),
232
  ],
233
  'hrefs' => [
234
  'go_pro' => 'https://shsec.io/shieldgoprofeature',
src/lib/src/Modules/BaseShield/ModCon.php CHANGED
@@ -97,6 +97,10 @@ class ModCon extends Base\ModCon {
97
  return $data;
98
  }
99
 
 
 
 
 
100
  protected function getSecAdminCheckAjaxData() :array {
101
  // We set a custom mod_slug so that this module handles the ajax request
102
  $dat = $this->getAjaxActionData( 'sec_admin_check' );
@@ -127,26 +131,28 @@ class ModCon extends Base\ModCon {
127
  $secOpts = $this->getCon()
128
  ->getModule_SecAdmin()
129
  ->getOptions();
130
- $aData = Services::DataManipulation()
131
- ->mergeArraysRecursive(
132
- $this->getUIHandler()->getBaseDisplayData(),
133
- [
134
- 'ajax' => [
135
- 'restricted_access' => $this->getAjaxActionData( 'restricted_access' ),
136
- ],
137
- 'strings' => [
138
- 'force_remove_email' => __( "If you've forgotten your PIN, a link can be sent to the plugin administrator email address to remove this restriction.", 'wp-simple-firewall' ),
139
- 'click_email' => __( "Click here to send the verification email.", 'wp-simple-firewall' ),
140
- 'send_to_email' => sprintf( __( "Email will be sent to %s", 'wp-simple-firewall' ),
141
- Utilities\Obfuscate::Email( $this->getPluginReportEmail() ) ),
142
- 'no_email_override' => __( "The Security Administrator has restricted the use of the email override feature.", 'wp-simple-firewall' ),
143
- ],
144
- 'flags' => [
145
- 'allow_email_override' => $secOpts->isEmailOverridePermitted()
146
- ]
147
- ]
148
- );
149
- return $this->renderTemplate( '/wpadmin_pages/security_admin/index.twig', $aData, true );
 
 
150
  }
151
 
152
  public function getIfSupport3rdParty() :bool {
97
  return $data;
98
  }
99
 
100
+ /**
101
+ * @return array
102
+ * @deprecated 11.1
103
+ */
104
  protected function getSecAdminCheckAjaxData() :array {
105
  // We set a custom mod_slug so that this module handles the ajax request
106
  $dat = $this->getAjaxActionData( 'sec_admin_check' );
131
  $secOpts = $this->getCon()
132
  ->getModule_SecAdmin()
133
  ->getOptions();
134
+ return $this->renderTemplate(
135
+ '/wpadmin_pages/security_admin/index.twig',
136
+ Services::DataManipulation()
137
+ ->mergeArraysRecursive(
138
+ $this->getUIHandler()->getBaseDisplayData(),
139
+ [
140
+ 'ajax' => [
141
+ 'restricted_access' => $this->getAjaxActionData( 'restricted_access' ),
142
+ ],
143
+ 'strings' => [
144
+ 'force_remove_email' => __( "If you've forgotten your PIN, a link can be sent to the plugin administrator email address to remove this restriction.", 'wp-simple-firewall' ),
145
+ 'click_email' => __( "Click here to send the verification email.", 'wp-simple-firewall' ),
146
+ 'send_to_email' => sprintf( __( "Email will be sent to %s", 'wp-simple-firewall' ),
147
+ Utilities\Obfuscate::Email( $this->getPluginReportEmail() ) ),
148
+ 'no_email_override' => __( "The Security Administrator has restricted the use of the email override feature.", 'wp-simple-firewall' ),
149
+ ],
150
+ 'flags' => [
151
+ 'allow_email_override' => $secOpts->isEmailOverridePermitted()
152
+ ]
153
+ ]
154
+ ),
155
+ true );
156
  }
157
 
158
  public function getIfSupport3rdParty() :bool {
src/lib/src/Modules/BaseShield/UI.php CHANGED
@@ -56,14 +56,7 @@ class UI extends Base\UI {
56
  Services::Request()->query( 'inav', '' )
57
  ] ) )
58
  ],
59
- 'vars' => [
60
- 'related_hrefs' => $this->getSettingsRelatedLinks()
61
- ]
62
  ]
63
  );
64
  }
65
-
66
- protected function getSettingsRelatedLinks() :array {
67
- return [];
68
- }
69
  }
56
  Services::Request()->query( 'inav', '' )
57
  ] ) )
58
  ],
 
 
 
59
  ]
60
  );
61
  }
 
 
 
 
62
  }
src/lib/src/Modules/CommentsFilter/Scan/Scanner.php CHANGED
@@ -102,6 +102,7 @@ class Scanner {
102
  'spam_block_'.$mResult->get_error_code(),
103
  [ 'audit' => $mResult->get_error_data() ]
104
  );
 
105
 
106
  if ( $mResult->get_error_code() == 'human' ) {
107
  $status = $opts->getOpt( 'comments_default_action_human_spam' );
102
  'spam_block_'.$mResult->get_error_code(),
103
  [ 'audit' => $mResult->get_error_data() ]
104
  );
105
+ $this->getCon()->fireEvent( 'comment_spam_block' );
106
 
107
  if ( $mResult->get_error_code() == 'human' ) {
108
  $status = $opts->getOpt( 'comments_default_action_human_spam' );
src/lib/src/Modules/Events/Consolidate/ConsolidateAllEvents.php CHANGED
@@ -12,12 +12,12 @@ class ConsolidateAllEvents {
12
  use ModConsumer;
13
 
14
  public function run() {
15
- foreach ( $this->getAllEvents() as $sEvent ) {
16
- $this->consolidateEventIntoHourly( $sEvent );
17
- $this->consolidateEventIntoDaily( $sEvent );
18
- $this->consolidateEventIntoWeekly( $sEvent );
19
- $this->consolidateEventIntoMonthly( $sEvent );
20
- $this->consolidateEventIntoYearly( $sEvent );
21
  }
22
  }
23
 
@@ -178,9 +178,9 @@ class ConsolidateAllEvents {
178
  /**
179
  * Consolidates each event in Daily sums. Doesn't process events from the previous 48hrs.
180
  * Processes event for the 7 days previous to the last 48 hours.
181
- * @param $sEvent
182
  */
183
- protected function consolidateEventIntoMonthly( $sEvent ) {
184
  /** @var ModCon $mod */
185
  $mod = $this->getMod();
186
  $dbh = $mod->getDbHandler_Events();
@@ -192,28 +192,28 @@ class ConsolidateAllEvents {
192
 
193
  $nMonthCount = 0;
194
  do {
195
- /** @var Events\Select $oSel */
196
- $oSel = $dbh->getQuerySelector();
197
- $nRecords = $oSel->filterByBoundary_Month( $oTime->timestamp )
198
- ->filterByEvent( $sEvent )
199
- ->count();
200
 
201
  if ( $nRecords > 1 ) {
202
  /** @var Events\Select $oSel */
203
- $oSel = $dbh->getQuerySelector();
204
  /** @var Events\EntryVO[] $aRecords */
205
- $nSum = $oSel->filterByBoundary_Month( $oTime->timestamp )
206
- ->sumEvent( $sEvent );
207
 
208
  if ( $nSum > 0 ) {
209
  /** @var Events\Delete $oDel */
210
  $oDel = $dbh->getQueryDeleter();
211
  $oDel->filterByBoundary_Month( $oTime->timestamp )
212
- ->filterByEvent( $sEvent )
213
  ->query();
214
 
215
  $oEntry = new Events\EntryVO();
216
- $oEntry->event = $sEvent;
217
  $oEntry->count = $nSum;
218
  $oEntry->created_at = $oTime->timestamp + 1;
219
  /** @var Events\Insert $oQI */
@@ -282,11 +282,11 @@ class ConsolidateAllEvents {
282
  /**
283
  * @return string[]
284
  */
285
- protected function getAllEvents() {
286
  /** @var ModCon $mod */
287
  $mod = $this->getMod();
288
- /** @var Events\Select $oSel */
289
- $oSel = $mod->getDbHandler_Events()->getQuerySelector();
290
- return $oSel->getAllEvents();
291
  }
292
  }
12
  use ModConsumer;
13
 
14
  public function run() {
15
+ foreach ( $this->getAllEvents() as $event ) {
16
+ $this->consolidateEventIntoHourly( $event );
17
+ $this->consolidateEventIntoDaily( $event );
18
+ $this->consolidateEventIntoWeekly( $event );
19
+ $this->consolidateEventIntoMonthly( $event );
20
+ $this->consolidateEventIntoYearly( $event );
21
  }
22
  }
23
 
178
  /**
179
  * Consolidates each event in Daily sums. Doesn't process events from the previous 48hrs.
180
  * Processes event for the 7 days previous to the last 48 hours.
181
+ * @param $event
182
  */
183
+ protected function consolidateEventIntoMonthly( $event ) {
184
  /** @var ModCon $mod */
185
  $mod = $this->getMod();
186
  $dbh = $mod->getDbHandler_Events();
192
 
193
  $nMonthCount = 0;
194
  do {
195
+ /** @var Events\Select $select */
196
+ $select = $dbh->getQuerySelector();
197
+ $nRecords = $select->filterByBoundary_Month( $oTime->timestamp )
198
+ ->filterByEvent( $event )
199
+ ->count();
200
 
201
  if ( $nRecords > 1 ) {
202
  /** @var Events\Select $oSel */
203
+ $select = $dbh->getQuerySelector();
204
  /** @var Events\EntryVO[] $aRecords */
205
+ $nSum = $select->filterByBoundary_Month( $oTime->timestamp )
206
+ ->sumEvent( $event );
207
 
208
  if ( $nSum > 0 ) {
209
  /** @var Events\Delete $oDel */
210
  $oDel = $dbh->getQueryDeleter();
211
  $oDel->filterByBoundary_Month( $oTime->timestamp )
212
+ ->filterByEvent( $event )
213
  ->query();
214
 
215
  $oEntry = new Events\EntryVO();
216
+ $oEntry->event = $event;
217
  $oEntry->count = $nSum;
218
  $oEntry->created_at = $oTime->timestamp + 1;
219
  /** @var Events\Insert $oQI */
282
  /**
283
  * @return string[]
284
  */
285
+ protected function getAllEvents() :array {
286
  /** @var ModCon $mod */
287
  $mod = $this->getMod();
288
+ /** @var Events\Select $select */
289
+ $select = $mod->getDbHandler_Events()->getQuerySelector();
290
+ return $select->getAllEvents();
291
  }
292
  }
src/lib/src/Modules/Events/Lib/EventsListener.php CHANGED
@@ -22,10 +22,9 @@ abstract class EventsListener {
22
  $this->setCon( $con );
23
 
24
  add_action( $con->prefix( 'event' ),
25
- function ( $event, $meta = [] ) use ( $con ) {
26
- if ( $con->loadEventsService()->isSupportedEvent( $event ) ) {
27
- $this->captureEvent( $event, $meta );
28
- }
29
  }, 10, 2 );
30
 
31
  add_action( $con->prefix( 'plugin_shutdown' ), function () {
@@ -35,9 +34,10 @@ abstract class EventsListener {
35
 
36
  /**
37
  * @param string $evt
38
- * @param array $aMeta
 
39
  */
40
- abstract protected function captureEvent( $evt, $aMeta = [] );
41
 
42
  protected function onShutdown() {
43
 
22
  $this->setCon( $con );
23
 
24
  add_action( $con->prefix( 'event' ),
25
+ function ( $event, $meta = [], $def = [] ) use ( $con ) {
26
+ // TODO @deprecated 11.1 remove ??
27
+ $this->captureEvent( $event, $meta, $def ?? [] );
 
28
  }, 10, 2 );
29
 
30
  add_action( $con->prefix( 'plugin_shutdown' ), function () {
34
 
35
  /**
36
  * @param string $evt
37
+ * @param array $meta
38
+ * @param array $def
39
  */
40
+ abstract protected function captureEvent( string $evt, $meta = [], $def = [] );
41
 
42
  protected function onShutdown() {
43
 
src/lib/src/Modules/Events/Lib/EventsService.php CHANGED
@@ -18,9 +18,14 @@ class EventsService {
18
  * @param array $meta
19
  * @return $this
20
  */
21
- public function fireEvent( $event, $meta = [] ) {
22
  if ( $this->isSupportedEvent( $event ) ) {
23
- do_action( $this->getCon()->prefix( 'event' ), $event, $meta );
 
 
 
 
 
24
  }
25
  return $this;
26
  }
18
  * @param array $meta
19
  * @return $this
20
  */
21
+ public function fireEvent( string $event, $meta = [] ) {
22
  if ( $this->isSupportedEvent( $event ) ) {
23
+ do_action(
24
+ $this->getCon()->prefix( 'event' ),
25
+ $event,
26
+ $meta,
27
+ $this->getEventDef( $event )
28
+ );
29
  }
30
  return $this;
31
  }
src/lib/src/Modules/Events/Lib/Reports/KeyStats.php CHANGED
@@ -12,16 +12,16 @@ class KeyStats extends BaseReporter {
12
  * @inheritDoc
13
  */
14
  public function build() {
15
- $aAlerts = [];
16
 
17
  /** @var Events\ModCon $mod */
18
  $mod = $this->getMod();
19
- /** @var DBEvents\Select $oSelEvts */
20
- $oSelEvts = $mod->getDbHandler_Events()->getQuerySelector();
21
- /** @var Events\Strings $oStrings */
22
- $oStrings = $mod->getStrings();
23
 
24
- $aEventKeys = [
25
  'ip_offense',
26
  'ip_blocked',
27
  'conn_kill',
@@ -38,19 +38,18 @@ class KeyStats extends BaseReporter {
38
  'spam_block_human',
39
  ];
40
 
41
- $oRep = $this->getReport();
42
 
43
- $aCounts = [];
44
- foreach ( $aEventKeys as $sEvent ) {
45
  try {
46
- $nCount = $oSelEvts
47
- ->filterByEvent( $sEvent )
48
- ->filterByBoundary( $oRep->interval_start_at, $oRep->interval_end_at )
49
- ->count();
50
- if ( $nCount > 0 ) {
51
- $aCounts[ $sEvent ] = [
52
- 'count' => $nCount,
53
- 'name' => $oStrings->getEventName( $sEvent ),
54
  ];
55
  }
56
  }
@@ -58,12 +57,12 @@ class KeyStats extends BaseReporter {
58
  }
59
  }
60
 
61
- if ( count( $aCounts ) > 0 ) {
62
- $aAlerts[] = $this->getMod()->renderTemplate(
63
  '/components/reports/mod/events/info_keystats.twig',
64
  [
65
  'vars' => [
66
- 'counts' => $aCounts
67
  ],
68
  'strings' => [
69
  'title' => __( 'Top Security Statistics', 'wp-simple-firewall' ),
@@ -74,6 +73,6 @@ class KeyStats extends BaseReporter {
74
  );
75
  }
76
 
77
- return $aAlerts;
78
  }
79
  }
12
  * @inheritDoc
13
  */
14
  public function build() {
15
+ $alerts = [];
16
 
17
  /** @var Events\ModCon $mod */
18
  $mod = $this->getMod();
19
+ /** @var DBEvents\Select $selector */
20
+ $selector = $mod->getDbHandler_Events()->getQuerySelector();
21
+ /** @var Events\Strings $strings */
22
+ $strings = $mod->getStrings();
23
 
24
+ $eventKeys = [
25
  'ip_offense',
26
  'ip_blocked',
27
  'conn_kill',
38
  'spam_block_human',
39
  ];
40
 
41
+ $rep = $this->getReport();
42
 
43
+ $sums = [];
44
+ foreach ( $eventKeys as $event ) {
45
  try {
46
+ $eventSum = $selector
47
+ ->filterByBoundary( $rep->interval_start_at, $rep->interval_end_at )
48
+ ->sumEvent( $event );
49
+ if ( $eventSum > 0 ) {
50
+ $sums[ $event ] = [
51
+ 'count' => $eventSum,
52
+ 'name' => $strings->getEventName( $event ),
 
53
  ];
54
  }
55
  }
57
  }
58
  }
59
 
60
+ if ( count( $sums ) > 0 ) {
61
+ $alerts[] = $this->getMod()->renderTemplate(
62
  '/components/reports/mod/events/info_keystats.twig',
63
  [
64
  'vars' => [
65
+ 'counts' => $sums
66
  ],
67
  'strings' => [
68
  'title' => __( 'Top Security Statistics', 'wp-simple-firewall' ),
73
  );
74
  }
75
 
76
+ return $alerts;
77
  }
78
  }
src/lib/src/Modules/Events/Lib/StatsWriter.php CHANGED
@@ -17,12 +17,18 @@ class StatsWriter extends EventsListener {
17
 
18
  /**
19
  * @param string $evt
20
- * @param array $aMeta
 
21
  */
22
- protected function captureEvent( $evt, $aMeta = [] ) {
23
- $aStats = $this->getEventStats();
24
- $aStats[ $evt ] = isset( $aMeta[ 'ts' ] ) ? $aMeta[ 'ts' ] : Services::Request()->ts();
25
- $this->setEventStats( $aStats );
 
 
 
 
 
26
  }
27
 
28
  protected function onShutdown() {
17
 
18
  /**
19
  * @param string $evt
20
+ * @param array $meta
21
+ * @param array $def
22
  */
23
+ protected function captureEvent( string $evt, $meta = [], $def = [] ) {
24
+ if ( empty( $def ) ) {
25
+ $def = $this->getCon()->loadEventsService()->getEventDef( $evt );
26
+ }
27
+ if ( !empty( $def[ 'stat' ] ) ) {
28
+ $stats = $this->getEventStats();
29
+ $stats[ $evt ] = $meta[ 'ts' ] ?? Services::Request()->ts();
30
+ $this->setEventStats( $stats );
31
+ }
32
  }
33
 
34
  protected function onShutdown() {
src/lib/src/Modules/Events/Strings.php CHANGED
@@ -37,6 +37,8 @@ class Strings extends Base\Strings {
37
  'ip_offense' => __( 'Offense Triggered', 'wp-simple-firewall' ),
38
  'ip_blocked' => __( 'IP Blocked', 'wp-simple-firewall' ),
39
  'ip_unblock_flag' => __( 'IP Unblocked Using Flag File', 'wp-simple-firewall' ),
 
 
40
  'bottrack_404' => sprintf( '%s: %s',
41
  __( 'Bot Detection', 'wp-simple-firewall' ),
42
  '404'
@@ -216,6 +218,10 @@ class Strings extends Base\Strings {
216
  'password_policy_block' => __( 'Password Change Blocked', 'wp-simple-firewall' ),
217
  'user_hard_suspended' => __( 'User Hard-Suspended', 'wp-simple-firewall' ),
218
  'user_hard_unsuspended' => __( 'User Hard-Unsuspended', 'wp-simple-firewall' ),
 
 
 
 
219
  'spam_block_bot' => sprintf( '%s: %s',
220
  __( 'SPAM Blocked', 'wp-simple-firewall' ),
221
  __( 'Bot', 'wp-simple-firewall' )
37
  'ip_offense' => __( 'Offense Triggered', 'wp-simple-firewall' ),
38
  'ip_blocked' => __( 'IP Blocked', 'wp-simple-firewall' ),
39
  'ip_unblock_flag' => __( 'IP Unblocked Using Flag File', 'wp-simple-firewall' ),
40
+ 'antibot_fail' => __( 'Fail AntiBot Test', 'wp-simple-firewall' ),
41
+ 'antibot_pass' => __( 'Pass AntiBot Test', 'wp-simple-firewall' ),
42
  'bottrack_404' => sprintf( '%s: %s',
43
  __( 'Bot Detection', 'wp-simple-firewall' ),
44
  '404'
218
  'password_policy_block' => __( 'Password Change Blocked', 'wp-simple-firewall' ),
219
  'user_hard_suspended' => __( 'User Hard-Suspended', 'wp-simple-firewall' ),
220
  'user_hard_unsuspended' => __( 'User Hard-Unsuspended', 'wp-simple-firewall' ),
221
+ 'spam_block_antibot' => sprintf( '%s: %s',
222
+ __( 'SPAM Blocked', 'wp-simple-firewall' ),
223
+ __( 'AntiBot System', 'wp-simple-firewall' )
224
+ ),
225
  'spam_block_bot' => sprintf( '%s: %s',
226
  __( 'SPAM Blocked', 'wp-simple-firewall' ),
227
  __( 'Bot', 'wp-simple-firewall' )
src/lib/src/Modules/Events/UI.php ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Events;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Databases;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
7
+ use FernleafSystems\Wordpress\Services\Services;
8
+
9
+ class UI extends BaseShield\UI {
10
+
11
+ public function buildInsightsVars() :array {
12
+ $stats = $this->buildStats();
13
+ return [
14
+ 'flags' => [
15
+ 'has_stats' => !empty( $stats )
16
+ ],
17
+ 'strings' => [
18
+ 'no_stats' => __('No stats yet. It wont take long though, so check back here soon.')
19
+ ],
20
+ 'vars' => [
21
+ 'stats' => $stats,
22
+ 'stat_intervals' => [
23
+ 'days_1' => '24 Hours',
24
+ 'days_7' => '7 Days',
25
+ 'months_1' => '1 Month',
26
+ 'lifetime' => 'Lifetime',
27
+ ]
28
+ ],
29
+ ];
30
+ }
31
+
32
+ private function buildStats() :array {
33
+ $allStats = [];
34
+
35
+ /** @var ModCon $mod */
36
+ $mod = $this->getMod();
37
+ /** @var Strings $strings */
38
+ $strings = $mod->getStrings();
39
+ foreach ( $this->getAllEvents() as $eventSection ) {
40
+ $stats = [];
41
+ foreach ( $eventSection as $event ) {
42
+ $sums = $this->buildSums( $event );
43
+ if ( !empty( array_filter( $sums ) ) ) {
44
+ $stats[ $event ] = [
45
+ 'key' => $event,
46
+ 'name' => $strings->getEventName( $event ),
47
+ 'counts' => $this->buildSums( $event ),
48
+ ];
49
+ }
50
+ }
51
+ if ( !empty( $stats ) ) {
52
+ $allStats[] = $stats;
53
+ }
54
+ }
55
+
56
+ return $allStats;
57
+ }
58
+
59
+ private function buildSums( $event ) :array {
60
+ /** @var ModCon $mod */
61
+ $mod = $this->getMod();
62
+ /** @var Databases\Events\Select $selector */
63
+ $selector = $mod->getDbHandler_Events()->getQuerySelector();
64
+ $carbon = Services::Request()->carbon( true );
65
+ return [
66
+ 'lifetime' => $selector->sumEvent( $event ),
67
+ 'months_1' => $selector
68
+ ->filterByCreatedAt( ( clone $carbon )->subDays( 30 )->startOfDay()->timestamp, '>' )
69
+ ->sumEvent( $event ),
70
+ 'days_7' => $selector
71
+ ->filterByCreatedAt( ( clone $carbon )->subDays( 7 )->startOfDay()->timestamp, '>' )
72
+ ->sumEvent( $event ),
73
+ 'days_1' => $selector
74
+ ->filterByCreatedAt( ( clone $carbon )->subHours( 24 )->timestamp, '>' )
75
+ ->sumEvent( $event ),
76
+ ];
77
+ }
78
+
79
+ private function getAllEvents() :array {
80
+ return [
81
+ [
82
+ 'ip_offense',
83
+ 'conn_kill',
84
+ 'ip_blocked',
85
+ ],
86
+ [
87
+ 'antibot_fail',
88
+ 'antibot_pass',
89
+ 'bottrack_404',
90
+ 'bottrack_fakewebcrawler',
91
+ 'bottrack_linkcheese',
92
+ 'bottrack_loginfailed',
93
+ 'bottrack_logininvalid',
94
+ 'bottrack_useragent',
95
+ 'bottrack_xmlrpc',
96
+ 'bottrack_invalidscript',
97
+ ],
98
+ [
99
+ 'spam_block_antibot',
100
+ 'spam_block_bot',
101
+ 'spam_block_recaptcha',
102
+ 'spam_block_human',
103
+ ],
104
+ [
105
+ 'cooldown_fail',
106
+ 'honeypot_fail',
107
+ 'botbox_fail',
108
+ 'login_block',
109
+ '2fa_success',
110
+ ],
111
+ ];
112
+ }
113
+ }
src/lib/src/Modules/Firewall/Lib/Scan/CanScan.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Firewall\Lib\Scan;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Firewall\Options;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
+ use FernleafSystems\Wordpress\Services\Services;
8
+
9
+ class CanScan {
10
+
11
+ use ModConsumer;
12
+
13
+ public function run() :bool {
14
+ /** @var Options $opts */
15
+ $opts = $this->getOptions();
16
+ $req = Services::Request();
17
+
18
+ $canScan = count( $req->getRawRequestParams( false ) ) > 0 && !empty( $req->getPath() );
19
+ if ( $canScan ) {
20
+ $paramsToScan = ( new ParametersToScan() )
21
+ ->setMod( $this->getMod() )
22
+ ->retrieve();
23
+ $canScan = count( $paramsToScan ) > 0
24
+ && ( !$opts->isIgnoreAdmin() && is_super_admin() );
25
+ }
26
+ return $canScan;
27
+ }
28
+ }
src/lib/src/Modules/Firewall/Lib/Scan/Checks/Base.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Firewall\Lib\Scan\Checks;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
+
7
+ class Base {
8
+
9
+ use ModConsumer;
10
+
11
+ protected $check;
12
+
13
+ /**
14
+ * @param string $check
15
+ * @return $this
16
+ */
17
+ public function setCheck( string $check ) {
18
+ $this->check = $check;
19
+ return $this;
20
+ }
21
+
22
+ protected function getFirewallPatterns() :array {
23
+ return $this->getOptions()->getDef( 'firewall_patterns' )[ $this->check ] ?? [];
24
+ }
25
+
26
+ protected function getFirewallPatterns_Regex() :array {
27
+ return array_map(
28
+ function ( $regex ) {
29
+ return '/'.$regex.'/i';
30
+ },
31
+ $this->getFirewallPatterns()[ 'regex' ] ?? []
32
+ );
33
+ }
34
+
35
+ protected function getFirewallPatterns_Simple() :array {
36
+ return $this->getFirewallPatterns()[ 'simple' ] ?? [];
37
+ }
38
+ }
src/lib/src/Modules/Firewall/Lib/Scan/Checks/ExeFiles.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Firewall\Lib\Scan\Checks;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
+
7
+ class ExeFiles extends Base {
8
+
9
+ use ModConsumer;
10
+
11
+ /**
12
+ * @return false|\WP_Error
13
+ */
14
+ public function run() {
15
+ $found = false;
16
+ foreach ( $this->getFileNames() as $param => $file ) {
17
+ foreach ( $this->getFirewallPatterns_Regex() as $term ) {
18
+ if ( preg_match( $term, $file ) ) {
19
+ $found = new \WP_Error( 'shield-firewall', '', [
20
+ 'term' => $term,
21
+ 'param' => $param,
22
+ 'value' => $file,
23
+ 'check' => $this->check,
24
+ 'type' => 'regex',
25
+ ] );
26
+ break( 2 );
27
+ }
28
+ }
29
+ }
30
+ return $found;
31
+ }
32
+
33
+ private function getFileNames() :array {
34
+ return array_filter( array_map(
35
+ function ( $file ) {
36
+ return $file[ 'name' ] ?? '';
37
+ },
38
+ ( !empty( $_FILES ) && is_array( $_FILES ) ) ? $_FILES : []
39
+ ) );
40
+ }
41
+ }
src/lib/src/Modules/Firewall/Lib/Scan/Checks/Standard.php ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Firewall\Lib\Scan\Checks;
4
+
5
+ class Standard extends Base {
6
+
7
+ private $params;
8
+
9
+ /**
10
+ * @param array $params
11
+ * @return false|\WP_Error
12
+ */
13
+ public function run( array $params ) {
14
+ $checkResult = false;
15
+
16
+ $this->params = $params;
17
+
18
+ if ( !empty( $this->getFirewallPatterns() ) ) {
19
+ $checkResult = $this->testSimplePatterns();
20
+ if ( !is_wp_error( $checkResult ) ) {
21
+ $checkResult = $this->testRegexPatterns();
22
+ }
23
+ }
24
+
25
+ return $checkResult;
26
+ }
27
+
28
+ /**
29
+ * @return false|\WP_Error
30
+ */
31
+ protected function testRegexPatterns() {
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,
39
+ 'check' => $this->check,
40
+ 'type' => 'regex',
41
+ ] );
42
+ break( 2 );
43
+ }
44
+ }
45
+ }
46
+ return $found;
47
+ }
48
+
49
+ /**
50
+ * @return false|\WP_Error
51
+ */
52
+ protected function testSimplePatterns() {
53
+ $found = false;
54
+ foreach ( $this->getFirewallPatterns_Simple() as $term ) {
55
+ foreach ( $this->params as $param => $value ) {
56
+ if ( stripos( $value, $term ) !== false ) {
57
+ $found = new \WP_Error( 'shield-firewall', '', [
58
+ 'param' => $param,
59
+ 'value' => $value,
60
+ 'check' => $this->check,
61
+ 'type' => 'simple',
62
+ ] );
63
+ break( 2 );
64
+ }
65
+ }
66
+ }
67
+ return $found;
68
+ }
69
+ }
src/lib/src/Modules/Firewall/Lib/Scan/ParametersToScan.php ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Firewall\Lib\Scan;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Firewall\Options;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
+ use FernleafSystems\Wordpress\Services\Services;
8
+
9
+ class ParametersToScan {
10
+
11
+ use ModConsumer;
12
+
13
+ private $params = [];
14
+
15
+ public function retrieve() :array {
16
+
17
+ // Ensure strings and remove non-scalar entries
18
+ $this->params = array_map( 'strval', array_filter(
19
+ Services::Request()->getRawRequestParams( false ),
20
+ function ( $value ) {
21
+ return is_scalar( $value );
22
+ }
23
+ ) );
24
+
25
+ if ( !empty( $this->params ) ) {
26
+ $this->removeParamsBasedOnPageName();
27
+ }
28
+
29
+ if ( !empty( $this->params ) ) {
30
+ $this->removeAllPageParams();
31
+ }
32
+
33
+ return $this->params;
34
+ }
35
+
36
+ private function removeAllPageParams() {
37
+ foreach ( $this->getAllPageWhitelistedParameters() as $listParam ) {
38
+
39
+ if ( preg_match( '#^/.+/$#', $listParam ) ) {
40
+ foreach ( array_keys( $this->params ) as $param ) {
41
+ if ( preg_match( $listParam, $param ) ) {
42
+ unset( $this->params[ $param ] );
43
+ }
44
+ }
45
+ }
46
+ elseif ( isset( $params[ $listParam ] ) ) {
47
+ unset( $params[ $listParam ] );
48
+ }
49
+ }
50
+ }
51
+
52
+ private function removeParamsBasedOnPageName() {
53
+ // Now we run through the list of whitelist pages
54
+ $thePage = Services::Request()->getPath();
55
+ foreach ( $this->getWhitelistedParameters() as $pageName => $pageParams ) {
56
+
57
+ // if the page is white listed
58
+ if ( $pageName !== '*' && strpos( $thePage, $pageName ) !== false ) {
59
+
60
+ /**
61
+ * If the page has no parameters, then remove all parameters to scan
62
+ * Otherwise, remove only those parameter specified
63
+ */
64
+ $this->params = empty( $pageParams ) ? []
65
+ : array_diff_key( $this->params, array_flip( $pageParams ) );
66
+ break;
67
+ }
68
+ }
69
+ }
70
+
71
+ private function getAllPageWhitelistedParameters() :array {
72
+ $all = $this->getWhitelistedParameters()[ '*' ] ?? [];
73
+ return is_array( $all ) ? $all : [];
74
+ }
75
+
76
+ private function getWhitelistedParameters() :array {
77
+ /** @var Options $opts */
78
+ $opts = $this->getOptions();
79
+ return Services::DataManipulation()
80
+ ->mergeArraysRecursive(
81
+ $opts->getDef( 'default_whitelist' ),
82
+ $opts->getCustomWhitelist()
83
+ );
84
+ }
85
+ }
src/lib/src/Modules/Firewall/Lib/Scan/PerformScan.php ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Firewall\Lib\Scan;
4
+
5
+ use FernleafSystems\Utilities\Logic\ExecOnce;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
+
8
+ class PerformScan {
9
+
10
+ use ModConsumer;
11
+ use ExecOnce;
12
+
13
+ /**
14
+ * @var false|\WP_Error
15
+ */
16
+ private $checkResult = false;
17
+
18
+ /**
19
+ * @return false|\WP_Error
20
+ */
21
+ public function getCheckResult() {
22
+ return $this->checkResult;
23
+ }
24
+
25
+ protected function canRun() :bool {
26
+ return ( new CanScan() )
27
+ ->setMod( $this->getMod() )
28
+ ->run();
29
+ }
30
+
31
+ protected function run() {
32
+ $opts = $this->getOptions();
33
+
34
+ $params = ( new ParametersToScan() )
35
+ ->setMod( $this->getMod() )
36
+ ->retrieve();
37
+
38
+ $standardChecker = ( new Checks\Standard() )
39
+ ->setMod( $this->getMod() );
40
+ foreach ( $this->getStandardChecks() as $opt => $check ) {
41
+ if ( $opts->isOpt( 'block_'.$opt, 'Y' ) ) {
42
+ $this->checkResult = $standardChecker
43
+ ->setCheck( $check )
44
+ ->run( $params );
45
+ if ( is_wp_error( $this->checkResult ) ) {
46
+ break;
47
+ }
48
+ }
49
+ }
50
+
51
+ if ( !is_wp_error( $this->checkResult ) ) {
52
+ $this->checkResult = ( new Checks\ExeFiles() )
53
+ ->setMod( $this->getMod() )
54
+ ->setCheck( 'exefile' )
55
+ ->run();
56
+ }
57
+ }
58
+
59
+ private function getStandardChecks() :array {
60
+ return [
61
+ 'dir_traversal' => 'dirtraversal',
62
+ 'sql_queries' => 'sqlqueries',
63
+ 'wordpress_terms' => 'wpterms',
64
+ 'field_truncation' => 'fieldtruncation',
65
+ 'php_code' => 'phpcode',
66
+ 'leading_schema' => 'schema',
67
+ 'aggressive' => 'aggressive',
68
+ ];
69
+ }
70
+ }
src/lib/src/Modules/Firewall/Options.php CHANGED
@@ -7,8 +7,8 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
7
  class Options extends BaseShield\Options {
8
 
9
  public function getCustomWhitelist() :array {
10
- $aW = $this->getOpt( 'page_params_whitelist', [] );
11
- return is_array( $aW ) ? $aW : [];
12
  }
13
 
14
  public function isIgnoreAdmin() :bool {
7
  class Options extends BaseShield\Options {
8
 
9
  public function getCustomWhitelist() :array {
10
+ $w = $this->getOpt( 'page_params_whitelist', [] );
11
+ return is_array( $w ) ? $w : [];
12
  }
13
 
14
  public function isIgnoreAdmin() :bool {
src/lib/src/Modules/Firewall/Processor.php CHANGED
@@ -10,7 +10,7 @@ class Processor extends BaseShield\Processor {
10
  /**
11
  * @var array
12
  */
13
- private $aDieMessage;
14
 
15
  /**
16
  * @var array
@@ -48,12 +48,11 @@ class Processor extends BaseShield\Processor {
48
  /** @var Options $opts */
49
  $opts = $this->getOptions();
50
 
51
- $sPath = Services::Request()->getPath();
52
-
53
  if ( count( $this->getRawRequestParams() ) == 0 ) {
54
  $bPerformScan = false;
55
  }
56
- elseif ( empty( $sPath ) ) {
57
  $this->getCon()->fireEvent( 'firewall_skip' );
58
  $bPerformScan = false;
59
  }
@@ -68,6 +67,13 @@ class Processor extends BaseShield\Processor {
68
  return $bPerformScan;
69
  }
70
 
 
 
 
 
 
 
 
71
  private function isVisitorRequestPermitted() :bool {
72
  $opts = $this->getOptions();
73
 
@@ -277,10 +283,10 @@ class Processor extends BaseShield\Processor {
277
  }
278
 
279
  protected function getFirewallDieMessage() :array {
280
- if ( !isset( $this->aDieMessage ) || !is_array( $this->aDieMessage ) ) {
281
- $this->aDieMessage = [ $this->getMod()->getTextOpt( 'text_firewalldie' ) ];
282
  }
283
- return $this->aDieMessage;
284
  }
285
 
286
  protected function getFirewallDieMessageForDisplay() :string {
@@ -292,13 +298,13 @@ class Processor extends BaseShield\Processor {
292
  }
293
 
294
  /**
295
- * @param string $sMessagePart
296
  * @return $this
297
  */
298
- protected function addToFirewallDieMessage( $sMessagePart ) {
299
- $aMessages = $this->getFirewallDieMessage();
300
- $aMessages[] = $sMessagePart;
301
- $this->aDieMessage = $aMessages;
302
  return $this;
303
  }
304
 
@@ -363,7 +369,7 @@ class Processor extends BaseShield\Processor {
363
  }
364
 
365
  private function getRawRequestParams() :array {
366
- return Services::Request()->getRawRequestParams( $this->getOptions()->isOpt( 'include_cookie_checks', 'Y' ) );
367
  }
368
 
369
  private function sendBlockEmail( string $recipient ) :bool {
10
  /**
11
  * @var array
12
  */
13
+ private $dieMessage;
14
 
15
  /**
16
  * @var array
48
  /** @var Options $opts */
49
  $opts = $this->getOptions();
50
 
51
+ $path = Services::Request()->getPath();
 
52
  if ( count( $this->getRawRequestParams() ) == 0 ) {
53
  $bPerformScan = false;
54
  }
55
+ elseif ( empty( $path ) ) {
56
  $this->getCon()->fireEvent( 'firewall_skip' );
57
  $bPerformScan = false;
58
  }
67
  return $bPerformScan;
68
  }
69
 
70
+ private function runScan() :bool {
71
+ $scanner = ( new Lib\Scan\PerformScan() )
72
+ ->setMod( $this->getMod() );
73
+ $scanner->execute();
74
+ $result = $scanner->getCheckResult();
75
+ }
76
+
77
  private function isVisitorRequestPermitted() :bool {
78
  $opts = $this->getOptions();
79
 
283
  }
284
 
285
  protected function getFirewallDieMessage() :array {
286
+ if ( !isset( $this->dieMessage ) || !is_array( $this->dieMessage ) ) {
287
+ $this->dieMessage = [ $this->getMod()->getTextOpt( 'text_firewalldie' ) ];
288
  }
289
+ return $this->dieMessage;
290
  }
291
 
292
  protected function getFirewallDieMessageForDisplay() :string {
298
  }
299
 
300
  /**
301
+ * @param string $msg
302
  * @return $this
303
  */
304
+ protected function addToFirewallDieMessage( string $msg ) {
305
+ $messages = $this->getFirewallDieMessage();
306
+ $messages[] = $msg;
307
+ $this->dieMessage = $messages;
308
  return $this;
309
  }
310
 
369
  }
370
 
371
  private function getRawRequestParams() :array {
372
+ return Services::Request()->getRawRequestParams( false );
373
  }
374
 
375
  private function sendBlockEmail( string $recipient ) :bool {
src/lib/src/Modules/HackGuard/AjaxHandler.php CHANGED
@@ -4,6 +4,7 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Databases;
 
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\FileLocker;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Scan;
9
  use FernleafSystems\Wordpress\Services\Services;
@@ -66,8 +67,7 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
66
  /** @var ModCon $mod */
67
  $mod = $this->getMod();
68
 
69
- $sScanSlug = Services::Request()->post( 'fScan' );
70
- switch ( $sScanSlug ) {
71
 
72
  case 'aggregate':
73
  $oTableBuilder = new Shield\Tables\Build\ScanAggregate();
@@ -147,6 +147,8 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
147
  'modified_file' => __( 'Modified File' ),
148
  'locked' => __( 'Locked' ),
149
  'modified_timestamp' => __( 'File Modified Timestamp' ),
 
 
150
  'modified' => __( 'Modified' ),
151
  'download' => __( 'Download' ),
152
  'change_detected_at' => __( 'Change Detected' ),
@@ -156,14 +158,17 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
156
  'download_modified' => __( 'Download Modified' ),
157
  'file_download' => __( 'File Download' ),
158
  'file_info' => __( 'File Info' ),
159
- 'file_accept' => __( 'File Accept' ),
160
  'file_accept_checkbox' => __( 'Are you sure you want to keep the file changes?' ),
161
- 'file_restore' => __( 'File Restore' ),
162
  'file_restore_checkbox' => __( 'Are you sure you want to restore the original file contents?' ),
163
  'file_restore_button' => __( 'Are you sure you want to restore the original file contents?' ),
164
  ]
165
  ];
166
  try {
 
 
 
167
 
168
  $lock = $oFLCon->getFileLock( $nRID );
169
  $bDiff = $lock->detected_at > 0;
@@ -174,11 +179,24 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
174
  ->setMod( $this->getMod() )
175
  ->run( $nRID, 'diff' ) : '';
176
 
177
- $oCarb = Services::Request()->carbon( true );
178
- $data[ 'vars' ][ 'locked_at' ] = $oCarb->setTimestamp( $lock->created_at )->diffForHumans();
 
 
 
 
 
 
 
 
 
 
 
179
  $data[ 'vars' ][ 'file_modified_at' ] =
180
  Services::WpGeneral()->getTimeStampForDisplay( $FS->getModifiedTime( $lock->file ) );
181
- $data[ 'vars' ][ 'change_detected_at' ] = $oCarb->setTimestamp( $lock->detected_at )->diffForHumans();
 
 
182
  $data[ 'vars' ][ 'file_size_locked' ] = Shield\Utilities\Tool\FormatBytes::Format( strlen(
183
  ( new FileLocker\Ops\ReadOriginalFileContent() )
184
  ->setMod( $mod )
@@ -199,7 +217,7 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
199
  'message' => $data[ 'error' ],
200
  'html' => $this->getMod()
201
  ->renderTemplate(
202
- '/wpadmin_pages/insights/scans/realtime/file_locker/file_diff.twig',
203
  $data,
204
  true
205
  )
@@ -255,10 +273,10 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
255
 
256
  /**
257
  * @param string $action
258
- * @param bool $bIsBulkAction
259
  * @return array
260
  */
261
- private function ajaxExec_ScanItemAction( $action, $bIsBulkAction = false ) :array {
262
  /** @var ModCon $mod */
263
  $mod = $this->getMod();
264
 
@@ -270,7 +288,7 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
270
  $msg = __( 'File download has started.', 'wp-simple-firewall' );
271
  }
272
  else {
273
- if ( $bIsBulkAction ) {
274
  $itemIDs = (array)Services::Request()->post( 'ids', [] );
275
  }
276
  else {
@@ -380,7 +398,7 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
380
  $success = false;
381
  $reloadPage = false;
382
  $msg = __( 'No scans were selected', 'wp-simple-firewall' );
383
- $formParams = $this->getAjaxFormParams();
384
 
385
  $scanCon = $mod->getScanQueueController();
386
 
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Databases;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Request\FormParams;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\FileLocker;
9
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Scan;
10
  use FernleafSystems\Wordpress\Services\Services;
67
  /** @var ModCon $mod */
68
  $mod = $this->getMod();
69
 
70
+ switch ( Services::Request()->post( 'fScan', '' ) ) {
 
71
 
72
  case 'aggregate':
73
  $oTableBuilder = new Shield\Tables\Build\ScanAggregate();
147
  'modified_file' => __( 'Modified File' ),
148
  'locked' => __( 'Locked' ),
149
  'modified_timestamp' => __( 'File Modified Timestamp' ),
150
+ 'file_modified' => __( 'File Modified' ),
151
+ 'relative_path' => __( 'Relative Path' ),
152
  'modified' => __( 'Modified' ),
153
  'download' => __( 'Download' ),
154
  'change_detected_at' => __( 'Change Detected' ),
158
  'download_modified' => __( 'Download Modified' ),
159
  'file_download' => __( 'File Download' ),
160
  'file_info' => __( 'File Info' ),
161
+ 'file_accept' => __( 'Accept File Changes' ),
162
  'file_accept_checkbox' => __( 'Are you sure you want to keep the file changes?' ),
163
+ 'file_restore' => __( 'Restore Original File' ),
164
  'file_restore_checkbox' => __( 'Are you sure you want to restore the original file contents?' ),
165
  'file_restore_button' => __( 'Are you sure you want to restore the original file contents?' ),
166
  ]
167
  ];
168
  try {
169
+ if ( !is_numeric( $nRID ) ) {
170
+ throw new \Exception( 'Not a valid file lock request.' );
171
+ }
172
 
173
  $lock = $oFLCon->getFileLock( $nRID );
174
  $bDiff = $lock->detected_at > 0;
179
  ->setMod( $this->getMod() )
180
  ->run( $nRID, 'diff' ) : '';
181
 
182
+ $carb = Services::Request()->carbon( true );
183
+
184
+ $absPath = wp_normalize_path( ABSPATH );
185
+ $filePath = wp_normalize_path( $lock->file );
186
+ if ( strpos( $filePath, $absPath ) !== false ) {
187
+ $data[ 'vars' ][ 'relative_path' ] = str_replace( $absPath, '/', $filePath );
188
+ }
189
+ else {
190
+ $data[ 'vars' ][ 'relative_path' ] = '../'.basename( $filePath );
191
+ }
192
+
193
+ $data[ 'vars' ][ 'relative_path' ] = str_replace( wp_normalize_path( ABSPATH ), '/', wp_normalize_path( $lock->file ) );
194
+ $data[ 'vars' ][ 'locked_at' ] = $carb->setTimestamp( $lock->created_at )->diffForHumans();
195
  $data[ 'vars' ][ 'file_modified_at' ] =
196
  Services::WpGeneral()->getTimeStampForDisplay( $FS->getModifiedTime( $lock->file ) );
197
+ $data[ 'vars' ][ 'file_modified_ago' ] =
198
+ $carb->setTimestamp( $FS->getModifiedTime( $lock->file ) )->diffForHumans();
199
+ $data[ 'vars' ][ 'change_detected_at' ] = $carb->setTimestamp( $lock->detected_at )->diffForHumans();
200
  $data[ 'vars' ][ 'file_size_locked' ] = Shield\Utilities\Tool\FormatBytes::Format( strlen(
201
  ( new FileLocker\Ops\ReadOriginalFileContent() )
202
  ->setMod( $mod )
217
  'message' => $data[ 'error' ],
218
  'html' => $this->getMod()
219
  ->renderTemplate(
220
+ '/wpadmin_pages/insights/scans/results/realtime/file_locker/file_diff.twig',
221
  $data,
222
  true
223
  )
273
 
274
  /**
275
  * @param string $action
276
+ * @param bool $isBulkAction
277
  * @return array
278
  */
279
+ private function ajaxExec_ScanItemAction( $action, $isBulkAction = false ) :array {
280
  /** @var ModCon $mod */
281
  $mod = $this->getMod();
282
 
288
  $msg = __( 'File download has started.', 'wp-simple-firewall' );
289
  }
290
  else {
291
+ if ( $isBulkAction ) {
292
  $itemIDs = (array)Services::Request()->post( 'ids', [] );
293
  }
294
  else {
398
  $success = false;
399
  $reloadPage = false;
400
  $msg = __( 'No scans were selected', 'wp-simple-firewall' );
401
+ $formParams = FormParams::Retrieve();
402
 
403
  $scanCon = $mod->getScanQueueController();
404
 
src/lib/src/Modules/HackGuard/Insights/OverviewCards.php CHANGED
@@ -85,7 +85,7 @@ class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
85
  $cards[ 'wcf_problem' ] = [
86
  'name' => __( 'Core Files Changed', 'wp-simple-firewall' ),
87
  'summary' => __( 'WordPress core files have been modified.', 'wp-simple-firewall' ),
88
- 'href' => $this->getUrlForScans(),
89
  'state' => -2,
90
  'help' => __( 'Scan WP core files and repair any files that are flagged as modified.', 'wp-simple-firewall' )
91
  ];
@@ -129,7 +129,7 @@ class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
129
  'summary' => __( 'Unrecognised files found in WordPress Core directory.', 'wp-simple-firewall' ),
130
  'help' => __( 'Scan and remove any files that are not meant to be in the WP core directories.', 'wp-simple-firewall' ),
131
  'state' => -2,
132
- 'href' => $this->getUrlForScans(),
133
  ];
134
  }
135
 
@@ -158,7 +158,7 @@ class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
158
  'name' => $scanCon->getScanName(),
159
  'summary' => __( 'A plugin/theme was found to have been modified.', 'wp-simple-firewall' ),
160
  'state' => -2,
161
- 'href' => $this->getUrlForScans(),
162
  'help' => __( 'Reviewing modifications to your plugins/themes is recommended.', 'wp-simple-firewall' ),
163
 
164
  ];
@@ -189,7 +189,7 @@ class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
189
  'name' => __( 'Malware Detected', 'wp-simple-firewall' ),
190
  'summary' => __( 'Potential Malware files have been discovered.', 'wp-simple-firewall' ),
191
  'state' => -2,
192
- 'href' => $this->getUrlForScans(),
193
  'help' => __( 'Files identified as potential malware should be examined as soon as possible.', 'wp-simple-firewall' ),
194
  ];
195
  }
@@ -218,7 +218,7 @@ class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
218
  'name' => __( 'Plugin Abandoned' ),
219
  'summary' => __( 'At least 1 plugin on your site is abandoned.', 'wp-simple-firewall' ),
220
  'state' => -1,
221
- 'href' => $this->getUrlForScans(),
222
  'help' => __( 'Plugins that have been abandoned represent a potential risk to your site.', 'wp-simple-firewall' )
223
  ];
224
  }
@@ -260,7 +260,7 @@ class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
260
  'name' => __( 'Vulnerable Plugin', 'wp-simple-firewall' ),
261
  'summary' => __( 'Plugin with vulnerabilities found on site.', 'wp-simple-firewall' ),
262
  'state' => -2,
263
- 'href' => $this->getUrlForScans(),
264
  'help' => __( 'Items with known vulnerabilities should be updated, removed, or replaced.', 'wp-simple-firewall' )
265
  ];
266
  }
@@ -268,7 +268,7 @@ class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
268
  return $cards;
269
  }
270
 
271
- private function getUrlForScans() :string {
272
- return $this->getCon()->getModule_Insights()->getUrl_SubInsightsPage( 'scans' );
273
  }
274
  }
85
  $cards[ 'wcf_problem' ] = [
86
  'name' => __( 'Core Files Changed', 'wp-simple-firewall' ),
87
  'summary' => __( 'WordPress core files have been modified.', 'wp-simple-firewall' ),
88
+ 'href' => $this->getUrlForScanResults(),
89
  'state' => -2,
90
  'help' => __( 'Scan WP core files and repair any files that are flagged as modified.', 'wp-simple-firewall' )
91
  ];
129
  'summary' => __( 'Unrecognised files found in WordPress Core directory.', 'wp-simple-firewall' ),
130
  'help' => __( 'Scan and remove any files that are not meant to be in the WP core directories.', 'wp-simple-firewall' ),
131
  'state' => -2,
132
+ 'href' => $this->getUrlForScanResults(),
133
  ];
134
  }
135
 
158
  'name' => $scanCon->getScanName(),
159
  'summary' => __( 'A plugin/theme was found to have been modified.', 'wp-simple-firewall' ),
160
  'state' => -2,
161
+ 'href' => $this->getUrlForScanResults(),
162
  'help' => __( 'Reviewing modifications to your plugins/themes is recommended.', 'wp-simple-firewall' ),
163
 
164
  ];
189
  'name' => __( 'Malware Detected', 'wp-simple-firewall' ),
190
  'summary' => __( 'Potential Malware files have been discovered.', 'wp-simple-firewall' ),
191
  'state' => -2,
192
+ 'href' => $this->getUrlForScanResults(),
193
  'help' => __( 'Files identified as potential malware should be examined as soon as possible.', 'wp-simple-firewall' ),
194
  ];
195
  }
218
  'name' => __( 'Plugin Abandoned' ),
219
  'summary' => __( 'At least 1 plugin on your site is abandoned.', 'wp-simple-firewall' ),
220
  'state' => -1,
221
+ 'href' => $this->getUrlForScanResults(),
222
  'help' => __( 'Plugins that have been abandoned represent a potential risk to your site.', 'wp-simple-firewall' )
223
  ];
224
  }
260
  'name' => __( 'Vulnerable Plugin', 'wp-simple-firewall' ),
261
  'summary' => __( 'Plugin with vulnerabilities found on site.', 'wp-simple-firewall' ),
262
  'state' => -2,
263
+ 'href' => $this->getUrlForScanResults(),
264
  'help' => __( 'Items with known vulnerabilities should be updated, removed, or replaced.', 'wp-simple-firewall' )
265
  ];
266
  }
268
  return $cards;
269
  }
270
 
271
+ private function getUrlForScanResults() :string{
272
+ return $this->getCon()->getModule_Insights()->getUrl_ScansResults();
273
  }
274
  }
src/lib/src/Modules/HackGuard/Lib/FileLocker/File.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\FileLocker;
4
 
5
- use FernleafSystems\Utilities\Data\Adapter\DynProperties;
6
  use FernleafSystems\Wordpress\Services\Services;
7
 
8
  /**
@@ -13,15 +13,24 @@ use FernleafSystems\Wordpress\Services\Services;
13
  * @property int $max_levels
14
  * @property int $max_paths
15
  */
16
- class File {
17
-
18
- use DynProperties;
19
 
20
  public function __construct( string $filename, $dir = ABSPATH ) {
21
  $this->file = $filename;
22
  $this->dir = wp_normalize_path( $dir );
23
  }
24
 
 
 
 
 
 
 
 
 
 
 
 
25
  /**
26
  * @return string[]
27
  */
@@ -50,14 +59,10 @@ class File {
50
  $workingDir = dirname( $workingDir );
51
  $dirCount++;
52
  } while (
53
- $dirCount < $this->getMaxDirLevels()
54
- && ( empty( $this->max_paths ) || count( $paths ) < $this->max_paths )
55
  );
56
 
57
  return $paths;
58
  }
59
-
60
- protected function getMaxDirLevels() :int {
61
- return (int)max( 1, (int)$this->max_levels );
62
- }
63
  }
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\FileLocker;
4
 
5
+ use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
6
  use FernleafSystems\Wordpress\Services\Services;
7
 
8
  /**
13
  * @property int $max_levels
14
  * @property int $max_paths
15
  */
16
+ class File extends DynPropertiesClass {
 
 
17
 
18
  public function __construct( string $filename, $dir = ABSPATH ) {
19
  $this->file = $filename;
20
  $this->dir = wp_normalize_path( $dir );
21
  }
22
 
23
+ public function __get( string $key ) {
24
+ $value = parent::__get( $key );
25
+ switch ( $key ) {
26
+ case 'max_paths':
27
+ case 'max_level':
28
+ $value = (int)max( 1, $value );
29
+ break;
30
+ }
31
+ return $value;
32
+ }
33
+
34
  /**
35
  * @return string[]
36
  */
59
  $workingDir = dirname( $workingDir );
60
  $dirCount++;
61
  } while (
62
+ $dirCount < $this->max_levels
63
+ && ( empty( $this->max_paths ) || count( $paths ) <= $this->max_paths )
64
  );
65
 
66
  return $paths;
67
  }
 
 
 
 
68
  }
src/lib/src/Modules/HackGuard/Lib/FileLocker/FileLockerController.php CHANGED
@@ -38,10 +38,15 @@ class FileLockerController {
38
 
39
  public function processFileLocks() {
40
  if ( !$this->getCon()->plugin_deactivating && !$this->getCon()->is_my_upgrade ) {
41
- $this->getOptions()->isOptChanged( 'file_locker' ) ? $this->deleteAllLocks() : $this->runAnalysis();
42
  }
43
  }
44
 
 
 
 
 
 
45
  public function addAdminMenuBarItem( array $items ) :array {
46
  $problems = $this->countProblems();
47
  if ( $problems > 0 ) {
@@ -49,7 +54,7 @@ class FileLockerController {
49
  'id' => $this->getCon()->prefix( 'filelocker_problems' ),
50
  'title' => __( 'File Locker', 'wp-simple-firewall' )
51
  .sprintf( '<div class="wp-core-ui wp-ui-notification shield-counter"><span aria-hidden="true">%s</span></div>', $problems ),
52
- 'href' => $this->getCon()->getModule_Insights()->getUrl_SubInsightsPage( 'scans' ),
53
  'warnings' => $problems
54
  ];
55
  }
@@ -171,62 +176,63 @@ class FileLockerController {
171
  }
172
  if ( $lockCreated ) {
173
  $state[ 'last_locks_created_at' ] = Services::Request()->ts();
174
- $this->setState( $state );
175
  }
 
 
 
176
  }
177
  }
178
 
179
  /**
180
  * @param string $fileKey
181
- * @return File|null
182
  * @throws \Exception
183
  */
184
- private function getFile( $fileKey ) {
185
- $oFile = null;
186
 
187
- $bIsSplitWp = false;
188
- $nMaxPaths = 0;
189
  switch ( $fileKey ) {
190
  case 'wpconfig':
191
  $fileKey = 'wp-config.php';
192
- $nMaxPaths = 1;
193
- $nLevels = $bIsSplitWp ? 3 : 2;
194
-
195
  $openBaseDir = ini_get( 'open_basedir' );
196
  if ( !empty( $openBaseDir ) ) {
197
- $nLevels--;
198
  }
199
- // TODO: is split URL?
200
  break;
201
 
202
  case 'root_htaccess':
203
  $fileKey = '.htaccess';
204
- $nLevels = $bIsSplitWp ? 2 : 1;
205
  break;
206
 
207
  case 'root_webconfig':
208
  $fileKey = 'Web.Config';
209
- $nLevels = $bIsSplitWp ? 2 : 1;
210
  break;
211
 
212
  case 'root_index':
213
  $fileKey = 'index.php';
214
- $nLevels = $bIsSplitWp ? 2 : 1;
215
  break;
216
  default:
217
  if ( Services::WpFs()->isAbsPath( $fileKey ) && Services::WpFs()->isFile( $fileKey ) ) {
218
- $nLevels = 1;
219
- $nMaxPaths = 1;
220
  }
221
  else {
222
  throw new \Exception( 'Not a supported file lock type' );
223
  }
224
  break;
225
  }
226
- $oFile = new File( $fileKey );
227
- $oFile->max_levels = $nLevels;
228
- $oFile->max_paths = $nMaxPaths;
229
- return $oFile;
 
230
  }
231
 
232
  protected function getState() :array {
@@ -234,7 +240,8 @@ class FileLockerController {
234
  $opts = $this->getOptions();
235
  return array_merge(
236
  [
237
- 'last_locks_created_at' => 0
 
238
  ],
239
  is_array( $opts->getOpt( 'filelocker_state' ) ) ? $opts->getOpt( 'filelocker_state' ) : []
240
  );
38
 
39
  public function processFileLocks() {
40
  if ( !$this->getCon()->plugin_deactivating && !$this->getCon()->is_my_upgrade ) {
41
+ $this->isFileLockerStateChanged() ? $this->deleteAllLocks() : $this->runAnalysis();
42
  }
43
  }
44
 
45
+ private function isFileLockerStateChanged() :bool {
46
+ return $this->getOptions()->isOptChanged( 'file_locker' )
47
+ || $this->getState()[ 'abspath' ] !== ABSPATH;
48
+ }
49
+
50
  public function addAdminMenuBarItem( array $items ) :array {
51
  $problems = $this->countProblems();
52
  if ( $problems > 0 ) {
54
  'id' => $this->getCon()->prefix( 'filelocker_problems' ),
55
  'title' => __( 'File Locker', 'wp-simple-firewall' )
56
  .sprintf( '<div class="wp-core-ui wp-ui-notification shield-counter"><span aria-hidden="true">%s</span></div>', $problems ),
57
+ 'href' => $this->getCon()->getModule_Insights()->getUrl_ScansResults(),
58
  'warnings' => $problems
59
  ];
60
  }
176
  }
177
  if ( $lockCreated ) {
178
  $state[ 'last_locks_created_at' ] = Services::Request()->ts();
 
179
  }
180
+
181
+ $state[ 'abspath' ] = ABSPATH;
182
+ $this->setState( $state );
183
  }
184
  }
185
 
186
  /**
187
  * @param string $fileKey
188
+ * @return File
189
  * @throws \Exception
190
  */
191
+ private function getFile( string $fileKey ) :File {
192
+ $file = null;
193
 
194
+ $isSplitWpUrl = false; // TODO: is split URL?
195
+ $maxPaths = 1;
196
  switch ( $fileKey ) {
197
  case 'wpconfig':
198
  $fileKey = 'wp-config.php';
199
+ $maxPaths = 1;
200
+ $levels = $isSplitWpUrl ? 3 : 2;
 
201
  $openBaseDir = ini_get( 'open_basedir' );
202
  if ( !empty( $openBaseDir ) ) {
203
+ $levels--;
204
  }
 
205
  break;
206
 
207
  case 'root_htaccess':
208
  $fileKey = '.htaccess';
209
+ $levels = $isSplitWpUrl ? 2 : 1;
210
  break;
211
 
212
  case 'root_webconfig':
213
  $fileKey = 'Web.Config';
214
+ $levels = $isSplitWpUrl ? 2 : 1;
215
  break;
216
 
217
  case 'root_index':
218
  $fileKey = 'index.php';
219
+ $levels = $isSplitWpUrl ? 2 : 1;
220
  break;
221
  default:
222
  if ( Services::WpFs()->isAbsPath( $fileKey ) && Services::WpFs()->isFile( $fileKey ) ) {
223
+ $levels = 1;
224
+ $maxPaths = 1;
225
  }
226
  else {
227
  throw new \Exception( 'Not a supported file lock type' );
228
  }
229
  break;
230
  }
231
+
232
+ $file = new File( $fileKey );
233
+ $file->max_levels = $levels;
234
+ $file->max_paths = $maxPaths;
235
+ return $file;
236
  }
237
 
238
  protected function getState() :array {
240
  $opts = $this->getOptions();
241
  return array_merge(
242
  [
243
+ 'abspath' => ABSPATH,
244
+ 'last_locks_created_at' => 0,
245
  ],
246
  is_array( $opts->getOpt( 'filelocker_state' ) ) ? $opts->getOpt( 'filelocker_state' ) : []
247
  );
src/lib/src/Modules/HackGuard/Lib/FileLocker/Ops/BaseOps.php CHANGED
@@ -19,28 +19,28 @@ class BaseOps {
19
  /**
20
  * @var FileLocker\File
21
  */
22
- protected $oFile;
23
 
24
  /**
25
  * @return Databases\FileLocker\EntryVO|null
26
  */
27
  protected function findLockRecordForFile() {
28
- $oTheRecord = null;
29
- foreach ( $this->oFile->getPossiblePaths() as $sPath ) {
30
- foreach ( $this->getFileLocks() as $oRecord ) {
31
- if ( $oRecord->file === $sPath ) {
32
- $oTheRecord = $oRecord;
33
  break;
34
  }
35
  }
36
  }
37
- return $oTheRecord;
38
  }
39
 
40
  /**
41
- * @return Databases\FileLocker\EntryVO[]|null
42
  */
43
- protected function getFileLocks() {
44
  return ( new LoadFileLocks() )
45
  ->setMod( $this->getMod() )
46
  ->loadLocks();
@@ -71,11 +71,11 @@ class BaseOps {
71
  }
72
 
73
  /**
74
- * @param FileLocker\File $oFile
75
  * @return $this
76
  */
77
- public function setWorkingFile( FileLocker\File $oFile ) {
78
- $this->oFile = $oFile;
79
  return $this;
80
  }
81
  }
19
  /**
20
  * @var FileLocker\File
21
  */
22
+ protected $file;
23
 
24
  /**
25
  * @return Databases\FileLocker\EntryVO|null
26
  */
27
  protected function findLockRecordForFile() {
28
+ $theLock = null;
29
+ foreach ( $this->file->getPossiblePaths() as $sPath ) {
30
+ foreach ( $this->getFileLocks() as $lock ) {
31
+ if ( $lock->file === $sPath ) {
32
+ $theLock = $lock;
33
  break;
34
  }
35
  }
36
  }
37
+ return $theLock;
38
  }
39
 
40
  /**
41
+ * @return Databases\FileLocker\EntryVO[]
42
  */
43
+ protected function getFileLocks() :array {
44
  return ( new LoadFileLocks() )
45
  ->setMod( $this->getMod() )
46
  ->loadLocks();
71
  }
72
 
73
  /**
74
+ * @param FileLocker\File $file
75
  * @return $this
76
  */
77
+ public function setWorkingFile( FileLocker\File $file ) {
78
+ $this->file = $file;
79
  return $this;
80
  }
81
  }
src/lib/src/Modules/HackGuard/Lib/FileLocker/Ops/CreateFileLocks.php CHANGED
@@ -17,7 +17,7 @@ class CreateFileLocks extends BaseOps {
17
  */
18
  public function create() :bool {
19
  $pathsProcessed = false;
20
- foreach ( $this->oFile->getExistingPossiblePaths() as $path ) {
21
  $theLock = null;
22
  foreach ( $this->getFileLocks() as $maybeLock ) {
23
  if ( $maybeLock->file === $path ) {
@@ -52,9 +52,9 @@ class CreateFileLocks extends BaseOps {
52
  ->setMod( $mod )
53
  ->build( $path, reset( $publicKey ) );
54
 
55
- /** @var FileLocker\Insert $oInserter */
56
- $oInserter = $mod->getDbHandler_FileLocker()->getQueryInserter();
57
- $success = $oInserter->insert( $entry );
58
 
59
  $this->clearFileLocksCache();
60
  }
17
  */
18
  public function create() :bool {
19
  $pathsProcessed = false;
20
+ foreach ( $this->file->getExistingPossiblePaths() as $path ) {
21
  $theLock = null;
22
  foreach ( $this->getFileLocks() as $maybeLock ) {
23
  if ( $maybeLock->file === $path ) {
52
  ->setMod( $mod )
53
  ->build( $path, reset( $publicKey ) );
54
 
55
+ /** @var FileLocker\Insert $inserter */
56
+ $inserter = $mod->getDbHandler_FileLocker()->getQueryInserter();
57
+ $success = $inserter->insert( $entry );
58
 
59
  $this->clearFileLocksCache();
60
  }
src/lib/src/Modules/HackGuard/Lib/FileLocker/Ops/DeleteFileLock.php CHANGED
@@ -5,29 +5,25 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\FileLock
5
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\FileLocker;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\ModCon;
7
 
8
- /**
9
- * Class DeleteFileLock
10
- * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\FileLocker\Ops
11
- */
12
  class DeleteFileLock extends BaseOps {
13
 
14
  /**
15
- * @param FileLocker\EntryVO $oLock
16
  * @return bool
17
  */
18
- public function delete( $oLock = null ) {
19
  /** @var ModCon $mod */
20
  $mod = $this->getMod();
21
- if ( empty( $oLock ) ) {
22
- $oLock = $this->findLockRecordForFile();
23
  }
24
- $bSuccess = $oLock instanceof FileLocker\EntryVO
25
- && $mod->getDbHandler_FileLocker()
26
- ->getQueryDeleter()
27
- ->deleteEntry( $oLock );
28
- if ( $bSuccess ) {
29
  $this->clearFileLocksCache();
30
  }
31
- return $bSuccess;
32
  }
33
  }
5
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\FileLocker;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\ModCon;
7
 
 
 
 
 
8
  class DeleteFileLock extends BaseOps {
9
 
10
  /**
11
+ * @param FileLocker\EntryVO|null $lock
12
  * @return bool
13
  */
14
+ public function delete( $lock = null ) :bool {
15
  /** @var ModCon $mod */
16
  $mod = $this->getMod();
17
+ if ( empty( $lock ) ) {
18
+ $lock = $this->findLockRecordForFile();
19
  }
20
+ $success = $lock instanceof FileLocker\EntryVO
21
+ && $mod->getDbHandler_FileLocker()
22
+ ->getQueryDeleter()
23
+ ->deleteEntry( $lock );
24
+ if ( $success ) {
25
  $this->clearFileLocksCache();
26
  }
27
+ return $success;
28
  }
29
  }
src/lib/src/Modules/HackGuard/Lib/FileLocker/Ops/LoadFileLocks.php CHANGED
@@ -22,7 +22,7 @@ class LoadFileLocks {
22
  /**
23
  * @return FileLocker\EntryVO[]
24
  */
25
- public function loadLocks() {
26
  if ( is_null( self::$aFileLockRecords ) ) {
27
  /** @var ModCon $mod */
28
  $mod = $this->getMod();
22
  /**
23
  * @return FileLocker\EntryVO[]
24
  */
25
+ public function loadLocks() :array {
26
  if ( is_null( self::$aFileLockRecords ) ) {
27
  /** @var ModCon $mod */
28
  $mod = $this->getMod();
src/lib/src/Modules/HackGuard/Lib/Reports/FileLockerAlerts.php CHANGED
@@ -35,7 +35,7 @@ class FileLockerAlerts extends BaseReporter {
35
  'view_results' => __( 'Click Here To View File Locker Results', 'wp-simple-firewall' ),
36
  ],
37
  'hrefs' => [
38
- 'view_results' => $this->getCon()->getModule_Insights()->getUrl_SubInsightsPage( 'scans' ),
39
  ],
40
  ]
41
  );
35
  'view_results' => __( 'Click Here To View File Locker Results', 'wp-simple-firewall' ),
36
  ],
37
  'hrefs' => [
38
+ 'view_results' => $this->getCon()->getModule_Insights()->getUrl_ScansResults(),
39
  ],
40
  ]
41
  );
src/lib/src/Modules/HackGuard/Lib/Reports/ScanAlerts.php CHANGED
@@ -13,6 +13,9 @@ class ScanAlerts extends BaseReporter {
13
  * @inheritDoc
14
  */
15
  public function build() {
 
 
 
16
  $alerts = [];
17
 
18
  /** @var HackGuard\Strings $strings */
@@ -43,7 +46,9 @@ class ScanAlerts extends BaseReporter {
43
  'view_results' => __( 'Click Here To View Scan Results Details', 'wp-simple-firewall' ),
44
  ],
45
  'hrefs' => [
46
- 'view_results' => $this->getCon()->getModule_Insights()->getUrl_SubInsightsPage( 'scans' ),
 
 
47
  ],
48
  ]
49
  );
13
  * @inheritDoc
14
  */
15
  public function build() {
16
+ /** @var HackGuard\ModCon $mod */
17
+ $mod = $this->getMod();
18
+
19
  $alerts = [];
20
 
21
  /** @var HackGuard\Strings $strings */
46
  'view_results' => __( 'Click Here To View Scan Results Details', 'wp-simple-firewall' ),
47
  ],
48
  'hrefs' => [
49
+ 'view_results' => $this->getCon()
50
+ ->getModule_Insights()
51
+ ->getUrl_ScansResults(),
52
  ],
53
  ]
54
  );
src/lib/src/Modules/HackGuard/ModCon.php CHANGED
@@ -139,27 +139,29 @@ class ModCon extends BaseShield\ModCon {
139
  protected function cleanFileExclusions() {
140
  /** @var Options $opts */
141
  $opts = $this->getOptions();
142
- $aExclusions = [];
143
 
144
- $aToClean = $opts->getOpt( 'ufc_exclusions', [] );
145
- if ( is_array( $aToClean ) ) {
146
- foreach ( $aToClean as $nKey => $sExclusion ) {
147
- $sExclusion = wp_normalize_path( trim( $sExclusion ) );
148
 
149
- if ( preg_match( '/^#(.+)#$/', $sExclusion, $aMatches ) ) { // it's regex
150
- // ignore it
151
  }
152
- elseif ( strpos( $sExclusion, '/' ) === false ) { // filename only
153
- $sExclusion = trim( preg_replace( '#[^.0-9a-z_-]#i', '', $sExclusion ) );
 
 
 
154
  }
155
 
156
- if ( !empty( $sExclusion ) ) {
157
- $aExclusions[] = $sExclusion;
158
  }
159
  }
160
  }
161
 
162
- $opts->setOpt( 'ufc_exclusions', array_unique( $aExclusions ) );
163
  }
164
 
165
  public function isPtgEnabled() :bool {
@@ -190,8 +192,7 @@ class ModCon extends BaseShield\ModCon {
190
  }
191
 
192
  public function getDbHandler_FileLocker() :Databases\FileLocker\Handler {
193
- $new = $this->getDbH( 'filelocker' );
194
- return empty( $new ) ? $this->getDbH( 'file_protect' ) : $new;
195
  }
196
 
197
  public function getDbHandler_ScanQueue() :Databases\ScanQueue\Handler {
139
  protected function cleanFileExclusions() {
140
  /** @var Options $opts */
141
  $opts = $this->getOptions();
142
+ $excl = [];
143
 
144
+ $toClean = $opts->getOpt( 'ufc_exclusions', [] );
145
+ if ( is_array( $toClean ) ) {
146
+ foreach ( $toClean as $exclusion ) {
 
147
 
148
+ if ( preg_match( '/^#(.+)#$/', $exclusion, $matches ) ) { // it's not regex
149
+ $exclusion = str_replace( '\\', '\\\\', $exclusion );
150
  }
151
+ else {
152
+ $exclusion = wp_normalize_path( trim( $exclusion ) );
153
+ if ( strpos( $exclusion, '/' ) === false ) { // filename only
154
+ $exclusion = trim( preg_replace( '#[^.0-9a-z_-]#i', '', $exclusion ) );
155
+ }
156
  }
157
 
158
+ if ( !empty( $exclusion ) ) {
159
+ $excl[] = $exclusion;
160
  }
161
  }
162
  }
163
 
164
+ $opts->setOpt( 'ufc_exclusions', array_unique( $excl ) );
165
  }
166
 
167
  public function isPtgEnabled() :bool {
192
  }
193
 
194
  public function getDbHandler_FileLocker() :Databases\FileLocker\Handler {
195
+ return $this->getDbH( 'filelocker' );
 
196
  }
197
 
198
  public function getDbHandler_ScanQueue() :Databases\ScanQueue\Handler {
src/lib/src/Modules/HackGuard/Scan/Queue/Build/QueueBuilder.php CHANGED
@@ -58,7 +58,7 @@ class QueueBuilder extends Utilities\BackgroundProcessing\BackgroundProcess {
58
  ( new HackGuard\Scan\Queue\ScanInitiate() )
59
  ->setMod( $this->getMod() )
60
  ->setQueueProcessor( $this->getQueueProcessor() )
61
- ->init( $slug );
62
  }
63
  catch ( \Exception $e ) {
64
  // error_log( $e->getMessage() );
58
  ( new HackGuard\Scan\Queue\ScanInitiate() )
59
  ->setMod( $this->getMod() )
60
  ->setQueueProcessor( $this->getQueueProcessor() )
61
+ ->init( (string)$slug );
62
  }
63
  catch ( \Exception $e ) {
64
  // error_log( $e->getMessage() );
src/lib/src/Modules/HackGuard/Scan/Queue/IsScanEnqueued.php CHANGED
@@ -12,13 +12,9 @@ class IsScanEnqueued {
12
 
13
  use Databases\Base\HandlerConsumer;
14
 
15
- /**
16
- * @param string $sScanSlug
17
- * @return bool
18
- */
19
- public function check( $sScanSlug ) {
20
- /** @var Databases\ScanQueue\Select $oSel */
21
- $oSel = $this->getDbHandler()->getQuerySelector();
22
- return $oSel->countForScan( $sScanSlug ) > 0;
23
  }
24
  }
12
 
13
  use Databases\Base\HandlerConsumer;
14
 
15
+ public function check( string $scan ) :bool {
16
+ /** @var Databases\ScanQueue\Select $selector */
17
+ $selector = $this->getDbHandler()->getQuerySelector();
18
+ return $selector->countForScan( $scan ) > 0;
 
 
 
 
19
  }
20
  }
src/lib/src/Modules/HackGuard/Scan/Queue/ScanInitiate.php CHANGED
@@ -20,7 +20,7 @@ class ScanInitiate {
20
  * @param string $slug
21
  * @throws \Exception
22
  */
23
- public function init( $slug ) {
24
  /** @var ModCon $mod */
25
  $mod = $this->getMod();
26
  $dbh = $mod->getDbHandler_ScanQueue();
20
  * @param string $slug
21
  * @throws \Exception
22
  */
23
+ public function init( string $slug ) {
24
  /** @var ModCon $mod */
25
  $mod = $this->getMod();
26
  $dbh = $mod->getDbHandler_ScanQueue();
src/lib/src/Modules/HackGuard/Strings.php CHANGED
@@ -21,7 +21,7 @@ class Strings extends Base\Strings {
21
  'ptg' => __( 'Plugin/Theme Guard', 'wp-simple-firewall' ),
22
  'mal' => __( 'Malware', 'wp-simple-firewall' ),
23
  'ufc' => __( 'Unrecognised Files', 'wp-simple-firewall' ),
24
- 'wcf' => __( 'WP Core Files', 'wp-simple-firewall' ),
25
  'wpv' => __( 'Vulnerabilities', 'wp-simple-firewall' ),
26
  ];
27
  }
@@ -30,29 +30,29 @@ class Strings extends Base\Strings {
30
  * @return string[][]
31
  */
32
  protected function getAuditMessages() :array {
33
- $aMessages = [];
34
- foreach ( $this->getScanNames() as $sSlug => $sScanName ) {
35
- $aMessages[ $sSlug.'_alert_sent' ] = [
36
- sprintf( __( '%s scan alert sent.', 'wp-simple-firewall' ), $sScanName )
37
  .' '.__( 'Alert sent to %s via %s.' )
38
  ];
39
- $aMessages[ $sSlug.'_scan_found' ] = [
40
- sprintf( __( '%s scan completed and items were discovered.', 'wp-simple-firewall' ), $sScanName ),
41
  sprintf( '%s: %s',
42
  __( 'Note', 'wp-simple-firewall' ),
43
  __( "These items wont display in results if you've previously marked them as ignored.", 'wp-simple-firewall' )
44
  )
45
  ];
46
- $aMessages[ $sSlug.'_item_repair_success' ] = [
47
- sprintf( __( '%s scan repaired a item found in the scan.', 'wp-simple-firewall' ), $sScanName )
48
  .' '.__( 'Item repaired: "%s"', 'wp-simple-firewall' ),
49
  ];
50
- $aMessages[ $sSlug.'_item_repair_fail' ] = [
51
- sprintf( __( '%s scan could not repair item.', 'wp-simple-firewall' ), $sScanName )
52
  .' '.__( 'Failed repair item: "%s"', 'wp-simple-firewall' ),
53
  ];
54
  }
55
- return $aMessages;
56
  }
57
 
58
  /**
21
  'ptg' => __( 'Plugin/Theme Guard', 'wp-simple-firewall' ),
22
  'mal' => __( 'Malware', 'wp-simple-firewall' ),
23
  'ufc' => __( 'Unrecognised Files', 'wp-simple-firewall' ),
24
+ 'wcf' => __( 'WordPress Core Files', 'wp-simple-firewall' ),
25
  'wpv' => __( 'Vulnerabilities', 'wp-simple-firewall' ),
26
  ];
27
  }
30
  * @return string[][]
31
  */
32
  protected function getAuditMessages() :array {
33
+ $messages = [];
34
+ foreach ( $this->getScanNames() as $slug => $scanName ) {
35
+ $messages[ $slug.'_alert_sent' ] = [
36
+ sprintf( __( '%s scan alert sent.', 'wp-simple-firewall' ), $scanName )
37
  .' '.__( 'Alert sent to %s via %s.' )
38
  ];
39
+ $messages[ $slug.'_scan_found' ] = [
40
+ sprintf( __( '%s scan completed and items were discovered.', 'wp-simple-firewall' ), $scanName ),
41
  sprintf( '%s: %s',
42
  __( 'Note', 'wp-simple-firewall' ),
43
  __( "These items wont display in results if you've previously marked them as ignored.", 'wp-simple-firewall' )
44
  )
45
  ];
46
+ $messages[ $slug.'_item_repair_success' ] = [
47
+ sprintf( __( '%s scan repaired a item found in the scan.', 'wp-simple-firewall' ), $scanName )
48
  .' '.__( 'Item repaired: "%s"', 'wp-simple-firewall' ),
49
  ];
50
+ $messages[ $slug.'_item_repair_fail' ] = [
51
+ sprintf( __( '%s scan could not repair item.', 'wp-simple-firewall' ), $scanName )
52
  .' '.__( 'Failed repair item: "%s"', 'wp-simple-firewall' ),
53
  ];
54
  }
55
+ return $messages;
56
  }
57
 
58
  /**
src/lib/src/Modules/HackGuard/UI.php CHANGED
@@ -14,16 +14,16 @@ class UI extends BaseShield\UI {
14
  /** @var Options $opts */
15
  $opts = $this->getOptions();
16
 
17
- $aUiTrack = $mod->getUiTrack();
18
- if ( empty( $aUiTrack[ 'selected_scans' ] ) ) {
19
- $aUiTrack[ 'selected_scans' ] = $opts->getScanSlugs();
20
  }
21
 
22
  // Can Scan Checks:
23
  $reasonsCantScan = $mod->getScansCon()->getReasonsScansCantExecute();
24
 
25
- /** @var \FernleafSystems\Wordpress\Plugin\Shield\Databases\Scanner\Select $oSelector */
26
- $oSelector = $mod->getDbHandler_ScanResults()->getQuerySelector();
27
  $data = [
28
  'ajax' => [
29
  'scans_start' => $mod->getAjaxActionData( 'scans_start', true ),
@@ -69,12 +69,11 @@ class UI extends BaseShield\UI {
69
  'vars' => [
70
  'initial_check' => $mod->getScanQueueController()->hasRunningScans(),
71
  'cannot_scan_reasons' => $reasonsCantScan,
72
- 'related_hrefs' => [
73
- [
74
- 'href' => $this->getCon()->getModule_HackGuard()->getUrl_AdminPage(),
75
- 'title' => __( 'Scan Settings', 'wp-simple-firewall' ),
76
- ],
77
- ]
78
  ],
79
  'scan_results' => [
80
  ],
@@ -91,32 +90,39 @@ class UI extends BaseShield\UI {
91
  'title' => __( 'File Scan', 'wp-simple-firewall' ),
92
  'subtitle' => __( "Results of all file scans", 'wp-simple-firewall' )
93
  ],
94
- 'count' => $oSelector->filterByScans( [ 'ptg', 'mal', 'wcf', 'ufc' ] )
95
- ->filterByNotIgnored()
96
- ->count()
97
  ],
98
  'file_locker' => $this->getFileLockerVars(),
99
  'scans' => [
100
- 'apc' => [
101
  'flags' => [
102
- 'has_items' => true,
103
- 'show_table' => true,
104
  ],
105
  'hrefs' => [],
106
  'vars' => [],
107
  'strings' => [
108
- 'subtitle' => __( "Discover plugins that may have been abandoned by their authors", 'wp-simple-firewall' )
 
 
 
 
 
 
 
109
  ],
110
  ],
111
- 'wcf' => [
112
  'flags' => [
113
  'has_items' => true,
114
- 'show_table' => false,
115
  ],
116
  'hrefs' => [],
117
  'vars' => [],
118
  'strings' => [
119
- 'subtitle' => __( "Detect changes to core WordPress files when compared to the official distribution", 'wp-simple-firewall' ),
120
  ],
121
  ],
122
  'ufc' => [
@@ -167,11 +173,13 @@ class UI extends BaseShield\UI {
167
  continue;
168
  }
169
  $lastScanAt = $scon->getLastScanAt();
170
-
 
171
  $scData[ 'flags' ][ 'is_available' ] = $scon->isScanningAvailable();
 
172
  $scData[ 'flags' ][ 'is_restricted' ] = !$scon->isScanningAvailable();
173
  $scData[ 'flags' ][ 'is_enabled' ] = $scon->isEnabled();
174
- $scData[ 'flags' ][ 'is_selected' ] = $scon->isScanningAvailable() && in_array( $slug, $aUiTrack[ 'selected_scans' ] );
175
  $scData[ 'vars' ][ 'last_scan_at_ts' ] = $lastScanAt;
176
  $scData[ 'flags' ][ 'has_last_scan' ] = $lastScanAt > 0;
177
  $scData[ 'vars' ][ 'last_scan_at' ] = sprintf(
@@ -183,7 +191,7 @@ class UI extends BaseShield\UI {
183
  $scData[ 'strings' ][ 'title' ] = $name[ $slug ];
184
  $scData[ 'hrefs' ][ 'options' ] = $mod->getUrl_DirectLinkToSection( 'section_scan_'.$slug );
185
  $scData[ 'hrefs' ][ 'please_enable' ] = $mod->getUrl_DirectLinkToSection( 'section_scan_'.$slug );
186
- $scData[ 'count' ] = $oSelector->countForScan( $slug );
187
  }
188
 
189
  return $data;
@@ -299,14 +307,4 @@ class UI extends BaseShield\UI {
299
 
300
  return $aWarnings;
301
  }
302
-
303
- protected function getSettingsRelatedLinks() :array {
304
- $modInsights = $this->getCon()->getModule_Insights();
305
- return [
306
- [
307
- 'href' => $modInsights->getUrl_SubInsightsPage( 'scans' ),
308
- 'title' => __( 'Run Scans', 'wp-simple-firewall' ),
309
- ]
310
- ];
311
- }
312
  }
14
  /** @var Options $opts */
15
  $opts = $this->getOptions();
16
 
17
+ $uiTrack = $mod->getUiTrack();
18
+ if ( empty( $uiTrack[ 'selected_scans' ] ) ) {
19
+ $uiTrack[ 'selected_scans' ] = $opts->getScanSlugs();
20
  }
21
 
22
  // Can Scan Checks:
23
  $reasonsCantScan = $mod->getScansCon()->getReasonsScansCantExecute();
24
 
25
+ /** @var \FernleafSystems\Wordpress\Plugin\Shield\Databases\Scanner\Select $selector */
26
+ $selector = $mod->getDbHandler_ScanResults()->getQuerySelector();
27
  $data = [
28
  'ajax' => [
29
  'scans_start' => $mod->getAjaxActionData( 'scans_start', true ),
69
  'vars' => [
70
  'initial_check' => $mod->getScanQueueController()->hasRunningScans(),
71
  'cannot_scan_reasons' => $reasonsCantScan,
72
+ ],
73
+ 'hrefs' => [
74
+ 'scans_results' => $this->getCon()
75
+ ->getModule_Insights()
76
+ ->getUrl_ScansResults(),
 
77
  ],
78
  'scan_results' => [
79
  ],
90
  'title' => __( 'File Scan', 'wp-simple-firewall' ),
91
  'subtitle' => __( "Results of all file scans", 'wp-simple-firewall' )
92
  ],
93
+ 'count' => $selector->filterByScans( [ 'ptg', 'mal', 'wcf', 'ufc' ] )
94
+ ->filterByNotIgnored()
95
+ ->count()
96
  ],
97
  'file_locker' => $this->getFileLockerVars(),
98
  'scans' => [
99
+ 'wcf' => [
100
  'flags' => [
101
+ 'has_items' => false,
102
+ 'show_table' => false,
103
  ],
104
  'hrefs' => [],
105
  'vars' => [],
106
  'strings' => [
107
+ 'subtitle' => __( "Detect changes to core WordPress files when compared to the official distribution", 'wp-simple-firewall' ),
108
+ 'explanation' => [
109
+ __( 'The files listed below are WordPress Core files - official files that are installed with every WordPress website.', 'wp-simple-firewall' ),
110
+ __( 'However, they have either been deleted, or their contents have changed in some way.', 'wp-simple-firewall' ),
111
+ __( 'Under normal circumstances this should never happen.', 'wp-simple-firewall' ),
112
+ __( 'You should review each file below and repair them. Repair can mean either re-install, or replace contents, with an original.', 'wp-simple-firewall' ),
113
+ __( "If you know why a file has been changed and you're happy to keep those changes, you can click to Ignore that file.", 'wp-simple-firewall' ),
114
+ ],
115
  ],
116
  ],
117
+ 'apc' => [
118
  'flags' => [
119
  'has_items' => true,
120
+ 'show_table' => true,
121
  ],
122
  'hrefs' => [],
123
  'vars' => [],
124
  'strings' => [
125
+ 'subtitle' => __( "Discover plugins that may have been abandoned by their authors", 'wp-simple-firewall' ),
126
  ],
127
  ],
128
  'ufc' => [
173
  continue;
174
  }
175
  $lastScanAt = $scon->getLastScanAt();
176
+ $scData[ 'vars' ][ 'slug' ] = $slug;
177
+ $scData[ 'count' ] = $selector->countForScan( $slug );
178
  $scData[ 'flags' ][ 'is_available' ] = $scon->isScanningAvailable();
179
+ // $scData[ 'flags' ][ 'show_table' ] = $scData[ 'count' ] > 0;
180
  $scData[ 'flags' ][ 'is_restricted' ] = !$scon->isScanningAvailable();
181
  $scData[ 'flags' ][ 'is_enabled' ] = $scon->isEnabled();
182
+ $scData[ 'flags' ][ 'is_selected' ] = $scon->isScanningAvailable() && in_array( $slug, $uiTrack[ 'selected_scans' ] );
183
  $scData[ 'vars' ][ 'last_scan_at_ts' ] = $lastScanAt;
184
  $scData[ 'flags' ][ 'has_last_scan' ] = $lastScanAt > 0;
185
  $scData[ 'vars' ][ 'last_scan_at' ] = sprintf(
191
  $scData[ 'strings' ][ 'title' ] = $name[ $slug ];
192
  $scData[ 'hrefs' ][ 'options' ] = $mod->getUrl_DirectLinkToSection( 'section_scan_'.$slug );
193
  $scData[ 'hrefs' ][ 'please_enable' ] = $mod->getUrl_DirectLinkToSection( 'section_scan_'.$slug );
194
+ $scData[ 'count' ] = $selector->countForScan( $slug );
195
  }
196
 
197
  return $data;
307
 
308
  return $aWarnings;
309
  }
 
 
 
 
 
 
 
 
 
 
310
  }
src/lib/src/Modules/Headers/ModCon.php CHANGED
@@ -24,10 +24,4 @@ class ModCon extends BaseShield\ModCon {
24
  $opts->getOpt( 'xcsp_custom', [] )
25
  ) ) ) );
26
  }
27
-
28
- /**
29
- * @deprecated 10.3
30
- */
31
- private function cleanCspHosts() {
32
- }
33
  }
24
  $opts->getOpt( 'xcsp_custom', [] )
25
  ) ) ) );
26
  }
 
 
 
 
 
 
27
  }
src/lib/src/Modules/Headers/Strings.php CHANGED
@@ -105,7 +105,6 @@ class Strings extends Base\Strings {
105
  $sName = __( 'Manual Rules', 'wp-simple-firewall' );
106
  $sSummary = __( 'Manual CSP Rules', 'wp-simple-firewall' );
107
  $sDescription = [
108
- __( 'Manual CSP rules which are not covered by the rules above.', 'wp-simple-firewall' ),
109
  '- '.__( 'Take a new line per rule.', 'wp-simple-firewall' ),
110
  '- '.__( 'We provide this feature as-is: to allow you to add custom CSP rules to your site.', 'wp-simple-firewall' ),
111
  '- '.__( "We don't provide support for creating CSP rules and whether they're correct for your site.", 'wp-simple-firewall' ),
105
  $sName = __( 'Manual Rules', 'wp-simple-firewall' );
106
  $sSummary = __( 'Manual CSP Rules', 'wp-simple-firewall' );
107
  $sDescription = [
 
108
  '- '.__( 'Take a new line per rule.', 'wp-simple-firewall' ),
109
  '- '.__( 'We provide this feature as-is: to allow you to add custom CSP rules to your site.', 'wp-simple-firewall' ),
110
  '- '.__( "We don't provide support for creating CSP rules and whether they're correct for your site.", 'wp-simple-firewall' ),
src/lib/src/Modules/IPs/AjaxHandler.php CHANGED
@@ -3,6 +3,7 @@
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield;
 
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Ops;
7
  use FernleafSystems\Wordpress\Services\Services;
8
  use FernleafSystems\Wordpress\Services\Utilities\Net\IpID;
@@ -71,13 +72,13 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
71
  $mod = $this->getMod();
72
  $oIpServ = Services::IP();
73
 
74
- $aFormParams = $this->getAjaxFormParams();
75
 
76
  $success = false;
77
  $msg = __( "IP address wasn't added to the list", 'wp-simple-firewall' );
78
 
79
- $ip = preg_replace( '#[^/:.a-f\d]#i', '', ( isset( $aFormParams[ 'ip' ] ) ? $aFormParams[ 'ip' ] : '' ) );
80
- $sList = isset( $aFormParams[ 'list' ] ) ? $aFormParams[ 'list' ] : '';
81
 
82
  $bAcceptableIp = $oIpServ->isValidIp( $ip )
83
  || $oIpServ->isValidIp4Range( $ip )
@@ -105,7 +106,7 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
105
  $msg = __( "This IP is reserved and can't be blacklisted.", 'wp-simple-firewall' );
106
  }
107
  else {
108
- $label = $aFormParams[ 'label' ] ?? '';
109
  $oIP = null;
110
  switch ( $sList ) {
111
  case $mod::LIST_MANUAL_WHITE:
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Request\FormParams;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Ops;
8
  use FernleafSystems\Wordpress\Services\Services;
9
  use FernleafSystems\Wordpress\Services\Utilities\Net\IpID;
72
  $mod = $this->getMod();
73
  $oIpServ = Services::IP();
74
 
75
+ $formParams = FormParams::Retrieve();
76
 
77
  $success = false;
78
  $msg = __( "IP address wasn't added to the list", 'wp-simple-firewall' );
79
 
80
+ $ip = preg_replace( '#[^/:.a-f\d]#i', '', ( isset( $formParams[ 'ip' ] ) ? $formParams[ 'ip' ] : '' ) );
81
+ $sList = isset( $formParams[ 'list' ] ) ? $formParams[ 'list' ] : '';
82
 
83
  $bAcceptableIp = $oIpServ->isValidIp( $ip )
84
  || $oIpServ->isValidIp4Range( $ip )
106
  $msg = __( "This IP is reserved and can't be blacklisted.", 'wp-simple-firewall' );
107
  }
108
  else {
109
+ $label = $formParams[ 'label' ] ?? '';
110
  $oIP = null;
111
  switch ( $sList ) {
112
  case $mod::LIST_MANUAL_WHITE:
src/lib/src/Modules/IPs/BotTrack/TrackLinkCheese.php CHANGED
@@ -86,19 +86,4 @@ class TrackLinkCheese extends Base {
86
  private function getCheeseWord() :string {
87
  return $this->getCon()->prefix( self::CHEESE_WORD );
88
  }
89
-
90
- /**
91
- * @return string[]
92
- * @deprecated 10.3
93
- */
94
- private function getPossibleWords() {
95
- return [
96
- 'mouse',
97
- 'cheese',
98
- 'venus',
99
- 'stilton',
100
- 'cheddar',
101
- 'holey',
102
- ];
103
- }
104
  }
86
  private function getCheeseWord() :string {
87
  return $this->getCon()->prefix( self::CHEESE_WORD );
88
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  }
src/lib/src/Modules/IPs/Lib/AutoUnblock.php CHANGED
@@ -2,6 +2,7 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib;
4
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
  use FernleafSystems\Wordpress\Services\Services;
@@ -28,9 +29,6 @@ class AutoUnblock {
28
  catch ( \Exception $e ) {
29
  }
30
  }
31
- if ( !$unblocked ) {
32
- $unblocked = $this->checkForBlockedServiceBot();
33
- }
34
  return $unblocked;
35
  }
36
 
@@ -75,36 +73,35 @@ class AutoUnblock {
75
  throw new \Exception( 'Email should not be provided in honeypot' );
76
  }
77
 
78
- $sIP = Services::IP()->getRequestIp();
79
- if ( $req->post( 'ip' ) != $sIP ) {
80
  throw new \Exception( 'IP does not match' );
81
  }
82
 
83
- $oLoginMod = $this->getCon()->getModule_LoginGuard();
84
- $sGasp = $req->post( $oLoginMod->getGaspKey() );
85
- if ( empty( $sGasp ) ) {
86
- throw new \Exception( 'GASP failed' );
87
  }
88
 
89
- if ( !$opts->getCanIpRequestAutoUnblock( $sIP ) ) {
90
- throw new \Exception( 'IP already processed in the last 24hrs' );
91
- }
 
92
 
93
  {
94
- $aExistingIps = $opts->getAutoUnblockIps();
95
- $aExistingIps[ $sIP ] = Services::Request()->ts();
96
  $opts->setOpt( 'autounblock_ips',
97
- array_filter( $aExistingIps, function ( $nTS ) {
98
  return Services::Request()
99
  ->carbon()
100
- ->subDays( 1 )->timestamp < $nTS;
101
  } )
102
  );
103
  }
104
 
105
  ( new IPs\Lib\Ops\DeleteIp() )
106
  ->setMod( $mod )
107
- ->setIP( $sIP )
108
  ->fromBlacklist();
109
  $unblocked = true;
110
  }
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter\Scan\AntiBot;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
8
  use FernleafSystems\Wordpress\Services\Services;
29
  catch ( \Exception $e ) {
30
  }
31
  }
 
 
 
32
  return $unblocked;
33
  }
34
 
73
  throw new \Exception( 'Email should not be provided in honeypot' );
74
  }
75
 
76
+ $ip = Services::IP()->getRequestIp();
77
+ if ( empty( $ip ) || $req->post( 'ip' ) !== Services::IP()->getRequestIp() ) {
78
  throw new \Exception( 'IP does not match' );
79
  }
80
 
81
+ if ( !$opts->getCanIpRequestAutoUnblock( $ip ) ) {
82
+ throw new \Exception( 'IP already processed in the last 1hr' );
 
 
83
  }
84
 
85
+ // Perform the test
86
+ ( new AntiBot() )
87
+ ->setMod( $this->getMod() )
88
+ ->scan();
89
 
90
  {
91
+ $existing = $opts->getAutoUnblockIps();
92
+ $existing[ $ip ] = Services::Request()->ts();
93
  $opts->setOpt( 'autounblock_ips',
94
+ array_filter( $existing, function ( $ts ) {
95
  return Services::Request()
96
  ->carbon()
97
+ ->subHours( 1 )->timestamp < $ts;
98
  } )
99
  );
100
  }
101
 
102
  ( new IPs\Lib\Ops\DeleteIp() )
103
  ->setMod( $mod )
104
+ ->setIP( $ip )
105
  ->fromBlacklist();
106
  $unblocked = true;
107
  }
src/lib/src/Modules/IPs/Lib/BlockRequest.php CHANGED
@@ -46,19 +46,16 @@ class BlockRequest {
46
  /** @var IPs\Options $opts */
47
  $opts = $this->getOptions();
48
  $con = $this->getCon();
49
- $oLoginMod = $con->getModule_LoginGuard();
50
 
51
- $sUniqId = 'uau'.uniqid();
52
-
53
- $sIP = Services::IP()->getRequestIp();
54
- $nTimeRemaining = max( floor( $opts->getAutoExpireTime()/60 ), 0 );
55
 
56
  $user = Services::WpUsers()->getCurrentWpUser();
57
- $bCanUauGasp = $opts->isEnabledAutoVisitorRecover() && $opts->getCanIpRequestAutoUnblock( $sIP );
58
- $bCanUauMagic = $opts->isEnabledMagicEmailLinkRecover() &&
59
- $user instanceof \WP_User
60
- && $opts->getCanRequestAutoUnblockEmailLink( $user );
61
- $bCanAutoRecover = $bCanUauGasp || $bCanUauMagic;
62
 
63
  if ( !empty( $con->getLabels()[ 'PluginURI' ] ) ) {
64
  $homeURL = $con->getLabels()[ 'PluginURI' ];
@@ -77,7 +74,7 @@ class BlockRequest {
77
  ),
78
  'lines' => [
79
  sprintf( __( 'Time remaining on black list: %s', 'wp-simple-firewall' ),
80
- sprintf( _n( '%s minute', '%s minutes', $nTimeRemaining, 'wp-simple-firewall' ), $nTimeRemaining )
81
  ),
82
  sprintf( __( 'You tripped the security plugin defenses a total of %s times making you a suspect.', 'wp-simple-firewall' ), $opts->getOffenseLimit() ),
83
  sprintf( __( 'If you believe this to be in error, please contact the site owner and quote your IP address below.', 'wp-simple-firewall' ) ),
@@ -92,28 +89,17 @@ class BlockRequest {
92
  'content' => [
93
  'email_unblock' => $this->renderEmailMagicLinkContent()
94
  ],
 
 
 
95
  'vars' => [
96
- 'nonce' => $mod->getNonceActionData( 'uau' ),
97
- 'ip' => $sIP,
98
- 'gasp_element' => $mod->renderTemplate(
99
- 'snippets/gasp_js.php',
100
- [
101
- 'sCbName' => $oLoginMod->getGaspKey(),
102
- 'sLabel' => $oLoginMod->getTextImAHuman(),
103
- 'sAlert' => $oLoginMod->getTextPleaseCheckBox(),
104
- 'sMustJs' => __( 'You MUST enable Javascript to be able to login', 'wp-simple-firewall' ),
105
- 'sUniqId' => $sUniqId,
106
- 'sUniqElem' => 'icwp_wpsf_login_p'.$sUniqId,
107
- 'strings' => [
108
- 'loading' => __( 'Loading', 'wp-simple-firewall' )
109
- ]
110
- ]
111
- ),
112
  ],
113
  'flags' => [
114
- 'is_autorecover' => $bCanAutoRecover,
115
- 'is_uaug_permitted' => $bCanUauGasp,
116
- 'is_uaum_permitted' => $bCanUauMagic,
117
  ],
118
  ];
119
  Services::WpGeneral()
46
  /** @var IPs\Options $opts */
47
  $opts = $this->getOptions();
48
  $con = $this->getCon();
 
49
 
50
+ $ip = Services::IP()->getRequestIp();
51
+ $timeRemaining = max( floor( $opts->getAutoExpireTime()/60 ), 0 );
 
 
52
 
53
  $user = Services::WpUsers()->getCurrentWpUser();
54
+ $canUauBot = $opts->isEnabledAutoVisitorRecover() && !empty( $ip ) && $opts->getCanIpRequestAutoUnblock( $ip );
55
+ $canUauMagic = $opts->isEnabledMagicEmailLinkRecover() &&
56
+ $user instanceof \WP_User
57
+ && $opts->getCanRequestAutoUnblockEmailLink( $user );
58
+ $canAutoRecover = $canUauBot || $canUauMagic;
59
 
60
  if ( !empty( $con->getLabels()[ 'PluginURI' ] ) ) {
61
  $homeURL = $con->getLabels()[ 'PluginURI' ];
74
  ),
75
  'lines' => [
76
  sprintf( __( 'Time remaining on black list: %s', 'wp-simple-firewall' ),
77
+ sprintf( _n( '%s minute', '%s minutes', $timeRemaining, 'wp-simple-firewall' ), $timeRemaining )
78
  ),
79
  sprintf( __( 'You tripped the security plugin defenses a total of %s times making you a suspect.', 'wp-simple-firewall' ), $opts->getOffenseLimit() ),
80
  sprintf( __( 'If you believe this to be in error, please contact the site owner and quote your IP address below.', 'wp-simple-firewall' ) ),
89
  'content' => [
90
  'email_unblock' => $this->renderEmailMagicLinkContent()
91
  ],
92
+ 'hrefs' => [
93
+ 'home' => Services::WpGeneral()->getHomeUrl()
94
+ ],
95
  'vars' => [
96
+ 'nonce' => $mod->getNonceActionData( 'uau' ),
97
+ 'ip' => $ip,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  ],
99
  'flags' => [
100
+ 'is_autorecover' => $canAutoRecover,
101
+ 'is_uaug_permitted' => $canUauBot,
102
+ 'is_uaum_permitted' => $canUauMagic,
103
  ],
104
  ];
105
  Services::WpGeneral()
src/lib/src/Modules/IPs/Lib/Bots/BotEventListener.php ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Bots;
4
+
5
+ use FernleafSystems\Utilities\Logic\ExecOnce;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\ModCon;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
8
+ use FernleafSystems\Wordpress\Services\Services;
9
+
10
+ class BotEventListener {
11
+
12
+ use ModConsumer;
13
+ use ExecOnce;
14
+
15
+ public function fireEventForIP( $ip, $event ) {
16
+ $events = $this->getEventsToColumn();
17
+
18
+ foreach ( $events as $eventTrigger => $column ) {
19
+ if ( $eventTrigger === $event || preg_match( sprintf( '#^%s$#', $eventTrigger ), $event ) ) {
20
+ try {
21
+ ( new BotSignalsRecord() )
22
+ ->setMod( $this->getMod() )
23
+ ->setIP( $ip )
24
+ ->updateSignalField( $column );
25
+ }
26
+ catch ( \LogicException $e ) {
27
+ error_log( 'Error updating bot signal: '.$e->getMessage() );
28
+ }
29
+ }
30
+ }
31
+ }
32
+
33
+ protected function canRun() :bool {
34
+ /** @var ModCon $mod */
35
+ $mod = $this->getMod();
36
+ return !$mod->isVerifiedBot();
37
+ }
38
+
39
+ protected function run() {
40
+ add_action( $this->getCon()->prefix( 'event' ), function ( $event ) {
41
+ $this->fireEventForIP( Services::IP()->getRequestIp(), $event );
42
+ } );
43
+ }
44
+
45
+ /**
46
+ * @return string[]
47
+ */
48
+ private function getEventsToColumn() :array {
49
+ return array_map(
50
+ function ( $column ) {
51
+ return str_replace( '_at', '', $column ).'_at';
52
+ },
53
+ [
54
+ 'bottrack_notbot' => 'notbot',
55
+ 'frontpage_load' => 'frontpage',
56
+ 'bottrack_404' => 'bt404',
57
+ 'bottrack_fakewebcrawler' => 'btfake',
58
+ 'bottrack_linkcheese' => 'btcheese',
59
+ 'bottrack_loginfailed' => 'btloginfail',
60
+ 'bottrack_useragent' => 'btua',
61
+ 'bottrack_xmlrpc' => 'btxml',
62
+ 'bottrack_logininvalid' => 'btlogininvalid',
63
+ 'bottrack_invalidscript' => 'btinvalidscript',
64
+ 'cooldown_fail' => 'cooldown',
65
+ 'recaptcha_success' => 'captchapass',
66
+ 'request_limit_exceeded' => 'ratelimit',
67
+ 'recaptcha_fail' => 'captchafail',
68
+ 'spam_block_human' => 'humanspam',
69
+ 'comment_markspam' => 'markspam',
70
+ 'comment_unmarkspam' => 'unmarkspam',
71
+ 'blockparam_.*' => 'firewall',
72
+ 'ip_offense' => 'offense',
73
+ 'ip_blocked' => 'blocked',
74
+ 'ip_unblock' => 'unblocked',
75
+ 'ip_bypass' => 'bypass',
76
+ 'login_success' => 'auth',
77
+ ]
78
+ );
79
+ }
80
+ }
src/lib/src/Modules/IPs/Lib/Bots/BotSignalsController.php CHANGED
@@ -18,7 +18,7 @@ class BotSignalsController {
18
  private $handlerNotBot;
19
 
20
  /**
21
- * @var EventListener
22
  */
23
  private $eventListener;
24
 
@@ -53,9 +53,9 @@ class BotSignalsController {
53
  return $this->handlerNotBot;
54
  }
55
 
56
- public function getEventListener() :EventListener {
57
  if ( !isset( $this->eventListener ) ) {
58
- $this->eventListener = ( new EventListener() )->setMod( $this->getMod() );
59
  }
60
  return $this->eventListener;
61
  }
18
  private $handlerNotBot;
19
 
20
  /**
21
+ * @var BotEventListener
22
  */
23
  private $eventListener;
24
 
53
  return $this->handlerNotBot;
54
  }
55
 
56
+ public function getEventListener() :BotEventListener {
57
  if ( !isset( $this->eventListener ) ) {
58
+ $this->eventListener = ( new BotEventListener() )->setMod( $this->getMod() );
59
  }
60
  return $this->eventListener;
61
  }
src/lib/src/Modules/IPs/Lib/OffenseTracker.php CHANGED
@@ -18,16 +18,19 @@ class OffenseTracker extends EventsListener {
18
 
19
  /**
20
  * @param string $evt
21
- * @param array $aMeta
 
22
  */
23
- protected function captureEvent( $evt, $aMeta = [] ) {
24
- $aDef = $this->getCon()
25
- ->loadEventsService()
26
- ->getEventDef( $evt );
 
 
27
 
28
- if ( !empty( $aDef ) && !empty( $aDef[ 'offense' ] ) && empty( $aMeta[ 'suppress_offense' ] ) ) {
29
- $this->incrementCount( isset( $aMeta[ 'offense_count' ] ) ? $aMeta[ 'offense_count' ] : 1 );
30
- if ( !empty( $aMeta[ 'block' ] ) ) {
31
  $this->setIsBlocked( true );
32
  }
33
  }
@@ -40,43 +43,37 @@ class OffenseTracker extends EventsListener {
40
  return $this->isBlocked() || $this->getOffenseCount() > 0;
41
  }
42
 
43
- /**
44
- * @return bool
45
- */
46
- public function isBlocked() {
47
  return (bool)$this->bIsBlocked;
48
  }
49
 
50
- /**
51
- * @return int
52
- */
53
- public function getOffenseCount() {
54
  return (int)$this->nOffenseCount;
55
  }
56
 
57
  /**
58
- * @param bool $bIsBlocked
59
  * @return $this
60
  */
61
- public function setIsBlocked( $bIsBlocked ) {
62
- $this->bIsBlocked = $bIsBlocked;
63
  return $this;
64
  }
65
 
66
  /**
67
- * @param int $nIncrement
68
  * @return $this
69
  */
70
- public function incrementCount( $nIncrement = 1 ) {
71
- return $this->setOffenseCount( $this->getOffenseCount() + (int)$nIncrement );
72
  }
73
 
74
  /**
75
- * @param int $nOffenseCount
76
  * @return $this
77
  */
78
- public function setOffenseCount( $nOffenseCount ) {
79
- $this->nOffenseCount = max( $nOffenseCount, (int)$this->nOffenseCount );
80
  return $this;
81
  }
82
  }
18
 
19
  /**
20
  * @param string $evt
21
+ * @param array $meta
22
+ * @param array $def
23
  */
24
+ protected function captureEvent( string $evt, $meta = [], $def = [] ) {
25
+ if ( empty( $def ) ) {
26
+ $def = $this->getCon()
27
+ ->loadEventsService()
28
+ ->getEventDef( $evt );
29
+ }
30
 
31
+ if ( !empty( $def[ 'offense' ] ) && empty( $meta[ 'suppress_offense' ] ) ) {
32
+ $this->incrementCount( (int)( $meta[ 'offense_count' ] ?? 1) );
33
+ if ( !empty( $meta[ 'block' ] ) ) {
34
  $this->setIsBlocked( true );
35
  }
36
  }
43
  return $this->isBlocked() || $this->getOffenseCount() > 0;
44
  }
45
 
46
+ public function isBlocked() :bool {
 
 
 
47
  return (bool)$this->bIsBlocked;
48
  }
49
 
50
+ public function getOffenseCount() :int {
 
 
 
51
  return (int)$this->nOffenseCount;
52
  }
53
 
54
  /**
55
+ * @param bool $isBlocked
56
  * @return $this
57
  */
58
+ public function setIsBlocked( bool $isBlocked ) {
59
+ $this->bIsBlocked = $isBlocked;
60
  return $this;
61
  }
62
 
63
  /**
64
+ * @param int $increment
65
  * @return $this
66
  */
67
+ public function incrementCount( int $increment = 1 ) {
68
+ return $this->setOffenseCount( $this->getOffenseCount() + (int)$increment );
69
  }
70
 
71
  /**
72
+ * @param int $offenseCount
73
  * @return $this
74
  */
75
+ public function setOffenseCount( int $offenseCount ) {
76
+ $this->nOffenseCount = max( $offenseCount, (int)$this->nOffenseCount );
77
  return $this;
78
  }
79
  }
src/lib/src/Modules/IPs/Lib/ProcessOffenses.php CHANGED
@@ -34,9 +34,9 @@ class ProcessOffenses {
34
  /** @var IPs\ModCon $mod */
35
  $mod = $this->getMod();
36
 
37
- $oTracker = $mod->loadOffenseTracker();
38
  if ( !$this->getCon()->plugin_deleting
39
- && $oTracker->hasVisitorOffended() && $oTracker->isCommit() ) {
40
  ( new IPs\Components\ProcessOffense() )
41
  ->setMod( $mod )
42
  ->setIp( Services::IP()->getRequestIp() )
@@ -66,14 +66,14 @@ class ProcessOffenses {
66
 
67
  /**
68
  * Allows 3rd parties to trigger Shield offenses
69
- * @param string $sMessage
70
- * @param int $nOffenseCount
71
  * @param bool $bIncludeLoggedIn
72
  */
73
- public function processCustomShieldOffense( $sMessage, $nOffenseCount = 1, $bIncludeLoggedIn = true ) {
74
  if ( $this->getCon()->isPremiumActive() ) {
75
- if ( empty( $sMessage ) ) {
76
- $sMessage = __( 'No custom message provided.', 'wp-simple-firewall' );
77
  }
78
 
79
  if ( $bIncludeLoggedIn || !did_action( 'init' ) || !Services::WpUsers()->isUserLoggedIn() ) {
@@ -81,8 +81,8 @@ class ProcessOffenses {
81
  ->fireEvent(
82
  'custom_offense',
83
  [
84
- 'audit' => [ 'message' => $sMessage ],
85
- 'offense_count' => $nOffenseCount
86
  ]
87
  );
88
  }
34
  /** @var IPs\ModCon $mod */
35
  $mod = $this->getMod();
36
 
37
+ $tracker = $mod->loadOffenseTracker();
38
  if ( !$this->getCon()->plugin_deleting
39
+ && $tracker->hasVisitorOffended() && $tracker->isCommit() ) {
40
  ( new IPs\Components\ProcessOffense() )
41
  ->setMod( $mod )
42
  ->setIp( Services::IP()->getRequestIp() )
66
 
67
  /**
68
  * Allows 3rd parties to trigger Shield offenses
69
+ * @param string $message
70
+ * @param int $offenseCount
71
  * @param bool $bIncludeLoggedIn
72
  */
73
+ public function processCustomShieldOffense( $message, $offenseCount = 1, $bIncludeLoggedIn = true ) {
74
  if ( $this->getCon()->isPremiumActive() ) {
75
+ if ( empty( $message ) ) {
76
+ $message = __( 'No custom message provided.', 'wp-simple-firewall' );
77
  }
78
 
79
  if ( $bIncludeLoggedIn || !did_action( 'init' ) || !Services::WpUsers()->isUserLoggedIn() ) {
81
  ->fireEvent(
82
  'custom_offense',
83
  [
84
+ 'audit' => [ 'message' => $message ],
85
+ 'offense_count' => (int)$offenseCount
86
  ]
87
  );
88
  }
src/lib/src/Modules/IPs/ModCon.php CHANGED
@@ -48,8 +48,7 @@ class ModCon extends BaseShield\ModCon {
48
  }
49
 
50
  public function getDbHandler_IPs() :Shield\Databases\IPs\Handler {
51
- $new = $this->getDbH( 'ip_lists' );
52
- return empty( $new ) ? $this->getDbH( 'ips' ) : $new;
53
  }
54
 
55
  /**
48
  }
49
 
50
  public function getDbHandler_IPs() :Shield\Databases\IPs\Handler {
51
+ return $this->getDbH( 'ip_lists' );
 
52
  }
53
 
54
  /**
src/lib/src/Modules/IPs/Options.php CHANGED
@@ -30,14 +30,10 @@ class Options extends BaseShield\Options {
30
  return is_array( $aIps ) ? $aIps : [];
31
  }
32
 
33
- /**
34
- * @param string $ip
35
- * @return bool
36
- */
37
- public function getCanIpRequestAutoUnblock( $ip ) {
38
  $existing = $this->getAutoUnblockIps();
39
  return !array_key_exists( $ip, $existing )
40
- || ( Services::Request()->carbon()->subDay( 1 )->timestamp > $existing[ $ip ] );
41
  }
42
 
43
  /**
30
  return is_array( $aIps ) ? $aIps : [];
31
  }
32
 
33
+ public function getCanIpRequestAutoUnblock( string $ip ) :bool {
 
 
 
 
34
  $existing = $this->getAutoUnblockIps();
35
  return !array_key_exists( $ip, $existing )
36
+ || ( Services::Request()->carbon()->subHour( 1 )->timestamp > $existing[ $ip ] );
37
  }
38
 
39
  /**
src/lib/src/Modules/IPs/Strings.php CHANGED
@@ -21,9 +21,9 @@ class Strings extends Base\Strings {
21
  switch ( $section ) {
22
 
23
  case 'section_enable_plugin_feature_ips' :
24
- $sTitleShort = sprintf( '%s/%s', __( 'On', 'wp-simple-firewall' ), __( 'Off', 'wp-simple-firewall' ) );
25
- $sTitle = sprintf( __( 'Enable Module: %s', 'wp-simple-firewall' ), $sModName );
26
- $aSummary = [
27
  sprintf( '%s - %s', __( 'Purpose', 'wp-simple-firewall' ), __( 'The IP Manager allows you to whitelist, blacklist and configure auto-blacklist rules.', 'wp-simple-firewall' ) ),
28
  sprintf( '%s - %s', __( 'Recommendation', 'wp-simple-firewall' ), sprintf( __( 'Keep the %s feature turned on.', 'wp-simple-firewall' ), __( 'IP Manager', 'wp-simple-firewall' ) ) )
29
  .'<br />'.__( 'You should also carefully review the automatic black list settings.', 'wp-simple-firewall' )
@@ -31,9 +31,9 @@ class Strings extends Base\Strings {
31
  break;
32
 
33
  case 'section_auto_black_list' :
34
- $sTitle = __( 'Auto IP Blocking Rules', 'wp-simple-firewall' );
35
- $sTitleShort = __( 'Auto Blocking Rules', 'wp-simple-firewall' );
36
- $aSummary = [
37
  sprintf( '%s - %s', __( 'Purpose', 'wp-simple-firewall' ), __( 'The Automatic IP Black List system will block the IP addresses of naughty visitors after a specified number of offenses.', 'wp-simple-firewall' ) ),
38
  sprintf( '%s - %s', __( 'Recommendation', 'wp-simple-firewall' ), sprintf( __( 'Keep the %s feature turned on.', 'wp-simple-firewall' ), __( 'Automatic IP Black List', 'wp-simple-firewall' ) ) ),
39
  __( "Think of 'offenses' as just a counter for the number of times a visitor does something bad.", 'wp-simple-firewall' )
@@ -46,9 +46,9 @@ class Strings extends Base\Strings {
46
  break;
47
 
48
  case 'section_enable_plugin_feature_bottrap' :
49
- $sTitleShort = __( 'Bot-Trap', 'wp-simple-firewall' );
50
- $sTitle = __( 'Identify And Capture Bots Based On Their Site Activity', 'wp-simple-firewall' );
51
- $aSummary = [
52
  __( "A bot doesn't know what's real and what's not, so it probes many different avenues until it finds something it recognises.", 'wp-simple-firewall' ),
53
  __( "Bot-Trap monitors a set of typical bot behaviours to help identify probing bots.", 'wp-simple-firewall' ),
54
  sprintf( '%s - %s', __( 'Recommendation', 'wp-simple-firewall' ), __( 'Enable as many mouse traps as possible.', 'wp-simple-firewall' ) )
@@ -56,9 +56,9 @@ class Strings extends Base\Strings {
56
  break;
57
 
58
  case 'section_logins':
59
- $sTitleShort = __( 'Login Bots', 'wp-simple-firewall' );
60
- $sTitle = __( 'Detect & Capture Login Bots', 'wp-simple-firewall' );
61
- $aSummary = [
62
  sprintf( '%s - %s', __( 'Summary', 'wp-simple-firewall' ),
63
  __( "Certain bots are designed to test your logins and this feature lets you decide how to handle them.", 'wp-simple-firewall' ) ),
64
  sprintf( '%s - %s', __( 'Recommendation', 'wp-simple-firewall' ),
@@ -69,9 +69,9 @@ class Strings extends Base\Strings {
69
  break;
70
 
71
  case 'section_probes':
72
- $sTitleShort = __( 'Probing Bots', 'wp-simple-firewall' );
73
- $sTitle = __( 'Detect & Capture Probing Bots', 'wp-simple-firewall' );
74
- $aSummary = [
75
  sprintf( '%s - %s', __( 'Summary', 'wp-simple-firewall' ),
76
  __( "Bots are designed to probe and this feature is dedicated to detecting probing bots.", 'wp-simple-firewall' ) ),
77
  sprintf( '%s - %s', __( 'Recommendation', 'wp-simple-firewall' ),
@@ -80,9 +80,9 @@ class Strings extends Base\Strings {
80
  break;
81
 
82
  case 'section_behaviours':
83
- $sTitleShort = __( 'Bot Behaviours', 'wp-simple-firewall' );
84
- $sTitle = __( 'Detect Behaviours Common To Bots', 'wp-simple-firewall' );
85
- $aSummary = [
86
  sprintf( '%s - %s', __( 'Summary', 'wp-simple-firewall' ),
87
  __( "Detect characteristics and behaviour commonly associated with illegitimate bots.", 'wp-simple-firewall' ) ),
88
  sprintf( '%s - %s', __( 'Recommendation', 'wp-simple-firewall' ),
@@ -95,9 +95,9 @@ class Strings extends Base\Strings {
95
  }
96
 
97
  return [
98
- 'title' => $sTitle,
99
- 'title_short' => $sTitleShort,
100
- 'summary' => ( isset( $aSummary ) && is_array( $aSummary ) ) ? $aSummary : [],
101
  ];
102
  }
103
 
21
  switch ( $section ) {
22
 
23
  case 'section_enable_plugin_feature_ips' :
24
+ $titleShort = sprintf( '%s/%s', __( 'On', 'wp-simple-firewall' ), __( 'Off', 'wp-simple-firewall' ) );
25
+ $title = sprintf( __( 'Enable Module: %s', 'wp-simple-firewall' ), $sModName );
26
+ $summary = [
27
  sprintf( '%s - %s', __( 'Purpose', 'wp-simple-firewall' ), __( 'The IP Manager allows you to whitelist, blacklist and configure auto-blacklist rules.', 'wp-simple-firewall' ) ),
28
  sprintf( '%s - %s', __( 'Recommendation', 'wp-simple-firewall' ), sprintf( __( 'Keep the %s feature turned on.', 'wp-simple-firewall' ), __( 'IP Manager', 'wp-simple-firewall' ) ) )
29
  .'<br />'.__( 'You should also carefully review the automatic black list settings.', 'wp-simple-firewall' )
31
  break;
32
 
33
  case 'section_auto_black_list' :
34
+ $title = __( 'Auto IP Blocking Rules', 'wp-simple-firewall' );
35
+ $titleShort = __( 'Auto Blocking Rules', 'wp-simple-firewall' );
36
+ $summary = [
37
  sprintf( '%s - %s', __( 'Purpose', 'wp-simple-firewall' ), __( 'The Automatic IP Black List system will block the IP addresses of naughty visitors after a specified number of offenses.', 'wp-simple-firewall' ) ),
38
  sprintf( '%s - %s', __( 'Recommendation', 'wp-simple-firewall' ), sprintf( __( 'Keep the %s feature turned on.', 'wp-simple-firewall' ), __( 'Automatic IP Black List', 'wp-simple-firewall' ) ) ),
39
  __( "Think of 'offenses' as just a counter for the number of times a visitor does something bad.", 'wp-simple-firewall' )
46
  break;
47
 
48
  case 'section_enable_plugin_feature_bottrap' :
49
+ $titleShort = __( 'Bot-Trap', 'wp-simple-firewall' );
50
+ $title = __( 'Identify And Capture Bots Based On Their Site Activity', 'wp-simple-firewall' );
51
+ $summary = [
52
  __( "A bot doesn't know what's real and what's not, so it probes many different avenues until it finds something it recognises.", 'wp-simple-firewall' ),
53
  __( "Bot-Trap monitors a set of typical bot behaviours to help identify probing bots.", 'wp-simple-firewall' ),
54
  sprintf( '%s - %s', __( 'Recommendation', 'wp-simple-firewall' ), __( 'Enable as many mouse traps as possible.', 'wp-simple-firewall' ) )
56
  break;
57
 
58
  case 'section_logins':
59
+ $titleShort = __( 'Login Bots', 'wp-simple-firewall' );
60
+ $title = __( 'Detect & Capture Login Bots', 'wp-simple-firewall' );
61
+ $summary = [
62
  sprintf( '%s - %s', __( 'Summary', 'wp-simple-firewall' ),
63
  __( "Certain bots are designed to test your logins and this feature lets you decide how to handle them.", 'wp-simple-firewall' ) ),
64
  sprintf( '%s - %s', __( 'Recommendation', 'wp-simple-firewall' ),
69
  break;
70
 
71
  case 'section_probes':
72
+ $titleShort = __( 'Probing Bots', 'wp-simple-firewall' );
73
+ $title = __( 'Detect & Capture Probing Bots', 'wp-simple-firewall' );
74
+ $summary = [
75
  sprintf( '%s - %s', __( 'Summary', 'wp-simple-firewall' ),
76
  __( "Bots are designed to probe and this feature is dedicated to detecting probing bots.", 'wp-simple-firewall' ) ),
77
  sprintf( '%s - %s', __( 'Recommendation', 'wp-simple-firewall' ),
80
  break;
81
 
82
  case 'section_behaviours':
83
+ $titleShort = __( 'Bot Behaviours', 'wp-simple-firewall' );
84
+ $title = __( 'Detect Behaviours Common To Bots', 'wp-simple-firewall' );
85
+ $summary = [
86
  sprintf( '%s - %s', __( 'Summary', 'wp-simple-firewall' ),
87
  __( "Detect characteristics and behaviour commonly associated with illegitimate bots.", 'wp-simple-firewall' ) ),
88
  sprintf( '%s - %s', __( 'Recommendation', 'wp-simple-firewall' ),
95
  }
96
 
97
  return [
98
+ 'title' => $title,
99
+ 'title_short' => $titleShort,
100
+ 'summary' => ( isset( $summary ) && is_array( $summary ) ) ? $summary : [],
101
  ];
102
  }
103
 
src/lib/src/Modules/IPs/UI.php CHANGED
@@ -61,17 +61,6 @@ class UI extends BaseShield\UI {
61
  'tab_ip_analysis' => __( 'IP Analysis', 'wp-simple-firewall' ),
62
  ],
63
  'vars' => [
64
- 'related_hrefs' => [
65
- [
66
- 'href' => $mod->getUrl_AdminPage(),
67
- 'title' => __( 'IP Block Settings', 'wp-simple-firewall' ),
68
- ],
69
- [
70
- 'href' => $mod->createFileDownloadLink( 'db_ip' ),
71
- 'classes' => [ 'shield_file_download' ],
72
- 'title' => sprintf( __( 'Download (as %s)', 'wp-simple-firewall' ), 'CSV' ),
73
- ],
74
- ],
75
  'unique_ips_black' => ( new RetrieveIpsForLists() )
76
  ->setDbHandler( $mod->getDbHandler_IPs() )
77
  ->black(),
@@ -136,14 +125,4 @@ class UI extends BaseShield\UI {
136
  true
137
  );
138
  }
139
-
140
- protected function getSettingsRelatedLinks() :array {
141
- $modInsights = $this->getCon()->getModule_Insights();
142
- return [
143
- [
144
- 'href' => $modInsights->getUrl_SubInsightsPage( 'ips' ),
145
- 'title' => __( 'Analyse & Manage IPs', 'wp-simple-firewall' ),
146
- ]
147
- ];
148
- }
149
  }
61
  'tab_ip_analysis' => __( 'IP Analysis', 'wp-simple-firewall' ),
62
  ],
63
  'vars' => [
 
 
 
 
 
 
 
 
 
 
 
64
  'unique_ips_black' => ( new RetrieveIpsForLists() )
65
  ->setDbHandler( $mod->getDbHandler_IPs() )
66
  ->black(),
125
  true
126
  );
127
  }
 
 
 
 
 
 
 
 
 
 
128
  }
src/lib/src/Modules/Insights/AjaxHandler.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Insights;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield;
6
+
7
+ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
8
+
9
+ protected function processAjaxAction( string $action ) :array {
10
+
11
+ switch ( $action ) {
12
+ case 'dynamic_load':
13
+ $response = $this->ajaxExec_DynamicLoad();
14
+ break;
15
+
16
+ default:
17
+ $response = parent::processAjaxAction( $action );
18
+ }
19
+
20
+ return $response;
21
+ }
22
+
23
+ private function ajaxExec_DynamicLoad() :array {
24
+
25
+ try {
26
+ $pageData = ( new Lib\Requests\DynamicPageLoader() )
27
+ ->setMod( $this->getMod() )
28
+ ->build( Shield\Modules\Base\Lib\Request\FormParams::Retrieve() );
29
+ $success = true;
30
+ }
31
+ catch ( \Exception $e ) {
32
+ $pageData = [
33
+ 'message' => $e->getMessage(),
34
+ 'success' => false,
35
+ ];
36
+ $success = false;
37
+ }
38
+
39
+ return array_merge(
40
+ [
41
+ 'success' => false,
42
+ 'message' => 'no msg',
43
+ 'html' => 'no html',
44
+ 'show_toast' => !$success,
45
+ ],
46
+ $pageData
47
+ );
48
+ }
49
+ }
src/lib/src/Modules/Insights/Lib/Requests/DynamicPageLoader.php ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Insights\Lib\Requests;
4
+
5
+ use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\ModCon;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
8
+
9
+ /**
10
+ * Class DynamicPageLoader
11
+ * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Insights\Lib\Requests
12
+ * @property string $load_type
13
+ * @property string $load_variant
14
+ */
15
+ class DynamicPageLoader extends DynPropertiesClass {
16
+
17
+ use ModConsumer;
18
+
19
+ private $params = [];
20
+
21
+ /**
22
+ * @param array $params
23
+ * @return array
24
+ * @throws \Exception
25
+ */
26
+ public function build( array $params ) :array {
27
+ if ( empty( $params ) || empty( $params[ 'load_params' ] ) ) {
28
+ throw new \Exception( 'No dynamic page loading params' );
29
+ }
30
+ $this->applyFromArray( $params[ 'load_params' ] );
31
+ return [
32
+ 'html' => $this->getContent(),
33
+ 'page_url' => $this->getPageUrl(),
34
+ 'page_title' => $this->getPageTitle(),
35
+ ];
36
+ }
37
+
38
+ private function getContent() :string {
39
+
40
+ switch ( $this->load_type ) {
41
+ case 'settings':
42
+ $content = $this->renderSettings();
43
+ break;
44
+
45
+ default:
46
+ throw new \Exception( 'Unsupported dynamic page load type' );
47
+ }
48
+
49
+ return $content;
50
+ }
51
+
52
+ private function getPageUrl() :string {
53
+ $con = $this->getCon();
54
+
55
+ switch ( $this->load_type ) {
56
+ case 'settings':
57
+ $url = $con->getModule( $this->load_variant )->getUrl_AdminPage();
58
+ break;
59
+
60
+ default:
61
+ throw new \Exception( 'Unsupported dynamic page load type' );
62
+ }
63
+ return $url;
64
+ }
65
+
66
+ private function getPageTitle() :string {
67
+ $con = $this->getCon();
68
+
69
+ switch ( $this->load_type ) {
70
+ case 'settings':
71
+ $title = sprintf( '%s: %s',
72
+ __( 'Settings', 'wp-simple-firewall' ),
73
+ $con->getModule( $this->load_variant )->getMainFeatureName()
74
+ );
75
+ break;
76
+
77
+ default:
78
+ throw new \Exception( 'Unsupported dynamic page load type' );
79
+ }
80
+ return $title;
81
+ }
82
+
83
+ /**
84
+ * @throws \Exception
85
+ */
86
+ private function renderSettings() :string {
87
+
88
+ $mod = $this->getCon()->getModule( $this->load_variant );
89
+ if ( !$mod instanceof ModCon ) {
90
+ throw new \Exception( 'Invalid dynamic page load data (variant)' );
91
+ }
92
+
93
+ return $mod->renderOptionsForm();
94
+ }
95
+ }
src/lib/src/Modules/Insights/Lib/SideMenuBuilder.php ADDED
@@ -0,0 +1,477 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Insights\Lib;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Insights\ModCon;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
+ use FernleafSystems\Wordpress\Services\Services;
8
+
9
+ class SideMenuBuilder {
10
+
11
+ use ModConsumer;
12
+
13
+ public function build() :array {
14
+ $menu = [
15
+ $this->search(),
16
+ $this->overview(),
17
+ $this->stats(),
18
+ $this->settings(),
19
+ $this->scans(),
20
+ $this->ips(),
21
+ $this->audit(),
22
+ $this->traffic(),
23
+ $this->users(),
24
+ $this->integrations(),
25
+ $this->gopro(),
26
+ $this->tools(),
27
+ $this->docs(),
28
+ ];
29
+
30
+ foreach ( $menu as $key => $item ) {
31
+ $item = Services::DataManipulation()->mergeArraysRecursive( [
32
+ 'slug' => 'no-slug',
33
+ 'title' => __( 'NO TITLE', 'wp-simple-firewall' ),
34
+ 'href' => '#',
35
+ 'classes' => [],
36
+ 'id' => '',
37
+ 'active' => $this->getInav() === $item[ 'slug' ],
38
+ 'sub_items' => [],
39
+ 'target' => '',
40
+ 'data' => [],
41
+ 'badge' => [],
42
+ ], $item );
43
+
44
+ if ( !empty( $item[ 'sub_items' ] ) ) {
45
+ $item[ 'data' ][ 'toggle' ] = 'collapse';
46
+ $item[ 'href' ] = '#collapse-'.$item[ 'slug' ];
47
+
48
+ // Set parent active if any sub-items are active
49
+ if ( !$item[ 'active' ] ) {
50
+ $item[ 'active' ] = count( array_filter( $item[ 'sub_items' ], function ( $sub ) {
51
+ return $sub[ 'active' ] ?? false;
52
+ } ) );
53
+ }
54
+ }
55
+
56
+ $menu[ $key ] = $item;
57
+ }
58
+
59
+ return $menu;
60
+ }
61
+
62
+ private function ips() :array {
63
+ $con = $this->getCon();
64
+ /** @var ModCon $mod */
65
+ $mod = $this->getMod();
66
+
67
+ $slug = 'ips';
68
+
69
+ $subItems = [
70
+ [
71
+ 'slug' => $slug.'-manage',
72
+ 'title' => __( 'Manage IPs', 'wp-simple-firewall' ),
73
+ 'href' => $mod->getUrl_SubInsightsPage( 'ips' ),
74
+ 'active' => $this->getInav() === $slug,
75
+ ],
76
+ [
77
+ 'slug' => $slug.'-blocksettings',
78
+ 'title' => sprintf( '%s: %s', __( 'Settings', 'wp-simple-firewall' ), __( 'IP Blocking', 'wp-simple-firewall' ) ),
79
+ 'href' => $con->getModule_IPs()->getUrl_AdminPage(),
80
+ ],
81
+ [
82
+ 'slug' => $slug.'-antibotsettings',
83
+ 'title' => sprintf( '%s: %s', __( 'Settings', 'wp-simple-firewall' ), __( 'AntiBot', 'wp-simple-firewall' ) ),
84
+ 'href' => $con->getModule_IPs()->getUrl_DirectLinkToSection( 'section_antibot' ),
85
+ ],
86
+ [
87
+ 'slug' => 'ips-download',
88
+ 'href' => $con->getModule_IPs()->createFileDownloadLink( 'db_ip' ),
89
+ 'classes' => [ 'shield_file_download' ],
90
+ 'title' => sprintf( __( 'Download (as %s)', 'wp-simple-firewall' ), 'CSV' ),
91
+ ],
92
+ ];
93
+
94
+ return [
95
+ 'slug' => $slug,
96
+ 'title' => __( 'IPs and Bots', 'wp-simple-firewall' ),
97
+ 'img' => $this->getCon()->urls->forImage( 'bootstrap/diagram-3.svg' ),
98
+ 'introjs' => __( "Protection begins by detecting bad bots - Review and Analyse all visitor IPs that have an impact on your site.", 'wp-simple-firewall' ),
99
+ 'sub_items' => $subItems,
100
+ ];
101
+ }
102
+
103
+ private function audit() :array {
104
+ $con = $this->getCon();
105
+ /** @var ModCon $mod */
106
+ $mod = $this->getMod();
107
+
108
+ $slug = 'audit';
109
+ $subItems = [
110
+ [
111
+ 'slug' => $slug.'-log',
112
+ 'title' => __( 'View Log', 'wp-simple-firewall' ),
113
+ 'href' => $mod->getUrl_SubInsightsPage( $slug ),
114
+ 'active' => $this->getInav() === $slug,
115
+ ],
116
+ [
117
+ 'slug' => $slug.'-settings',
118
+ 'title' => __( 'Settings', 'wp-simple-firewall' ),
119
+ 'href' => $con->getModule_AuditTrail()->getUrl_AdminPage(),
120
+ ],
121
+ [
122
+ 'slug' => 'audit-download',
123
+ 'title' => sprintf( __( 'Download (as %s)', 'wp-simple-firewall' ), 'CSV' ),
124
+ 'href' => $con->getModule_AuditTrail()->createFileDownloadLink( 'db_audit' ),
125
+ 'classes' => [ 'shield_file_download' ],
126
+ ],
127
+ [
128
+ 'slug' => 'audit-glossary',
129
+ 'title' => __( 'Audit Trail Glossary', 'wp-simple-firewall' ),
130
+ 'href' => 'https://shsec.io/audittrailglossary',
131
+ 'target' => '_blank',
132
+ ],
133
+ ];
134
+
135
+ return [
136
+ 'slug' => 'audit',
137
+ 'title' => __( 'Audit Trail', 'wp-simple-firewall' ),
138
+ 'img' => $this->getCon()->urls->forImage( 'bootstrap/person-lines-fill.svg' ),
139
+ 'introjs' => __( "Track and review all important actions taken on your site - see the Who, What and When.", 'wp-simple-firewall' ),
140
+ 'sub_items' => $subItems,
141
+ ];
142
+ }
143
+
144
+ private function scans() :array {
145
+ /** @var ModCon $mod */
146
+ $mod = $this->getMod();
147
+ $con = $this->getCon();
148
+
149
+ $slug = 'scans';
150
+
151
+ $subItems = [
152
+ [
153
+ 'slug' => $slug.'-run',
154
+ 'title' => __( 'Run Scan', 'wp-simple-firewall' ),
155
+ 'href' => $mod->getUrl_ScansRun(),
156
+ 'active' => $this->getInav() === 'scans_run',
157
+ ],
158
+ [
159
+ 'slug' => $slug.'-results',
160
+ 'title' => __( 'Scan Results', 'wp-simple-firewall' ),
161
+ 'href' => $mod->getUrl_ScansResults(),
162
+ 'active' => $this->getInav() === 'scans_results',
163
+ ],
164
+ [
165
+ 'slug' => $slug.'-settings',
166
+ 'title' => sprintf( '%s: %s', __( 'Settings', 'wp-simple-firewall' ), __( 'Automatic Scans', 'wp-simple-firewall' ) ),
167
+ 'href' => $con->getModule_HackGuard()->getUrl_AdminPage(),
168
+ ],
169
+ ];
170
+
171
+ return [
172
+ 'slug' => $slug,
173
+ 'title' => __( 'Scans', 'wp-simple-firewall' ),
174
+ 'img' => $this->getCon()->urls->forImage( 'bootstrap/shield-shaded.svg' ),
175
+ 'introjs' => sprintf( __( "Run a %s scan at any time, or view the results from the latest scan.", 'wp-simple-firewall' ),
176
+ $this->getCon()->getHumanName() ),
177
+ 'sub_items' => $subItems,
178
+ ];
179
+ }
180
+
181
+ private function search() :array {
182
+ /** @var ModCon $mod */
183
+ $mod = $this->getMod();
184
+ return [
185
+ 'slug' => 'search',
186
+ 'title' => __( 'Search', 'wp-simple-firewall' ),
187
+ 'img' => $this->getCon()->urls->forImage( 'bootstrap/search.svg' ),
188
+ 'id' => 'NavMenuSearch',
189
+ 'href' => $mod->getUrl_SubInsightsPage( 'overview' ),
190
+ 'introjs' => __( 'Use Search to find any option within the entire plugin' ),
191
+ 'data' => [
192
+ 'toggle' => 'modal',
193
+ 'target' => '#SearchDialog',
194
+ ],
195
+ ];
196
+ }
197
+
198
+ private function stats() :array {
199
+ /** @var ModCon $mod */
200
+ $mod = $this->getMod();
201
+
202
+ return [
203
+ 'slug' => 'reports',
204
+ 'title' => __( 'Reports', 'wp-simple-firewall' ),
205
+ 'img' => $this->getCon()->urls->forImage( 'bootstrap/graph-up.svg' ),
206
+ 'href' => $mod->getUrl_SubInsightsPage( 'reports' ),
207
+ 'introjs' => __( 'Reports use the built-in stats to show you how Shield is working to secure your site.' ),
208
+ 'sub_items' => [
209
+ [
210
+ 'slug' => 'reports-stats',
211
+ 'title' => __( 'Stats', 'wp-simple-firewall' ),
212
+ 'href' => $mod->getUrl_SubInsightsPage( 'stats' ),
213
+ 'active' => $this->getInav() === 'stats'
214
+ ],
215
+ [
216
+ 'slug' => 'reports-charts',
217
+ 'title' => __( 'Charts', 'wp-simple-firewall' ),
218
+ 'href' => $mod->getUrl_SubInsightsPage( 'reports' ),
219
+ 'active' => $this->getInav() === 'reports'
220
+ ],
221
+ ],
222
+ ];
223
+ }
224
+
225
+ private function overview() :array {
226
+ /** @var ModCon $mod */
227
+ $mod = $this->getMod();
228
+ return [
229
+ 'slug' => 'overview',
230
+ 'title' => __( 'Overview', 'wp-simple-firewall' ),
231
+ 'img' => $this->getCon()->urls->forImage( 'bootstrap/binoculars.svg' ),
232
+ 'href' => $mod->getUrl_SubInsightsPage( 'overview' ),
233
+ 'introjs' => sprintf( __( "Review your entire %s configuration at a glance to see what's working and what's not.", 'wp-simple-firewall' ),
234
+ $this->getCon()->getHumanName() ),
235
+ ];
236
+ }
237
+
238
+ private function settings() :array {
239
+ /** @var ModCon $mod */
240
+ $mod = $this->getMod();
241
+ $slug = 'settings';
242
+
243
+ $subItems = [];
244
+ foreach ( $mod->getModulesSummaryData() as $modData ) {
245
+ if ( $modData[ 'show_mod_opts' ] ) {
246
+ $subItems[] = [
247
+ 'slug' => $slug.'-'.$modData[ 'slug' ],
248
+ 'title' => $modData[ 'sidebar_name' ] ?? $modData[ 'name' ],
249
+ 'href' => $modData[ 'href' ],
250
+ 'classes' => [ 'dynamic_body_load' ],
251
+ 'data' => [
252
+ 'load_type' => $slug,
253
+ 'load_variant' => $modData[ 'slug' ],
254
+ ],
255
+ 'active' => Services::Request()->query( 'subnav' ) === $modData[ 'slug' ]
256
+ ];
257
+ }
258
+ }
259
+
260
+ return [
261
+ 'slug' => $slug,
262
+ 'title' => __( 'Settings', 'wp-simple-firewall' ),
263
+ 'img' => $this->getCon()->urls->forImage( 'bootstrap/sliders.svg' ),
264
+ 'introjs' => sprintf( __( "%s is a big plugin split into modules, and each with their own options - use these jump-off points to find the specific option you need.", 'wp-simple-firewall' ),
265
+ $this->getCon()->getHumanName() ),
266
+ 'sub_items' => $subItems,
267
+ ];
268
+ }
269
+
270
+ private function integrations() :array {
271
+ $con = $this->getCon();
272
+ return [
273
+ 'slug' => 'integrations',
274
+ 'img' => $this->getCon()->urls->forImage( 'bootstrap/puzzle-fill.svg' ),
275
+ 'title' => __( 'Integrations', 'wp-simple-firewall' ),
276
+ 'introjs' => __( "Integrate with your favourite plugins to block SPAM and manage Shield better.", 'wp-simple-firewall' ),
277
+ 'sub_items' => [
278
+ [
279
+ 'slug' => 'integrations-settings',
280
+ 'title' => __( 'Settings', 'wp-simple-firewall' ),
281
+ 'href' => $con->getModule_Integrations()->getUrl_AdminPage(),
282
+ ],
283
+ [
284
+ 'slug' => 'integrations-spam',
285
+ 'title' => __( 'Contact Form SPAM', 'wp-simple-firewall' ),
286
+ 'href' => $con->getModule_Integrations()->getUrl_DirectLinkToSection( 'section_spam' ),
287
+ ],
288
+ ],
289
+ ];
290
+ }
291
+
292
+ private function reports() :array {
293
+ /** @var ModCon $mod */
294
+ $mod = $this->getMod();
295
+ return [
296
+ 'slug' => 'reports',
297
+ 'title' => __( 'Reports', 'wp-simple-firewall' ),
298
+ 'img' => $this->getCon()->urls->forImage( 'bootstrap/graph-up.svg' ),
299
+ 'href' => $mod->getUrl_SubInsightsPage( 'reports' ),
300
+ ];
301
+ }
302
+
303
+ private function docs() :array {
304
+ /** @var ModCon $mod */
305
+ $mod = $this->getMod();
306
+ return [
307
+ 'slug' => 'docs',
308
+ 'title' => __( "View Docs", 'wp-simple-firewall' ),
309
+ 'img' => $this->getCon()->urls->forImage( 'bootstrap/book-half.svg' ),
310
+ 'href' => $mod->getUrl_SubInsightsPage( 'docs' ),
311
+ ];
312
+ }
313
+
314
+ private function gopro() :array {
315
+ /** @var ModCon $mod */
316
+ $mod = $this->getMod();
317
+
318
+ $isPro = $this->getCon()->isPremiumActive();
319
+
320
+ if ( $isPro ) {
321
+ $subItems = [];
322
+ }
323
+ else {
324
+ $subItems = [
325
+ [
326
+ 'slug' => 'license-gopro',
327
+ 'title' => __( 'Check License', 'wp-simple-firewall' ),
328
+ 'href' => $mod->getUrl_SubInsightsPage( 'license' ),
329
+ 'active' => $this->getInav() === 'license'
330
+ ],
331
+ [
332
+ 'slug' => 'license-trial',
333
+ 'title' => __( 'Free Trial', 'wp-simple-firewall' ),
334
+ 'href' => $mod->getUrl_SubInsightsPage( 'free_trial' ),
335
+ 'active' => $this->getInav() === 'free_trial'
336
+ ],
337
+ [
338
+ 'slug' => 'license-features',
339
+ 'href' => 'https://shsec.io/gp',
340
+ 'title' => __( 'ShieldPRO Features', 'wp-simple-firewall' ),
341
+ 'target' => '_blank',
342
+ ],
343
+ ];
344
+ }
345
+
346
+ return [
347
+ 'slug' => 'license',
348
+ 'title' => $isPro ? __( 'ShieldPRO', 'wp-simple-firewall' ) : __( 'Go PRO!', 'wp-simple-firewall' ),
349
+ 'img' => $this->getCon()->urls->forImage( 'bootstrap/award.svg' ),
350
+ 'href' => $mod->getUrl_SubInsightsPage( 'license' ),
351
+ 'sub_items' => $subItems,
352
+ ];
353
+ }
354
+
355
+ private function tools() :array {
356
+ $con = $this->getCon();
357
+ /** @var ModCon $mod */
358
+ $mod = $this->getMod();
359
+
360
+ $slug = 'tools';
361
+ $subItems = [
362
+ [
363
+ 'slug' => $slug.'-importexport',
364
+ 'title' => __( 'Import / Export', 'wp-simple-firewall' ),
365
+ 'href' => $mod->getUrl_SubInsightsPage( 'importexport' ),
366
+ 'active' => $this->getInav() === 'importexport'
367
+ ],
368
+ [
369
+ 'slug' => $slug.'-whitelabel',
370
+ 'title' => __( 'White Label', 'wp-simple-firewall' ),
371
+ 'href' => $con->getModule_SecAdmin()->getUrl_DirectLinkToSection( 'section_whitelabel' ),
372
+ ],
373
+ [
374
+ 'slug' => $slug.'-notes',
375
+ 'title' => __( 'Admin Notes', 'wp-simple-firewall' ),
376
+ 'href' => $mod->getUrl_SubInsightsPage( 'notes' ),
377
+ 'active' => $this->getInav() === 'notes'
378
+ ],
379
+ [
380
+ 'slug' => $slug.'-debug',
381
+ 'title' => __( "Debug Info", 'wp-simple-firewall' ),
382
+ 'href' => $mod->getUrl_SubInsightsPage( 'debug' ),
383
+ 'active' => $this->getInav() === 'debug'
384
+ ]
385
+ ];
386
+
387
+ return [
388
+ 'slug' => $slug,
389
+ 'title' => __( 'Tools', 'wp-simple-firewall' ),
390
+ 'img' => $this->getCon()->urls->forImage( 'bootstrap/tools.svg' ),
391
+ 'introjs' => __( "Important security tools, such a import/export, whitelabel and admin notes.", 'wp-simple-firewall' ),
392
+ 'sub_items' => $subItems,
393
+ ];
394
+ }
395
+
396
+ private function traffic() :array {
397
+ $con = $this->getCon();
398
+ /** @var ModCon $mod */
399
+ $mod = $this->getMod();
400
+
401
+ $slug = 'traffic';
402
+ $subItems = [
403
+ [
404
+ 'slug' => $slug.'-log',
405
+ 'title' => __( 'View Log', 'wp-simple-firewall' ),
406
+ 'href' => $mod->getUrl_SubInsightsPage( $slug ),
407
+ 'active' => $this->getInav() === $slug,
408
+ ],
409
+ [
410
+ 'slug' => $slug.'-ratelimitsettings',
411
+ 'title' => sprintf( '%s: %s', __( 'Settings', 'wp-simple-firewall' ), __( 'Rate Limiting', 'wp-simple-firewall' ) ),
412
+ 'href' => $con->getModule_Traffic()->getUrl_DirectLinkToSection( 'section_traffic_limiter' ),
413
+ ],
414
+ [
415
+ 'slug' => 'traffic-download',
416
+ 'href' => $con->getModule_Traffic()->createFileDownloadLink( 'db_traffic' ),
417
+ 'classes' => [ 'shield_file_download' ],
418
+ 'title' => sprintf( __( 'Download (as %s)', 'wp-simple-firewall' ), 'CSV' ),
419
+ ],
420
+ ];
421
+
422
+ return [
423
+ 'slug' => 'traffic',
424
+ 'title' => __( 'Traffic', 'wp-simple-firewall' ),
425
+ 'img' => $this->getCon()->urls->forImage( 'bootstrap/stoplights.svg' ),
426
+ 'introjs' => __( "Monitor and watch traffic as it hits your site.", 'wp-simple-firewall' ),
427
+ 'sub_items' => $subItems,
428
+ ];
429
+ }
430
+
431
+ private function users() :array {
432
+ $con = $this->getCon();
433
+ /** @var ModCon $mod */
434
+ $mod = $this->getMod();
435
+
436
+ $subItems = [
437
+ [
438
+ 'slug' => 'users-sessions',
439
+ 'title' => __( 'View Sessions', 'wp-simple-firewall' ),
440
+ 'href' => $mod->getUrl_SubInsightsPage( 'users' ),
441
+ ],
442
+ [
443
+ 'slug' => 'users-secadmin',
444
+ 'title' => sprintf( '%s: %s', __( 'Settings', 'wp-simple-firewall' ), __( 'Security Admin', 'wp-simple-firewall' ) ),
445
+ 'href' => $con->getModule_SecAdmin()->getUrl_DirectLinkToSection( 'section_security_admin_settings' ),
446
+ ],
447
+ [
448
+ 'slug' => 'users-settings',
449
+ 'title' => sprintf( '%s: %s', __( 'Settings', 'wp-simple-firewall' ), __( 'Sessions', 'wp-simple-firewall' ) ),
450
+ 'href' => $con->getModule_UserManagement()
451
+ ->getUrl_DirectLinkToSection( 'section_user_session_management' ),
452
+ ],
453
+ [
454
+ 'slug' => 'users-passwords',
455
+ 'title' => sprintf( '%s: %s', __( 'Settings', 'wp-simple-firewall' ), __( 'Password Policies', 'wp-simple-firewall' ) ),
456
+ 'href' => $con->getModule_UserManagement()->getUrl_DirectLinkToSection( 'section_passwords' ),
457
+ ],
458
+ [
459
+ 'slug' => 'users-suspend',
460
+ 'title' => sprintf( '%s: %s', __( 'Settings', 'wp-simple-firewall' ), __( 'User Suspension', 'wp-simple-firewall' ) ),
461
+ 'href' => $con->getModule_UserManagement()->getUrl_DirectLinkToSection( 'section_suspend' ),
462
+ ],
463
+ ];
464
+
465
+ return [
466
+ 'slug' => 'users',
467
+ 'title' => __( 'Users', 'wp-simple-firewall' ),
468
+ 'img' => $this->getCon()->urls->forImage( 'bootstrap/person-badge.svg' ),
469
+ 'introjs' => __( 'View sessions, and configure session timeouts and passwords requirements.', 'wp-simple-firewall' ),
470
+ 'sub_items' => $subItems,
471
+ ];
472
+ }
473
+
474
+ private function getInav() :string {
475
+ return (string)Services::Request()->query( 'inav' );
476
+ }
477
+ }
src/lib/src/Modules/Insights/ModCon.php CHANGED
@@ -18,13 +18,21 @@ class ModCon extends BaseShield\ModCon {
18
 
19
  protected function onModulesLoaded() {
20
  $this->maybeRedirectToAdmin();
 
 
 
 
 
 
 
 
21
  }
22
 
23
  private function maybeRedirectToAdmin() {
24
  $con = $this->getCon();
25
  $activeFor = $con->getModule_Plugin()->getActivateLength();
26
  if ( !Services::WpGeneral()->isAjax() && is_admin() && !$con->isModulePage() && $activeFor < 4 ) {
27
- Services::Response()->redirect( $this->getUrl_AdminPage() );
28
  }
29
  }
30
 
@@ -32,6 +40,14 @@ class ModCon extends BaseShield\ModCon {
32
  return add_query_arg( [ 'analyse_ip' => $ip ], $this->getUrl_SubInsightsPage( 'ips' ) );
33
  }
34
 
 
 
 
 
 
 
 
 
35
  public function getUrl_SubInsightsPage( string $subPage ) :string {
36
  return add_query_arg(
37
  [ 'inav' => sanitize_key( $subPage ) ],
@@ -47,23 +63,34 @@ class ModCon extends BaseShield\ModCon {
47
 
48
  public function getScriptLocalisations() :array {
49
  $con = $this->getCon();
 
 
50
  $locals = parent::getScriptLocalisations();
51
  $locals[] = [
52
  'plugin',
53
  'icwp_wpsf_vars_insights',
54
  [
55
  'strings' => [
56
- 'downloading_file' => __( 'Downloading file, please wait...', 'wp-simple-firewall' ),
57
- 'downloading_file_problem' => __( 'There was a problem downloading the file.', 'wp-simple-firewall' ),
58
- 'select_action' => __( 'Please select an action to perform.', 'wp-simple-firewall' ),
59
- 'are_you_sure' => __( 'Are you sure?', 'wp-simple-firewall' ),
60
  ],
61
  ]
62
  ];
 
63
  $locals[] = [
64
  $con->prefix( 'ip_detect' ),
65
  'icwp_wpsf_vars_ipdetect',
66
- [ 'ajax' => $con->getModule_Plugin()->getAjaxActionData( 'ipdetect' ) ]
 
 
 
 
 
 
 
 
 
 
67
  ];
68
 
69
  return $locals;
@@ -76,10 +103,13 @@ class ModCon extends BaseShield\ModCon {
76
  ];
77
 
78
  $con = $this->getCon();
79
- $iNav = Services::Request()->query( 'inav' );
 
 
 
80
 
81
- if ( $con->getIsPage_PluginAdmin() && !empty( $iNav ) ) {
82
- switch ( $iNav ) {
83
 
84
  case 'importexport':
85
  $enq[ Enqueue::JS ][] = 'shield/import';
@@ -107,22 +137,24 @@ class ModCon extends BaseShield\ModCon {
107
  break;
108
 
109
  case 'notes':
110
- case 'scans':
 
111
  case 'audit':
112
  case 'traffic':
113
  case 'ips':
114
  case 'debug':
115
  case 'users':
 
116
 
117
  $enq[ Enqueue::JS ][] = 'shield-tables';
118
- if ( $iNav == 'scans' ) {
119
  $enq[ Enqueue::JS ][] = 'shield-scans';
120
  }
121
- elseif ( $iNav == 'ips' ) {
122
  $enq[ Enqueue::JS ][] = 'shield/ipanalyse';
123
  }
124
 
125
- if ( in_array( $iNav, [ 'audit', 'traffic' ] ) ) {
126
  $enq[ Enqueue::JS ][] = 'bootstrap-datepicker';
127
  $enq[ Enqueue::CSS ][] = 'bootstrap-datepicker';
128
  }
18
 
19
  protected function onModulesLoaded() {
20
  $this->maybeRedirectToAdmin();
21
+ $this->maybeRedirectToOverview();
22
+ }
23
+
24
+ private function maybeRedirectToOverview() {
25
+ $req = Services::Request();
26
+ if ( $this->isThisModAdminPage() && empty( $req->query( 'inav' ) ) ) {
27
+ Services::Response()->redirect( $this->getCon()->getPluginUrl_DashboardHome() );
28
+ }
29
  }
30
 
31
  private function maybeRedirectToAdmin() {
32
  $con = $this->getCon();
33
  $activeFor = $con->getModule_Plugin()->getActivateLength();
34
  if ( !Services::WpGeneral()->isAjax() && is_admin() && !$con->isModulePage() && $activeFor < 4 ) {
35
+ Services::Response()->redirect( $this->getCon()->getPluginUrl_DashboardHome() );
36
  }
37
  }
38
 
40
  return add_query_arg( [ 'analyse_ip' => $ip ], $this->getUrl_SubInsightsPage( 'ips' ) );
41
  }
42
 
43
+ public function getUrl_ScansResults() :string {
44
+ return $this->getUrl_SubInsightsPage( 'scans_results' );
45
+ }
46
+
47
+ public function getUrl_ScansRun() :string {
48
+ return $this->getUrl_SubInsightsPage( 'scans_run' );
49
+ }
50
+
51
  public function getUrl_SubInsightsPage( string $subPage ) :string {
52
  return add_query_arg(
53
  [ 'inav' => sanitize_key( $subPage ) ],
63
 
64
  public function getScriptLocalisations() :array {
65
  $con = $this->getCon();
66
+ $modPlugin = $con->getModule_Plugin();
67
+
68
  $locals = parent::getScriptLocalisations();
69
  $locals[] = [
70
  'plugin',
71
  'icwp_wpsf_vars_insights',
72
  [
73
  'strings' => [
74
+ 'select_action' => __( 'Please select an action to perform.', 'wp-simple-firewall' ),
75
+ 'are_you_sure' => __( 'Are you sure?', 'wp-simple-firewall' ),
 
 
76
  ],
77
  ]
78
  ];
79
+
80
  $locals[] = [
81
  $con->prefix( 'ip_detect' ),
82
  'icwp_wpsf_vars_ipdetect',
83
+ [ 'ajax' => $modPlugin->getAjaxActionData( 'ipdetect' ) ]
84
+ ];
85
+
86
+ $locals[] = [
87
+ 'shield/navigation',
88
+ 'shield_vars_navigation',
89
+ [
90
+ 'ajax' => [
91
+ 'dynamic_load' => $this->getAjaxActionData( 'dynamic_load' )
92
+ ]
93
+ ]
94
  ];
95
 
96
  return $locals;
103
  ];
104
 
105
  $con = $this->getCon();
106
+ $inav = Services::Request()->query( 'inav' );
107
+ if ( empty( $inav ) ) {
108
+ $inav = 'overview';
109
+ }
110
 
111
+ if ( $con->getIsPage_PluginAdmin() && !empty( $inav ) ) {
112
+ switch ( $inav ) {
113
 
114
  case 'importexport':
115
  $enq[ Enqueue::JS ][] = 'shield/import';
137
  break;
138
 
139
  case 'notes':
140
+ case 'scans_results':
141
+ case 'scans_run':
142
  case 'audit':
143
  case 'traffic':
144
  case 'ips':
145
  case 'debug':
146
  case 'users':
147
+ case 'stats':
148
 
149
  $enq[ Enqueue::JS ][] = 'shield-tables';
150
+ if ( in_array( $inav, [ 'scans_results', 'scans_run' ] ) ) {
151
  $enq[ Enqueue::JS ][] = 'shield-scans';
152
  }
153
+ elseif ( $inav == 'ips' ) {
154
  $enq[ Enqueue::JS ][] = 'shield/ipanalyse';
155
  }
156
 
157
+ if ( in_array( $inav, [ 'audit', 'traffic' ] ) ) {
158
  $enq[ Enqueue::JS ][] = 'bootstrap-datepicker';
159
  $enq[ Enqueue::CSS ][] = 'bootstrap-datepicker';
160
  }
src/lib/src/Modules/Insights/UI.php CHANGED
@@ -52,12 +52,12 @@ class UI extends BaseShield\UI {
52
  $mod = $this->getMod();
53
  $req = Services::Request();
54
 
55
- $sNavSection = $req->query( 'inav', 'dashboard' );
56
  $subNavSection = $req->query( 'subnav' );
57
 
58
  $modPlugin = $con->getModule_Plugin();
59
 
60
- switch ( $sNavSection ) {
61
 
62
  case 'audit':
63
  $modAudit = $con->getModule_AuditTrail();
@@ -67,28 +67,6 @@ class UI extends BaseShield\UI {
67
  'content' => [
68
  'table_audit' => $auditUI->renderAuditTrailTable(),
69
  ],
70
- 'vars' => [
71
- 'related_hrefs' => [
72
- [
73
- 'href' => $con->getModule_AuditTrail()->getUrl_AdminPage(),
74
- 'title' => __( 'Audit Trail Settings', 'wp-simple-firewall' ),
75
- ],
76
- [
77
- 'href' => 'https://shsec.io/audittrailglossary',
78
- 'title' => __( 'Audit Trail Glossary', 'wp-simple-firewall' ),
79
- 'new' => true,
80
- ],
81
- [
82
- 'href' => $mod->getUrl_SubInsightsPage( 'traffic' ),
83
- 'title' => __( 'Traffic Log', 'wp-simple-firewall' ),
84
- ],
85
- [
86
- 'href' => $modAudit->createFileDownloadLink( 'db_audit' ),
87
- 'classes' => [ 'shield_file_download' ],
88
- 'title' => sprintf( __( 'Download (as %s)', 'wp-simple-firewall' ), 'CSV' ),
89
- ],
90
- ]
91
- ]
92
  ];
93
  break;
94
 
@@ -100,23 +78,6 @@ class UI extends BaseShield\UI {
100
  'content' => [
101
  'table_traffic' => $trafficUI->renderTrafficTable(),
102
  ],
103
- 'vars' => [
104
- 'related_hrefs' => [
105
- [
106
- 'href' => $con->getModule_Traffic()->getUrl_AdminPage(),
107
- 'title' => __( 'Traffic Settings', 'wp-simple-firewall' ),
108
- ],
109
- [
110
- 'href' => $mod->getUrl_SubInsightsPage( 'audit' ),
111
- 'title' => __( 'Audit Trail', 'wp-simple-firewall' ),
112
- ],
113
- [
114
- 'href' => $modTraffic->createFileDownloadLink( 'db_traffic' ),
115
- 'classes' => [ 'shield_file_download' ],
116
- 'title' => sprintf( __( 'Download (as %s)', 'wp-simple-firewall' ), 'CSV' ),
117
- ],
118
- ]
119
- ]
120
  ];
121
  break;
122
 
@@ -176,7 +137,8 @@ class UI extends BaseShield\UI {
176
  $data = $UIReporting->buildInsightsVars();
177
  break;
178
 
179
- case 'scans':
 
180
  /** @var Shield\Modules\HackGuard\UI $UIHackGuard */
181
  $UIHackGuard = $con->getModule_HackGuard()->getUIHandler();
182
  $data = $UIHackGuard->buildInsightsVars();
@@ -186,6 +148,12 @@ class UI extends BaseShield\UI {
186
  $data = $con->modules[ $subNavSection ]->getUIHandler()->getBaseDisplayData();
187
  break;
188
 
 
 
 
 
 
 
189
  case 'users':
190
  /** @var Shield\Modules\UserManagement\UI $UIUsers */
191
  $UIUsers = $con->modules[ 'user_management' ]->getUIHandler();
@@ -201,21 +169,23 @@ class UI extends BaseShield\UI {
201
  }
202
 
203
  $availablePages = [
204
- 'settings' => __( 'Plugin Settings', 'wp-simple-firewall' ),
205
- 'dashboard' => __( 'Dashboard', 'wp-simple-firewall' ),
206
- 'overview' => __( 'Security Overview', 'wp-simple-firewall' ),
207
- 'scans' => __( 'Scans', 'wp-simple-firewall' ),
208
- 'docs' => __( 'Docs', 'wp-simple-firewall' ),
209
- 'ips' => __( 'IP Management and Analysis', 'wp-simple-firewall' ),
210
- 'audit' => __( 'Audit Trail', 'wp-simple-firewall' ),
211
- 'traffic' => __( 'Traffic', 'wp-simple-firewall' ),
212
- 'notes' => __( 'Admin Notes', 'wp-simple-firewall' ),
213
- 'users' => __( 'User Sessions', 'wp-simple-firewall' ),
214
- 'license' => __( 'ShieldPRO', 'wp-simple-firewall' ),
215
- 'importexport' => __( 'Import / Export', 'wp-simple-firewall' ),
216
- 'reports' => __( 'Reports', 'wp-simple-firewall' ),
217
- 'debug' => __( 'Debug', 'wp-simple-firewall' ),
218
- 'free_trial' => __( 'Free Trial', 'wp-simple-firewall' ),
 
 
219
  ];
220
 
221
  $modsToSearch = array_filter(
@@ -225,7 +195,7 @@ class UI extends BaseShield\UI {
225
  }
226
  );
227
 
228
- $pageTitle = $availablePages[ $sNavSection ];
229
  if ( !empty( $subNavSection ) ) {
230
  $pageTitle = sprintf( '%s: %s',
231
  __( 'Settings', 'wp-simple-firewall' ), $modsToSearch[ $subNavSection ][ 'name' ] );
@@ -236,17 +206,15 @@ class UI extends BaseShield\UI {
236
  $this->getBaseDisplayData(),
237
  [
238
  'classes' => [
239
- 'page_container' => 'page-insights page-'.$sNavSection
240
  ],
241
  'flags' => [
242
- 'is_dashboard' => $sNavSection === 'dashboard',
243
- 'is_advanced' => $modPlugin->isShowAdvanced()
244
  ],
245
  'hrefs' => [
246
- 'back_to_dash' => $mod->getUrl_SubInsightsPage( 'dashboard' ),
247
- 'go_pro' => 'https://shsec.io/shieldgoprofeature',
248
- 'nav_home' => $mod->getUrl_AdminPage(),
249
- 'img_banner' => $con->urls->forImage( 'pluginlogo_banner-170x40.png' )
250
  ],
251
  'strings' => [
252
  'page_title' => $pageTitle
@@ -255,14 +223,22 @@ class UI extends BaseShield\UI {
255
  'changelog_id' => $con->cfg->meta[ 'announcekit_changelog_id' ],
256
  'mods' => $this->buildSelectData_ModuleSettings(),
257
  'search_select' => $this->buildSelectData_OptionsSearch(),
258
- 'active_module_settings' => $subNavSection
 
 
 
259
  ],
260
  ],
261
  $data
262
  );
263
 
 
 
 
 
 
264
  return $mod->renderTemplate(
265
- sprintf( '/wpadmin_pages/insights/%s/index.twig', $sNavSection ),
266
  $data,
267
  true
268
  );
@@ -332,14 +308,14 @@ class UI extends BaseShield\UI {
332
 
333
  private function printGoProFooter() {
334
  $con = $this->getCon();
335
- $nav = Services::Request()->query( 'inav', 'dashboard' );
336
  echo $this->getMod()->renderTemplate(
337
  'snippets/go_pro_banner.twig',
338
  [
339
  'flags' => [
340
  'show_promo' => $con->isModulePage()
341
  && !$con->isPremiumActive()
342
- && ( !in_array( $nav, [ 'scans' ] ) ),
343
  ],
344
  'hrefs' => [
345
  'go_pro' => 'https://shsec.io/shieldgoprofeature',
@@ -361,29 +337,4 @@ class UI extends BaseShield\UI {
361
  );
362
  }
363
  }
364
-
365
- private function printPluginDeactivateSurvey() {
366
- if ( Services::WpPost()->isCurrentPage( 'plugins.php' ) ) {
367
-
368
- $opts = [
369
- 'reason_confusing' => "It's too confusing",
370
- 'reason_expected' => "It's not what I expected",
371
- 'reason_accident' => "I downloaded it accidentally",
372
- 'reason_alternative' => "I'm already using an alternative",
373
- 'reason_trust' => "I don't trust the developer :(",
374
- 'reason_not_work' => "It doesn't work",
375
- 'reason_errors' => "I'm getting errors",
376
- ];
377
-
378
- echo $this->getMod()->renderTemplate( 'snippets/plugin-deactivate-survey.php', [
379
- 'strings' => [
380
- 'editing_restricted' => __( 'Editing this option is currently restricted.', 'wp-simple-firewall' ),
381
- ],
382
- 'inputs' => [
383
- 'checkboxes' => Services::DataManipulation()->shuffleArray( $opts )
384
- ],
385
- 'js_snippets' => []
386
- ] );
387
- }
388
- }
389
  }
52
  $mod = $this->getMod();
53
  $req = Services::Request();
54
 
55
+ $inav = $req->query( 'inav', 'overview' );
56
  $subNavSection = $req->query( 'subnav' );
57
 
58
  $modPlugin = $con->getModule_Plugin();
59
 
60
+ switch ( $inav ) {
61
 
62
  case 'audit':
63
  $modAudit = $con->getModule_AuditTrail();
67
  'content' => [
68
  'table_audit' => $auditUI->renderAuditTrailTable(),
69
  ],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  ];
71
  break;
72
 
78
  'content' => [
79
  'table_traffic' => $trafficUI->renderTrafficTable(),
80
  ],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  ];
82
  break;
83
 
137
  $data = $UIReporting->buildInsightsVars();
138
  break;
139
 
140
+ case 'scans_results':
141
+ case 'scans_run':
142
  /** @var Shield\Modules\HackGuard\UI $UIHackGuard */
143
  $UIHackGuard = $con->getModule_HackGuard()->getUIHandler();
144
  $data = $UIHackGuard->buildInsightsVars();
148
  $data = $con->modules[ $subNavSection ]->getUIHandler()->getBaseDisplayData();
149
  break;
150
 
151
+ case 'stats':
152
+ /** @var Shield\Modules\Events\UI $UIEvents */
153
+ $UIEvents = $con->getModule_Events()->getUIHandler();
154
+ $data = $UIEvents->buildInsightsVars();
155
+ break;
156
+
157
  case 'users':
158
  /** @var Shield\Modules\UserManagement\UI $UIUsers */
159
  $UIUsers = $con->modules[ 'user_management' ]->getUIHandler();
169
  }
170
 
171
  $availablePages = [
172
+ 'stats' => __( 'Quick Stats', 'wp-simple-firewall' ),
173
+ 'settings' => __( 'Plugin Settings', 'wp-simple-firewall' ),
174
+ 'dashboard' => __( 'Dashboard', 'wp-simple-firewall' ),
175
+ 'overview' => __( 'Security Overview', 'wp-simple-firewall' ),
176
+ 'scans_results' => __( 'Scan Results', 'wp-simple-firewall' ),
177
+ 'scans_run' => __( 'Run Scans', 'wp-simple-firewall' ),
178
+ 'docs' => __( 'Docs', 'wp-simple-firewall' ),
179
+ 'ips' => __( 'IP Management and Analysis', 'wp-simple-firewall' ),
180
+ 'audit' => __( 'Audit Trail', 'wp-simple-firewall' ),
181
+ 'traffic' => __( 'Traffic', 'wp-simple-firewall' ),
182
+ 'notes' => __( 'Admin Notes', 'wp-simple-firewall' ),
183
+ 'users' => __( 'User Sessions', 'wp-simple-firewall' ),
184
+ 'license' => __( 'ShieldPRO', 'wp-simple-firewall' ),
185
+ 'importexport' => __( 'Import / Export', 'wp-simple-firewall' ),
186
+ 'reports' => __( 'Reports', 'wp-simple-firewall' ),
187
+ 'debug' => __( 'Debug', 'wp-simple-firewall' ),
188
+ 'free_trial' => __( 'Free Trial', 'wp-simple-firewall' ),
189
  ];
190
 
191
  $modsToSearch = array_filter(
195
  }
196
  );
197
 
198
+ $pageTitle = $availablePages[ $inav ];
199
  if ( !empty( $subNavSection ) ) {
200
  $pageTitle = sprintf( '%s: %s',
201
  __( 'Settings', 'wp-simple-firewall' ), $modsToSearch[ $subNavSection ][ 'name' ] );
206
  $this->getBaseDisplayData(),
207
  [
208
  'classes' => [
209
+ 'page_container' => 'page-insights page-'.$inav
210
  ],
211
  'flags' => [
212
+ 'is_advanced' => $modPlugin->isShowAdvanced()
 
213
  ],
214
  'hrefs' => [
215
+ 'go_pro' => 'https://shsec.io/shieldgoprofeature',
216
+ 'nav_home' => $mod->getUrl_AdminPage(),
217
+ 'img_banner' => $con->urls->forImage( 'pluginlogo_banner-170x40.png' )
 
218
  ],
219
  'strings' => [
220
  'page_title' => $pageTitle
223
  'changelog_id' => $con->cfg->meta[ 'announcekit_changelog_id' ],
224
  'mods' => $this->buildSelectData_ModuleSettings(),
225
  'search_select' => $this->buildSelectData_OptionsSearch(),
226
+ 'active_module_settings' => $subNavSection,
227
+ 'navbar_menu' => ( new Lib\SideMenuBuilder() )
228
+ ->setMod( $this->getMod() )
229
+ ->build()
230
  ],
231
  ],
232
  $data
233
  );
234
 
235
+ $templateDir = $inav;
236
+ if ( strpos( $inav, 'scans_' ) === 0 ) {
237
+ $templateDir = implode( '/', explode( '_', $inav, 2 ) );
238
+ }
239
+
240
  return $mod->renderTemplate(
241
+ sprintf( '/wpadmin_pages/insights/%s/index.twig', $templateDir ),
242
  $data,
243
  true
244
  );
308
 
309
  private function printGoProFooter() {
310
  $con = $this->getCon();
311
+ $nav = Services::Request()->query( 'inav', 'overview' );
312
  echo $this->getMod()->renderTemplate(
313
  'snippets/go_pro_banner.twig',
314
  [
315
  'flags' => [
316
  'show_promo' => $con->isModulePage()
317
  && !$con->isPremiumActive()
318
+ && ( !in_array( $nav, [ 'scans_results', 'scans_run' ] ) ),
319
  ],
320
  'hrefs' => [
321
  'go_pro' => 'https://shsec.io/shieldgoprofeature',
337
  );
338
  }
339
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
340
  }
src/lib/src/Modules/Integrations/Lib/MainWP/Server/UI/ExtensionSettingsPage.php CHANGED
@@ -20,8 +20,8 @@ class ExtensionSettingsPage {
20
 
21
  if ( 'mainwp_page_'.$this->getCon()->mwpVO->extension->page === $hook ) {
22
 
23
- $enqueues[ Enqueue::JS ][] = 'shield/mainwp-extension';
24
- $enqueues[ Enqueue::CSS ][] = 'mainwp-extension';
25
 
26
  // $handle = 'semantic-ui-datatables-select';
27
  // wp_register_script(
20
 
21
  if ( 'mainwp_page_'.$this->getCon()->mwpVO->extension->page === $hook ) {
22
 
23
+ $enqueues[ Enqueue::JS ][] = 'shield/mainwp';
24
+ $enqueues[ Enqueue::CSS ][] = 'shield/mainwp';
25
 
26
  // $handle = 'semantic-ui-datatables-select';
27
  // wp_register_script(
src/lib/src/Modules/Integrations/Lib/MainWP/Server/UI/PageRender/SitesList.php CHANGED
@@ -132,7 +132,7 @@ class SitesList extends BaseRender {
132
  return str_replace(
133
  $WP->getAdminUrl(),
134
  '',
135
- $this->getCon()->getModule_Insights()->getUrl_SubInsightsPage( 'scans' )
136
  );
137
  }
138
 
132
  return str_replace(
133
  $WP->getAdminUrl(),
134
  '',
135
+ $this->getCon()->getModule_Insights()->getUrl_ScansResults()
136
  );
137
  }
138
 
src/lib/src/Modules/Integrations/Strings.php CHANGED
@@ -64,6 +64,7 @@ class Strings extends Base\Strings {
64
  $name = __( 'MainWP Integration', 'wp-simple-firewall' );
65
  $summary = __( "Turn-On Shield's Built-In Extension For MainWP Server And Client Installations", 'wp-simple-firewall' );
66
  $desc = [
 
67
  __( 'Easily integrate Shield Security to help you manage your site security from within MainWP.', 'wp-simple-firewall' ),
68
  __( "You don't need to install a separate extension for MainWP.", 'wp-simple-firewall' ),
69
  sprintf( '%s: %s', __( 'Important', 'wp-simple-firewall' ),
64
  $name = __( 'MainWP Integration', 'wp-simple-firewall' );
65
  $summary = __( "Turn-On Shield's Built-In Extension For MainWP Server And Client Installations", 'wp-simple-firewall' );
66
  $desc = [
67
+ __( 'This is a ShieldPRO-only feature.', 'wp-simple-firewall' ),
68
  __( 'Easily integrate Shield Security to help you manage your site security from within MainWP.', 'wp-simple-firewall' ),
69
  __( "You don't need to install a separate extension for MainWP.", 'wp-simple-firewall' ),
70
  sprintf( '%s: %s', __( 'Important', 'wp-simple-firewall' ),
src/lib/src/Modules/License/UI.php CHANGED
@@ -56,7 +56,6 @@ class UI extends BaseShield\UI {
56
  'license_table' => $aLicenseTableVars,
57
  'activation_url' => $WP->getHomeUrl(),
58
  'error' => $mod->getLastErrors( true ),
59
- 'related_hrefs' => $this->getSettingsRelatedLinks()
60
  ],
61
  'inputs' => [
62
  'license_key' => [
@@ -90,26 +89,4 @@ class UI extends BaseShield\UI {
90
  $mod = $this->getMod();
91
  return $mod->getLicenseHandler()->hasValidWorkingLicense();
92
  }
93
-
94
- protected function getSettingsRelatedLinks() :array {
95
- $modInsights = $this->getCon()->getModule_Insights();
96
- $links = [];
97
- if ( !$this->getCon()->isPremiumActive() ) {
98
- $links[] = [
99
- 'href' => $modInsights->getUrl_SubInsightsPage( 'free_trial' ),
100
- 'title' => __( 'Free Trial', 'wp-simple-firewall' ),
101
- ];
102
- }
103
- $links[] = [
104
- 'href' => 'https://shsec.io/c5',
105
- 'title' => __( 'License Activation', 'wp-simple-firewall' ),
106
- 'new' => true,
107
- ];
108
- $links[] = [
109
- 'href' => 'https://shsec.io/gp',
110
- 'title' => __( 'ShieldPRO Features', 'wp-simple-firewall' ),
111
- 'new' => true,
112
- ];
113
- return $links;
114
- }
115
  }
56
  'license_table' => $aLicenseTableVars,
57
  'activation_url' => $WP->getHomeUrl(),
58
  'error' => $mod->getLastErrors( true ),
 
59
  ],
60
  'inputs' => [
61
  'license_key' => [
89
  $mod = $this->getMod();
90
  return $mod->getLicenseHandler()->hasValidWorkingLicense();
91
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  }
src/lib/src/Modules/LoginGuard/Lib/AntiBot/AntibotSetup.php CHANGED
@@ -57,46 +57,46 @@ class AntibotSetup {
57
  if ( !empty( $providers ) ) {
58
 
59
  AntiBot\FormProviders\WordPress::SetProviders( $providers );
60
- /** @var AntiBot\FormProviders\BaseFormProvider[] $aFormProviders */
61
- $aFormProviders = [
62
  new AntiBot\FormProviders\WordPress()
63
  ];
64
 
65
  if ( $this->getMod()->getIfSupport3rdParty() ) {
66
  if ( @class_exists( 'BuddyPress' ) ) {
67
- $aFormProviders[] = new AntiBot\FormProviders\BuddyPress();
68
  }
69
  if ( @class_exists( 'Easy_Digital_Downloads' ) ) {
70
- $aFormProviders[] = new AntiBot\FormProviders\EasyDigitalDownloads();
71
  }
72
  if ( @class_exists( 'LearnPress' ) ) {
73
- $aFormProviders[] = new AntiBot\FormProviders\LearnPress();
74
  }
75
  if ( function_exists( 'mepr_autoloader' ) || @class_exists( 'MeprAccountCtrl' ) ) {
76
- $aFormProviders[] = new AntiBot\FormProviders\MemberPress();
77
  }
78
  if ( function_exists( 'UM' ) && @class_exists( 'UM' ) && method_exists( 'UM', 'form' ) ) {
79
- $aFormProviders[] = new AntiBot\FormProviders\UltimateMember();
80
  }
81
  if ( @class_exists( 'Paid_Member_Subscriptions' ) && function_exists( 'pms_errors' ) ) {
82
- $aFormProviders[] = new AntiBot\FormProviders\PaidMemberSubscriptions();
83
  }
84
  if ( defined( 'PROFILE_BUILDER_VERSION' ) ) {
85
- $aFormProviders[] = new AntiBot\FormProviders\ProfileBuilder();
86
  }
87
  if ( @class_exists( 'WooCommerce' ) ) {
88
- $aFormProviders[] = new AntiBot\FormProviders\WooCommerce();
89
  }
90
  if ( defined( 'WPMEM_VERSION' ) && function_exists( 'wpmem_init' ) ) {
91
- $aFormProviders[] = new AntiBot\FormProviders\WPMembers();
92
  }
93
  if ( false && @class_exists( 'UserRegistration' ) && @function_exists( 'UR' ) ) {
94
- $aFormProviders[] = new AntiBot\FormProviders\UserRegistration();
95
  }
96
  }
97
 
98
- foreach ( $aFormProviders as $oForm ) {
99
- $oForm->setMod( $mod )->run();
100
  }
101
  }
102
  }
57
  if ( !empty( $providers ) ) {
58
 
59
  AntiBot\FormProviders\WordPress::SetProviders( $providers );
60
+ /** @var AntiBot\FormProviders\BaseFormProvider[] $formProviders */
61
+ $formProviders = [
62
  new AntiBot\FormProviders\WordPress()
63
  ];
64
 
65
  if ( $this->getMod()->getIfSupport3rdParty() ) {
66
  if ( @class_exists( 'BuddyPress' ) ) {
67
+ $formProviders[] = new AntiBot\FormProviders\BuddyPress();
68
  }
69
  if ( @class_exists( 'Easy_Digital_Downloads' ) ) {
70
+ $formProviders[] = new AntiBot\FormProviders\EasyDigitalDownloads();
71
  }
72
  if ( @class_exists( 'LearnPress' ) ) {
73
+ $formProviders[] = new AntiBot\FormProviders\LearnPress();
74
  }
75
  if ( function_exists( 'mepr_autoloader' ) || @class_exists( 'MeprAccountCtrl' ) ) {
76
+ $formProviders[] = new AntiBot\FormProviders\MemberPress();
77
  }
78
  if ( function_exists( 'UM' ) && @class_exists( 'UM' ) && method_exists( 'UM', 'form' ) ) {
79
+ $formProviders[] = new AntiBot\FormProviders\UltimateMember();
80
  }
81
  if ( @class_exists( 'Paid_Member_Subscriptions' ) && function_exists( 'pms_errors' ) ) {
82
+ $formProviders[] = new AntiBot\FormProviders\PaidMemberSubscriptions();
83
  }
84
  if ( defined( 'PROFILE_BUILDER_VERSION' ) ) {
85
+ $formProviders[] = new AntiBot\FormProviders\ProfileBuilder();
86
  }
87
  if ( @class_exists( 'WooCommerce' ) ) {
88
+ $formProviders[] = new AntiBot\FormProviders\WooCommerce();
89
  }
90
  if ( defined( 'WPMEM_VERSION' ) && function_exists( 'wpmem_init' ) ) {
91
+ $formProviders[] = new AntiBot\FormProviders\WPMembers();
92
  }
93
  if ( false && @class_exists( 'UserRegistration' ) && @function_exists( 'UR' ) ) {
94
+ $formProviders[] = new AntiBot\FormProviders\UserRegistration();
95
  }
96
  }
97
 
98
+ foreach ( $formProviders as $form ) {
99
+ $form->setMod( $mod )->run();
100
  }
101
  }
102
  }
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/MfaController.php CHANGED
@@ -2,6 +2,7 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor;
4
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Session\Update;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
@@ -12,6 +13,7 @@ class MfaController {
12
 
13
  use Shield\Modules\ModConsumer;
14
  use Shield\Utilities\Consumer\WpLoginCapture;
 
15
 
16
  /**
17
  * @var Provider\BaseProvider[]
@@ -23,10 +25,11 @@ class MfaController {
23
  */
24
  private $oLoginIntentPageHandler;
25
 
26
- public function run() {
27
  add_action( 'init', [ $this, 'onWpInit' ], 10, 2 );
28
  add_action( 'wp_loaded', [ $this, 'onWpLoaded' ], 10, 2 );
29
  $this->setupLoginCaptureHooks();
 
30
  }
31
 
32
  public function onWpInit() {
@@ -71,6 +74,49 @@ class MfaController {
71
  }
72
  }
73
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  private function assessLoginIntent( \WP_User $user ) {
75
  if ( $this->getLoginIntentExpiresAt() > 0 ) {
76
 
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor;
4
 
5
+ use FernleafSystems\Utilities\Logic\ExecOnce;
6
  use FernleafSystems\Wordpress\Plugin\Shield;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Session\Update;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
13
 
14
  use Shield\Modules\ModConsumer;
15
  use Shield\Utilities\Consumer\WpLoginCapture;
16
+ use ExecOnce;
17
 
18
  /**
19
  * @var Provider\BaseProvider[]
25
  */
26
  private $oLoginIntentPageHandler;
27
 
28
+ protected function run() {
29
  add_action( 'init', [ $this, 'onWpInit' ], 10, 2 );
30
  add_action( 'wp_loaded', [ $this, 'onWpLoaded' ], 10, 2 );
31
  $this->setupLoginCaptureHooks();
32
+ $this->handleLoginLink();
33
  }
34
 
35
  public function onWpInit() {
74
  }
75
  }
76
 
77
+ private function handleLoginLink() {
78
+ add_action( $this->getCon()->prefix( 'shield_nonce_action' ), function ( string $action ) {
79
+ if ( strpos( $action, '2fa_verify' ) === 0 ) {
80
+ try {
81
+ $this->processEmail2faLink();
82
+ }
83
+ catch ( \Exception $e ) {
84
+ wp_die( $e->getMessage() );
85
+ }
86
+ }
87
+ } );
88
+ }
89
+
90
+ private function processEmail2faLink() {
91
+ $req = Services::Request();
92
+ $user = sanitize_user( $req->query( 'user' ) );
93
+ if ( empty( $user ) ) {
94
+ throw new \Exception( 'Not valid data.' );
95
+ }
96
+ $user = Services::WpUsers()->getUserByUsername( $user );
97
+ if ( !$user instanceof \WP_User ) {
98
+ throw new \Exception( 'Not valid data.' );
99
+ }
100
+ $providers = $this->getProvidersForUser( $user, true );
101
+ if ( !isset( $providers[ Provider\Email::SLUG ] ) ) {
102
+ throw new \Exception( 'Not a support provider' );
103
+ }
104
+ if ( !$providers[ Provider\Email::SLUG ]->validateLoginIntent( $user ) ) {
105
+ throw new \Exception( 'Login validation failed.' );
106
+ }
107
+ $providers[ Provider\Email::SLUG ]->postSuccessActions( $user );
108
+ if ( (int)$user->ID !== (int)Services::WpUsers()->getCurrentWpUserId() ) {
109
+ throw new \Exception( 'Action completed successfully. Please refresh your browser where you logged-in.' );
110
+ }
111
+
112
+ if ( $req->query( 'redirect_to' ) ) {
113
+ Services::Response()->redirect( $req->query( 'redirect_to' ) );
114
+ }
115
+ else {
116
+ Services::Response()->redirectToAdmin();
117
+ }
118
+ }
119
+
120
  private function assessLoginIntent( \WP_User $user ) {
121
  if ( $this->getLoginIntentExpiresAt() > 0 ) {
122
 
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Email.php CHANGED
@@ -149,7 +149,8 @@ class Email extends BaseProvider {
149
  'code' => $code
150
  ],
151
  'hrefs' => [
152
- 'login_link' => 'https://shsec.io/96'
 
153
  ],
154
  'strings' => [
155
  'someone' => __( 'Someone attempted to login into this WordPress site using your account.', 'wp-simple-firewall' ),
@@ -223,6 +224,22 @@ class Email extends BaseProvider {
223
  && ( $this->isEnforced( $user ) || $opts->isEnabledEmailAuthAnyUserSet() );
224
  }
225
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
  /**
227
  * @param \WP_User $user
228
  * @return string
149
  'code' => $code
150
  ],
151
  'hrefs' => [
152
+ 'login_link' => 'https://shsec.io/96',
153
+ 'verify_2fa' => $this->genLoginLink( $user, $code )
154
  ],
155
  'strings' => [
156
  'someone' => __( 'Someone attempted to login into this WordPress site using your account.', 'wp-simple-firewall' ),
224
  && ( $this->isEnforced( $user ) || $opts->isEnabledEmailAuthAnyUserSet() );
225
  }
226
 
227
+ private function genLoginLink( \WP_User $user, string $otp ) :string {
228
+ /** @var LoginGuard\Options $opts */
229
+ $opts = $this->getOptions();
230
+ $action = uniqid( '2fa_verify' );
231
+ return add_query_arg(
232
+ [
233
+ 'user' => $user->user_login,
234
+ $this->getLoginFormParameter() => $otp,
235
+ 'shield_nonce_action' => $action,
236
+ 'shield_nonce' => $this->getCon()
237
+ ->nonce_handler->create( $action, $opts->getLoginIntentMinutes()*60 ),
238
+ ],
239
+ Services::WpGeneral()->getHomeUrl()
240
+ );
241
+ }
242
+
243
  /**
244
  * @param \WP_User $user
245
  * @return string
src/lib/src/Modules/LoginGuard/Processor.php CHANGED
@@ -26,7 +26,7 @@ class Processor extends BaseShield\Processor {
26
  $this->launchAntiBot();
27
  }, -100 );
28
 
29
- $mod->getLoginIntentController()->run();
30
  }
31
  }
32
 
26
  $this->launchAntiBot();
27
  }, -100 );
28
 
29
+ $mod->getLoginIntentController()->execute();
30
  }
31
  }
32
 
src/lib/src/Modules/Plugin/AjaxHandler.php CHANGED
@@ -3,6 +3,7 @@
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield;
 
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin;
7
  use FernleafSystems\Wordpress\Services\Services;
8
  use FernleafSystems\Wordpress\Services\Utilities\Net\FindSourceFromIp;
@@ -43,10 +44,6 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
43
  $response = $this->ajaxExec_SetPluginTrackingPerm();
44
  break;
45
 
46
- case 'send_deactivate_survey':
47
- $response = $this->ajaxExec_SendDeactivateSurvey();
48
- break;
49
-
50
  case 'sgoptimizer_turnoff':
51
  $response = $this->ajaxExec_TurnOffSiteGroundOptions();
52
  break;
@@ -66,24 +63,6 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
66
  return $response;
67
  }
68
 
69
- private function ajaxExec_SendDeactivateSurvey() :array {
70
- /** @var ModCon $mod */
71
- $mod = $this->getMod();
72
- $results = [];
73
- foreach ( $_POST as $sKey => $sValue ) {
74
- if ( strpos( $sKey, 'reason_' ) === 0 ) {
75
- $results[] = str_replace( 'reason_', '', $sKey ).': '.$sValue;
76
- }
77
- }
78
- $mod->getEmailProcessor()
79
- ->send(
80
- $mod->getSurveyEmail(),
81
- 'Shield Deactivation Survey',
82
- implode( "\n<br/>", $results )
83
- );
84
- return [ 'success' => true ];
85
- }
86
-
87
  private function ajaxExec_PluginBadgeClose() :array {
88
  /** @var ModCon $mod */
89
  $mod = $this->getMod();
@@ -193,22 +172,22 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
193
 
194
  private function ajaxExec_ImportFromSite() :array {
195
  $success = false;
196
- $aFormParams = array_merge(
197
  [
198
  'confirm' => 'N'
199
  ],
200
- $this->getAjaxFormParams()
201
  );
202
 
203
  // TODO: align with wizard AND combine with file upload errors
204
- if ( $aFormParams[ 'confirm' ] !== 'Y' ) {
205
  $msg = __( 'Please check the box to confirm your intent to overwrite settings', 'wp-simple-firewall' );
206
  }
207
  else {
208
- $sMasterSiteUrl = $aFormParams[ 'MasterSiteUrl' ];
209
- $sSecretKey = $aFormParams[ 'MasterSiteSecretKey' ];
210
- $bEnabledNetwork = $aFormParams[ 'ShieldNetwork' ] === 'Y';
211
- $bDisableNetwork = $aFormParams[ 'ShieldNetwork' ] === 'N';
212
  $bNetwork = $bEnabledNetwork ? true : ( $bDisableNetwork ? false : null );
213
 
214
  /** @var Shield\Databases\AdminNotes\Insert $oInserter */
@@ -234,7 +213,7 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
234
  /** @var ModCon $mod */
235
  $mod = $this->getMod();
236
  $success = false;
237
- $formParams = $this->getAjaxFormParams();
238
 
239
  $note = trim( $formParams[ 'admin_note' ] ?? '' );
240
  if ( !$mod->getCanAdminNotes() ) {
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Request\FormParams;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin;
8
  use FernleafSystems\Wordpress\Services\Services;
9
  use FernleafSystems\Wordpress\Services\Utilities\Net\FindSourceFromIp;
44
  $response = $this->ajaxExec_SetPluginTrackingPerm();
45
  break;
46
 
 
 
 
 
47
  case 'sgoptimizer_turnoff':
48
  $response = $this->ajaxExec_TurnOffSiteGroundOptions();
49
  break;
63
  return $response;
64
  }
65
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  private function ajaxExec_PluginBadgeClose() :array {
67
  /** @var ModCon $mod */
68
  $mod = $this->getMod();
172
 
173
  private function ajaxExec_ImportFromSite() :array {
174
  $success = false;
175
+ $formParams = array_merge(
176
  [
177
  'confirm' => 'N'
178
  ],
179
+ FormParams::Retrieve()
180
  );
181
 
182
  // TODO: align with wizard AND combine with file upload errors
183
+ if ( $formParams[ 'confirm' ] !== 'Y' ) {
184
  $msg = __( 'Please check the box to confirm your intent to overwrite settings', 'wp-simple-firewall' );
185
  }
186
  else {
187
+ $sMasterSiteUrl = $formParams[ 'MasterSiteUrl' ];
188
+ $sSecretKey = $formParams[ 'MasterSiteSecretKey' ];
189
+ $bEnabledNetwork = $formParams[ 'ShieldNetwork' ] === 'Y';
190
+ $bDisableNetwork = $formParams[ 'ShieldNetwork' ] === 'N';
191
  $bNetwork = $bEnabledNetwork ? true : ( $bDisableNetwork ? false : null );
192
 
193
  /** @var Shield\Databases\AdminNotes\Insert $oInserter */
213
  /** @var ModCon $mod */
214
  $mod = $this->getMod();
215
  $success = false;
216
+ $formParams = FormParams::Retrieve();
217
 
218
  $note = trim( $formParams[ 'admin_note' ] ?? '' );
219
  if ( !$mod->getCanAdminNotes() ) {
src/lib/src/Modules/Plugin/Insights/DashboardCards.php CHANGED
@@ -56,7 +56,6 @@ class DashboardCards {
56
  'c' => [
57
  'title' => __( 'Shield Settings', 'wp-simple-firewall' ),
58
  'img' => $con->urls->forImage( 'bootstrap/sliders.svg' ),
59
- 'introjs' => sprintf( __( "%s is a big plugin split into modules, and each with their own options - use these jump-off points to find the specific option you need.", 'wp-simple-firewall' ), $name ),
60
  'paras' => [
61
  sprintf( __( "%s settings are arranged into modules.", 'wp-simple-firewall' ), $name )
62
  .' '.__( 'Choose the module you need from the dropdown.', 'wp-simple-firewall' )
@@ -113,7 +112,6 @@ class DashboardCards {
113
  'overview' => [
114
  'title' => __( 'Security Overview', 'wp-simple-firewall' ),
115
  'img' => $con->urls->forImage( 'bootstrap/binoculars.svg' ),
116
- 'introjs' => sprintf( __( "Review your entire Shield Security configuration at a glance to see what's working and what's not.", 'wp-simple-firewall' ), $name ),
117
  'paras' => [
118
  sprintf( __( "Review your entire %s security configuration at a glance to see what's working and what's not.", 'wp-simple-firewall' ), $name ),
119
  ],
@@ -128,7 +126,6 @@ class DashboardCards {
128
  'scans' => [
129
  'title' => __( 'Scans and Protection', 'wp-simple-firewall' ),
130
  'img' => $con->urls->forImage( 'bootstrap/shield-shaded.svg' ),
131
- 'introjs' => sprintf( __( "Run a %s scan at any time, or view the results from the latest scan.", 'wp-simple-firewall' ), $name ),
132
  'paras' => [
133
  sprintf( __( "Use %s Scans to automatically detect and repair intrusions on your site.", 'wp-simple-firewall' ), $name ),
134
  sprintf( __( "%s scans WordPress core files, plugins, themes and will detect Malware (ShieldPRO).", 'wp-simple-firewall' ), $name ),
@@ -136,7 +133,7 @@ class DashboardCards {
136
  'actions' => [
137
  [
138
  'text' => __( "Run Scans", 'wp-simple-firewall' ),
139
- 'href' => $modInsights->getUrl_SubInsightsPage( 'scans' ),
140
  ],
141
  [
142
  'text' => __( "Scans & Hack Guard Settings", 'wp-simple-firewall' ),
@@ -195,7 +192,6 @@ class DashboardCards {
195
  'ips' => [
196
  'title' => __( 'IP Blocking and Bypass', 'wp-simple-firewall' ),
197
  'img' => $con->urls->forImage( 'bootstrap/diagram-3.svg' ),
198
- 'introjs' => __( "Protection begins by detecting bad bots - Review and Analyse all visitor IPs that have an impact on your site.", 'wp-simple-firewall' ),
199
  'paras' => [
200
  __( "Shield automatically detects and blocks bad IP addresses based on your security settings.", 'wp-simple-firewall' ),
201
  __( "The IP Analysis Tool shows you all information for a given IP as it relates to your site.", 'wp-simple-firewall' ),
@@ -215,7 +211,6 @@ class DashboardCards {
215
  'audit_trail' => [
216
  'title' => __( 'Audit Trail', 'wp-simple-firewall' ),
217
  'img' => $con->urls->forImage( 'bootstrap/person-lines-fill.svg' ),
218
- 'introjs' => __( "Track and review all important actions taken on your site - see the Who, What and When.", 'wp-simple-firewall' ),
219
  'paras' => [
220
  __( "Provides in-depth logging for all major WordPress events.", 'wp-simple-firewall' ),
221
  ],
@@ -234,7 +229,6 @@ class DashboardCards {
234
  'traffic' => [
235
  'title' => __( 'Traffic Logging', 'wp-simple-firewall' ),
236
  'img' => $con->urls->forImage( 'bootstrap/stoplights.svg' ),
237
- 'introjs' => __( "Monitor and watch traffic as it hits your site.", 'wp-simple-firewall' ),
238
  'paras' => [
239
  __( "Use traffic logging to monitor visitor requests to your site.", 'wp-simple-firewall' ),
240
  __( "Traffic Rate Limiting lets you throttle requests from any single visitor.", 'wp-simple-firewall' ),
@@ -254,7 +248,6 @@ class DashboardCards {
254
  'users' => [
255
  'title' => __( 'WordPress Users', 'wp-simple-firewall' ),
256
  'img' => $con->urls->forImage( 'bootstrap/people.svg' ),
257
- 'introjs' => __( "Set user session timeouts and passwords requirements.", 'wp-simple-firewall' ),
258
  'paras' => [
259
  __( "Adds fine control over user sessions, account re-use, password strength and expiration, and user suspension.", 'wp-simple-firewall' ),
260
  ],
@@ -367,7 +360,6 @@ class DashboardCards {
367
 
368
  'integrations' => [
369
  'title' => __( '3rd Party Integrations', 'wp-simple-firewall' ),
370
- 'introjs' => __( "Integrate with your favourite plugins to block SPAM and manage Shield better.", 'wp-simple-firewall' ),
371
  'img' => $con->urls->forImage( 'bootstrap/link-45deg.svg' ),
372
  'paras' => [
373
  __( "Shield integrates with 3rd party plugins and services.", 'wp-simple-firewall' ),
56
  'c' => [
57
  'title' => __( 'Shield Settings', 'wp-simple-firewall' ),
58
  'img' => $con->urls->forImage( 'bootstrap/sliders.svg' ),
 
59
  'paras' => [
60
  sprintf( __( "%s settings are arranged into modules.", 'wp-simple-firewall' ), $name )
61
  .' '.__( 'Choose the module you need from the dropdown.', 'wp-simple-firewall' )
112
  'overview' => [
113
  'title' => __( 'Security Overview', 'wp-simple-firewall' ),
114
  'img' => $con->urls->forImage( 'bootstrap/binoculars.svg' ),
 
115
  'paras' => [
116
  sprintf( __( "Review your entire %s security configuration at a glance to see what's working and what's not.", 'wp-simple-firewall' ), $name ),
117
  ],
126
  'scans' => [
127
  'title' => __( 'Scans and Protection', 'wp-simple-firewall' ),
128
  'img' => $con->urls->forImage( 'bootstrap/shield-shaded.svg' ),
 
129
  'paras' => [
130
  sprintf( __( "Use %s Scans to automatically detect and repair intrusions on your site.", 'wp-simple-firewall' ), $name ),
131
  sprintf( __( "%s scans WordPress core files, plugins, themes and will detect Malware (ShieldPRO).", 'wp-simple-firewall' ), $name ),
133
  'actions' => [
134
  [
135
  'text' => __( "Run Scans", 'wp-simple-firewall' ),
136
+ 'href' => $modInsights->getUrl_ScansResults(),
137
  ],
138
  [
139
  'text' => __( "Scans & Hack Guard Settings", 'wp-simple-firewall' ),
192
  'ips' => [
193
  'title' => __( 'IP Blocking and Bypass', 'wp-simple-firewall' ),
194
  'img' => $con->urls->forImage( 'bootstrap/diagram-3.svg' ),
 
195
  'paras' => [
196
  __( "Shield automatically detects and blocks bad IP addresses based on your security settings.", 'wp-simple-firewall' ),
197
  __( "The IP Analysis Tool shows you all information for a given IP as it relates to your site.", 'wp-simple-firewall' ),
211
  'audit_trail' => [
212
  'title' => __( 'Audit Trail', 'wp-simple-firewall' ),
213
  'img' => $con->urls->forImage( 'bootstrap/person-lines-fill.svg' ),
 
214
  'paras' => [
215
  __( "Provides in-depth logging for all major WordPress events.", 'wp-simple-firewall' ),
216
  ],
229
  'traffic' => [
230
  'title' => __( 'Traffic Logging', 'wp-simple-firewall' ),
231
  'img' => $con->urls->forImage( 'bootstrap/stoplights.svg' ),
 
232
  'paras' => [
233
  __( "Use traffic logging to monitor visitor requests to your site.", 'wp-simple-firewall' ),
234
  __( "Traffic Rate Limiting lets you throttle requests from any single visitor.", 'wp-simple-firewall' ),
248
  'users' => [
249
  'title' => __( 'WordPress Users', 'wp-simple-firewall' ),
250
  'img' => $con->urls->forImage( 'bootstrap/people.svg' ),
 
251
  'paras' => [
252
  __( "Adds fine control over user sessions, account re-use, password strength and expiration, and user suspension.", 'wp-simple-firewall' ),
253
  ],
360
 
361
  'integrations' => [
362
  'title' => __( '3rd Party Integrations', 'wp-simple-firewall' ),
 
363
  'img' => $con->urls->forImage( 'bootstrap/link-45deg.svg' ),
364
  'paras' => [
365
  __( "Shield integrates with 3rd party plugins and services.", 'wp-simple-firewall' ),
src/lib/src/Modules/Plugin/Lib/Debug/Collate.php CHANGED
@@ -218,15 +218,15 @@ class Collate {
218
  $licPing->lookup_url_stub = $con->getModule_License()->getOptions()->getDef( 'license_store_url_api' );
219
  $data[ 'Ping License Server' ] = $licPing->ping() ? 'Yes' : 'No';
220
 
221
- $data[ 'Write TMP/Cache DIR' ] = $con->hasCacheDir() ?'Yes: '.$con->getPluginCachePath() : 'No' ;
222
 
223
  return $data;
224
  }
225
 
226
  private function getShieldSummary() :array {
227
- $oCon = $this->getCon();
228
- $oModLicense = $oCon->getModule_License();
229
- $oModPlugin = $oCon->getModule_Plugin();
230
  $oWpHashes = $oModLicense->getWpHashesTokenManager();
231
 
232
  $nPrevAttempt = $oWpHashes->getPreviousAttemptAt();
@@ -241,10 +241,12 @@ class Collate {
241
  }
242
 
243
  $aD = [
244
- 'Version' => $oCon->getVersion(),
245
- 'PRO' => $oCon->isPremiumActive() ? 'Yes' : 'No',
246
  'WP Hashes Token' => ( $oWpHashes->hasToken() ? $oWpHashes->getToken() : '' ).' ('.$sPrev.')',
247
- 'Security Admin Enabled' => $oCon->getModule_SecAdmin()->isEnabledSecurityAdmin() ? 'Yes' : 'No',
 
 
248
  ];
249
 
250
  /** @var Options $oOptsIP */
218
  $licPing->lookup_url_stub = $con->getModule_License()->getOptions()->getDef( 'license_store_url_api' );
219
  $data[ 'Ping License Server' ] = $licPing->ping() ? 'Yes' : 'No';
220
 
221
+ $data[ 'Write TMP/Cache DIR' ] = $con->hasCacheDir() ? 'Yes: '.$con->getPluginCachePath() : 'No';
222
 
223
  return $data;
224
  }
225
 
226
  private function getShieldSummary() :array {
227
+ $con = $this->getCon();
228
+ $oModLicense = $con->getModule_License();
229
+ $oModPlugin = $con->getModule_Plugin();
230
  $oWpHashes = $oModLicense->getWpHashesTokenManager();
231
 
232
  $nPrevAttempt = $oWpHashes->getPreviousAttemptAt();
241
  }
242
 
243
  $aD = [
244
+ 'Version' => $con->getVersion(),
245
+ 'PRO' => $con->isPremiumActive() ? 'Yes' : 'No',
246
  'WP Hashes Token' => ( $oWpHashes->hasToken() ? $oWpHashes->getToken() : '' ).' ('.$sPrev.')',
247
+ 'Security Admin Enabled' => $con->getModule_SecAdmin()
248
+ ->getSecurityAdminController()
249
+ ->isEnabledSecAdmin() ? 'Yes' : 'No',
250
  ];
251
 
252
  /** @var Options $oOptsIP */
src/lib/src/Modules/Plugin/Lib/ImportExport/ImportExportController.php CHANGED
@@ -116,12 +116,6 @@ class ImportExportController {
116
  'vars' => [
117
  'file_upload_nonce' => $mod->getNonceActionData( 'import_file_upload' ),
118
  'form_action' => $mod->getUrl_AdminPage(),
119
- 'related_hrefs' => [
120
- [
121
- 'href' => $mod->getUrl_DirectLinkToSection( 'section_importexport' ),
122
- 'title' => __( 'Import/Export Settings', 'wp-simple-firewall' ),
123
- ]
124
- ]
125
  ],
126
  'ajax' => [
127
  'import_from_site' => $mod->getAjaxActionData( 'import_from_site', true ),
@@ -146,30 +140,28 @@ class ImportExportController {
146
  'title_download_file' => __( 'Download Options Export File', 'wp-simple-firewall' ),
147
  'subtitle_download_file' => __( 'Use this file to copy options from this site into another site', 'wp-simple-firewall' ),
148
 
149
- 'subtitle_import_site' => __( 'Import options directly from another site', 'wp-simple-firewall' ),
150
- 'master_site_url' => __( 'Master Site URL', 'wp-simple-firewall' ),
151
- 'remember_include' => sprintf(
152
  __( 'Remember to include %s or %s', 'wp-simple-firewall' ),
153
  '<code>https://</code>',
154
  '<code>http://</code>'
155
  ),
156
- 'secret_key' => __( 'Secret Key', 'wp-simple-firewall' ),
157
- 'master_site_key' => __( 'Master Site Secret Key', 'wp-simple-firewall' ),
158
- 'create_network' => __( 'Create Shield Network', 'wp-simple-firewall' ),
159
- 'key_found_under' => sprintf( __( 'The secret key is found in: %s', 'wp-simple-firewall' ),
160
  ucwords( sprintf( '%s > %s > %s ', __( 'General Settings', 'wp-simple-firewall' ), __( 'Import/Export', 'wp-simple-firewall' ), __( 'Secret Key', 'wp-simple-firewall' ) ) )
161
  ),
162
- 'turn_on' => __( 'Turn On', 'wp-simple-firewall' ),
163
- 'turn_off' => __( 'Turn Off', 'wp-simple-firewall' ),
164
- 'no_change' => __( 'No Change', 'wp-simple-firewall' ),
165
- 'network_explain' => [
166
  __( 'Checking this option on will link this site to Master site.', 'wp-simple-firewall' ),
167
  __( 'Options will be automatically imported from the Master site each night', 'wp-simple-firewall' ),
168
  __( 'When you adjust options on the Master site, they will be reflected in this site after the automatic import', 'wp-simple-firewall' ),
169
  ],
170
- 'import_options' => __( 'Import Options', 'wp-simple-firewall' ),
171
- 'downloading_please_wait' => __( 'Downloading file, please wait...', 'wp-simple-firewall' ),
172
- 'problem_downloading_file' => __( 'There was a problem downloading the file.', 'wp-simple-firewall' ),
173
  ]
174
  ];
175
  }
116
  'vars' => [
117
  'file_upload_nonce' => $mod->getNonceActionData( 'import_file_upload' ),
118
  'form_action' => $mod->getUrl_AdminPage(),
 
 
 
 
 
 
119
  ],
120
  'ajax' => [
121
  'import_from_site' => $mod->getAjaxActionData( 'import_from_site', true ),
140
  'title_download_file' => __( 'Download Options Export File', 'wp-simple-firewall' ),
141
  'subtitle_download_file' => __( 'Use this file to copy options from this site into another site', 'wp-simple-firewall' ),
142
 
143
+ 'subtitle_import_site' => __( 'Import options directly from another site', 'wp-simple-firewall' ),
144
+ 'master_site_url' => __( 'Master Site URL', 'wp-simple-firewall' ),
145
+ 'remember_include' => sprintf(
146
  __( 'Remember to include %s or %s', 'wp-simple-firewall' ),
147
  '<code>https://</code>',
148
  '<code>http://</code>'
149
  ),
150
+ 'secret_key' => __( 'Secret Key', 'wp-simple-firewall' ),
151
+ 'master_site_key' => __( 'Master Site Secret Key', 'wp-simple-firewall' ),
152
+ 'create_network' => __( 'Create Shield Network', 'wp-simple-firewall' ),
153
+ 'key_found_under' => sprintf( __( 'The secret key is found in: %s', 'wp-simple-firewall' ),
154
  ucwords( sprintf( '%s > %s > %s ', __( 'General Settings', 'wp-simple-firewall' ), __( 'Import/Export', 'wp-simple-firewall' ), __( 'Secret Key', 'wp-simple-firewall' ) ) )
155
  ),
156
+ 'turn_on' => __( 'Turn On', 'wp-simple-firewall' ),
157
+ 'turn_off' => __( 'Turn Off', 'wp-simple-firewall' ),
158
+ 'no_change' => __( 'No Change', 'wp-simple-firewall' ),
159
+ 'network_explain' => [
160
  __( 'Checking this option on will link this site to Master site.', 'wp-simple-firewall' ),
161
  __( 'Options will be automatically imported from the Master site each night', 'wp-simple-firewall' ),
162
  __( 'When you adjust options on the Master site, they will be reflected in this site after the automatic import', 'wp-simple-firewall' ),
163
  ],
164
+ 'import_options' => __( 'Import Options', 'wp-simple-firewall' ),
 
 
165
  ]
166
  ];
167
  }
src/lib/src/Modules/Plugin/Lib/ImportExport/Options/BuildTransferableOptions.php CHANGED
@@ -12,11 +12,11 @@ class BuildTransferableOptions {
12
  * @return mixed[]
13
  */
14
  public function build() {
15
- $oOpts = $this->getOptions();
16
  return array_merge(
17
- array_fill_keys( $oOpts->getOptionsKeys(), false ),
18
- array_fill_keys( array_keys( $oOpts->getTransferableOptions() ), 'Y' ),
19
- array_fill_keys( $oOpts->getXferExcluded(), 'N' )
20
  );
21
  }
22
  }
12
  * @return mixed[]
13
  */
14
  public function build() {
15
+ $opts = $this->getOptions();
16
  return array_merge(
17
+ array_fill_keys( $opts->getOptionsKeys(), false ),
18
+ array_fill_keys( array_keys( $opts->getTransferableOptions() ), 'Y' ),
19
+ array_fill_keys( $opts->getXferExcluded(), 'N' )
20
  );
21
  }
22
  }
src/lib/src/Modules/Plugin/Lib/ImportExport/Options/SaveExcludedOptions.php CHANGED
@@ -11,16 +11,16 @@ class SaveExcludedOptions {
11
  /**
12
  * Takes a form submission and if the checkbox isn't checked for a given option,
13
  * it means we are to exclude that option from imports/exports.
14
- * @param string[] $aFormSubmission
15
  */
16
- public function save( $aFormSubmission ) {
17
- $oOpts = $this->getOptions();
18
  $aExcluded = [];
19
- foreach ( array_keys( $oOpts->getTransferableOptions() ) as $sOptKey ) {
20
- if ( empty( $aFormSubmission[ 'optxfer-'.$sOptKey ] ) ) {
21
  $aExcluded[] = $sOptKey;
22
  }
23
  }
24
- $oOpts->setOpt( 'xfer_excluded', $aExcluded );
25
  }
26
  }
11
  /**
12
  * Takes a form submission and if the checkbox isn't checked for a given option,
13
  * it means we are to exclude that option from imports/exports.
14
+ * @param string[] $formSubmission
15
  */
16
+ public function save( $formSubmission ) {
17
+ $opts = $this->getOptions();
18
  $aExcluded = [];
19
+ foreach ( array_keys( $opts->getTransferableOptions() ) as $sOptKey ) {
20
+ if ( empty( $formSubmission[ 'optxfer-'.$sOptKey ] ) ) {
21
  $aExcluded[] = $sOptKey;
22
  }
23
  }
24
+ $opts->setOpt( 'xfer_excluded', $aExcluded );
25
  }
26
  }
src/lib/src/Modules/Plugin/Lib/TourManager.php CHANGED
@@ -15,7 +15,8 @@ class TourManager {
15
 
16
  public function getAllTours() :array {
17
  return [
18
- 'dashboard_v1'
 
19
  ];
20
  }
21
 
15
 
16
  public function getAllTours() :array {
17
  return [
18
+ 'dashboard_v1',
19
+ 'navigation_v1',
20
  ];
21
  }
22
 
src/lib/src/Modules/Plugin/ModCon.php CHANGED
@@ -489,26 +489,8 @@ class ModCon extends BaseShield\ModCon {
489
  }
490
 
491
  public function getScriptLocalisations() :array {
492
- $con = $this->getCon();
493
  $locals = parent::getScriptLocalisations();
494
 
495
- if ( Services::WpPost()->isCurrentPage( 'plugins.php' ) ) {
496
- $file = $con->base_file;
497
- $locals[] = [
498
- 'global-plugin',
499
- 'icwp_wpsf_vars_plugin',
500
- [
501
- 'file' => $file,
502
- 'ajax' => [
503
- 'send_deactivate_survey' => $this->getAjaxActionData( 'send_deactivate_survey' ),
504
- ],
505
- 'hrefs' => [
506
- 'deactivate' => Services::WpPlugins()->getUrl_Deactivate( $file ),
507
- ],
508
- ]
509
- ];
510
- }
511
-
512
  $tourManager = $this->getTourManager();
513
  $locals[] = [
514
  'shield/tours',
@@ -526,7 +508,7 @@ class ModCon extends BaseShield\ModCon {
526
  [
527
  'strings' => [
528
  'downloading_file' => __( 'Downloading file, please wait...', 'wp-simple-firewall' ),
529
- 'problem_downloading_file' => __( 'There was a problem downloading the file.', 'wp-simple-firewall' ),
530
  ],
531
  ]
532
  ];
@@ -565,11 +547,4 @@ class ModCon extends BaseShield\ModCon {
565
  protected function getNamespaceBase() :string {
566
  return 'Plugin';
567
  }
568
-
569
- /**
570
- * @return string
571
- */
572
- public function getSurveyEmail() {
573
- return base64_decode( $this->getDef( 'survey_email' ) );
574
- }
575
  }
489
  }
490
 
491
  public function getScriptLocalisations() :array {
 
492
  $locals = parent::getScriptLocalisations();
493
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
494
  $tourManager = $this->getTourManager();
495
  $locals[] = [
496
  'shield/tours',
508
  [
509
  'strings' => [
510
  'downloading_file' => __( 'Downloading file, please wait...', 'wp-simple-firewall' ),
511
+ 'downloading_file_problem' => __( 'There was a problem downloading the file.', 'wp-simple-firewall' ),
512
  ],
513
  ]
514
  ];
547
  protected function getNamespaceBase() :string {
548
  return 'Plugin';
549
  }
 
 
 
 
 
 
 
550
  }
src/lib/src/Modules/Plugin/Strings.php CHANGED
@@ -196,18 +196,22 @@ class Strings extends Base\Strings {
196
  case 'visitor_address_source' :
197
  $name = __( 'IP Source', 'wp-simple-firewall' );
198
  $summary = __( 'Which IP Address Is Yours', 'wp-simple-firewall' );
199
- $desc = __( 'There are many possible ways to detect visitor IP addresses. If Auto-Detect is not working, please select yours from the list.', 'wp-simple-firewall' )
200
- .'<br />'.__( 'If the option you select becomes unavailable, we will revert to auto detection.', 'wp-simple-firewall' )
201
- .'<br />'.sprintf(
202
- __( 'Current source is: %s (%s)', 'wp-simple-firewall' ),
203
- '<strong>'.$opts->getIpSource().'</strong>',
204
- Services::IP()->getRequestIp()
205
- )
206
- .sprintf(
207
- '<p class="mt-2"><a href="%s" target="_blank">%s</a></p>',
208
- 'https://shsec.io/shieldwhatismyip',
209
- __( 'What Is My IP Address?', 'wp-simple-firewall' )
210
- );
 
 
 
 
211
  break;
212
 
213
  case 'block_send_email_address' :
196
  case 'visitor_address_source' :
197
  $name = __( 'IP Source', 'wp-simple-firewall' );
198
  $summary = __( 'Which IP Address Is Yours', 'wp-simple-firewall' );
199
+ $desc = [
200
+ __( "Knowing the real IP address of your visitors is critical to your security, but many hosts aren't configured correctly to let us find it easily.", 'wp-simple-firewall' ),
201
+ __( 'There are many possible ways to detect visitor IP addresses. If Auto-Detect is not working, please select yours from the list.', 'wp-simple-firewall' ),
202
+ __( 'Use the link below to find your correct IP address, then select the option on the list.', 'wp-simple-firewall' ),
203
+ sprintf(
204
+ '<p class="mt-2"><a href="%s" target="_blank">%s</a></p>',
205
+ 'https://shsec.io/shieldwhatismyip',
206
+ __( 'What Is My IP Address?', 'wp-simple-firewall' )
207
+ ),
208
+ sprintf(
209
+ __( 'Current source is: %s (%s)', 'wp-simple-firewall' ),
210
+ '<strong>'.$opts->getIpSource().'</strong>',
211
+ Services::IP()->getRequestIp()
212
+ ),
213
+ __( 'If the option you select becomes unavailable at some point, we will revert to auto detection.', 'wp-simple-firewall' ),
214
+ ];
215
  break;
216
 
217
  case 'block_send_email_address' :
src/lib/src/Modules/Plugin/UI.php CHANGED
@@ -45,19 +45,20 @@ class UI extends BaseShield\UI {
45
  protected function buildOptionForUi( $aOptParams ) {
46
  $aOptParams = parent::buildOptionForUi( $aOptParams );
47
  if ( $aOptParams[ 'key' ] === 'visitor_address_source' ) {
48
- $aNewOptions = [];
49
- $oIPDet = Services::IP()->getIpDetector();
50
- foreach ( $aOptParams[ 'value_options' ] as $sValKey => $sSource ) {
51
- if ( $sValKey == 'AUTO_DETECT_IP' ) {
52
- $aNewOptions[ $sValKey ] = $sSource;
53
  }
54
  else {
55
- $sIPs = implode( ', ', $oIPDet->getIpsFromSource( $sSource ) );
56
- $aNewOptions[ $sValKey ] = sprintf( '%s (%s)',
57
- $sSource, empty( $sIPs ) ? '-' : $sIPs );
 
58
  }
59
  }
60
- $aOptParams[ 'value_options' ] = $aNewOptions;
61
  }
62
  return $aOptParams;
63
  }
@@ -88,14 +89,4 @@ class UI extends BaseShield\UI {
88
 
89
  return $warnings;
90
  }
91
-
92
- protected function getSettingsRelatedLinks() :array {
93
- $modInsights = $this->getCon()->getModule_Insights();
94
- return [
95
- [
96
- 'href' => $modInsights->getUrl_SubInsightsPage( 'importexport' ),
97
- 'title' => __( 'Run Import/Export', 'wp-simple-firewall' ),
98
- ]
99
- ];
100
- }
101
  }
45
  protected function buildOptionForUi( $aOptParams ) {
46
  $aOptParams = parent::buildOptionForUi( $aOptParams );
47
  if ( $aOptParams[ 'key' ] === 'visitor_address_source' ) {
48
+ $newOptions = [];
49
+ $ipDetector = Services::IP()->getIpDetector();
50
+ foreach ( $aOptParams[ 'value_options' ] as $valKey => $source ) {
51
+ if ( $valKey == 'AUTO_DETECT_IP' ) {
52
+ $newOptions[ $valKey ] = $source;
53
  }
54
  else {
55
+ $IPs = implode( ', ', $ipDetector->getIpsFromSource( $source ) );
56
+ if ( !empty( $IPs ) ) {
57
+ $newOptions[ $valKey ] = sprintf( '%s (%s)', $source, $IPs );
58
+ }
59
  }
60
  }
61
+ $aOptParams[ 'value_options' ] = $newOptions;
62
  }
63
  return $aOptParams;
64
  }
89
 
90
  return $warnings;
91
  }
 
 
 
 
 
 
 
 
 
 
92
  }
src/lib/src/Modules/Reporting/AjaxHandler.php CHANGED
@@ -3,6 +3,7 @@
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Reporting;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield;
 
6
 
7
  class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
8
 
@@ -25,7 +26,7 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
25
  }
26
 
27
  private function ajaxExec_RenderCustomChart() :array {
28
- return $this->renderChart( $this->getAjaxFormParams() );
29
  }
30
 
31
  private function ajaxExec_RenderSummaryChart() :array {
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Reporting;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Request\FormParams;
7
 
8
  class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
9
 
26
  }
27
 
28
  private function ajaxExec_RenderCustomChart() :array {
29
+ return $this->renderChart( FormParams::Retrieve() );
30
  }
31
 
32
  private function ajaxExec_RenderSummaryChart() :array {
src/lib/src/Modules/Reporting/Lib/ReportingController.php CHANGED
@@ -66,7 +66,7 @@ class ReportingController {
66
  * @param Modules\Reporting\Lib\Reports\ReportVO $report
67
  * @return bool
68
  */
69
- private function storeReportRecord( Reports\ReportVO $report ) {
70
  $record = new DBReports\EntryVO();
71
  $record->sent_at = Services::Request()->ts();
72
  $record->rid = $report->rid;
@@ -82,10 +82,9 @@ class ReportingController {
82
  }
83
 
84
  /**
85
- * @return Modules\Reporting\Lib\Reports\ReportVO
86
  * @throws \Exception
87
  */
88
- private function buildReportAlerts() {
89
  $report = ( new Reports\CreateReportVO( DBReports\Handler::TYPE_ALERT ) )
90
  ->setMod( $this->getMod() )
91
  ->create();
@@ -96,10 +95,9 @@ class ReportingController {
96
  }
97
 
98
  /**
99
- * @return Modules\Reporting\Lib\Reports\ReportVO
100
  * @throws \Exception
101
  */
102
- private function buildReportInfo() {
103
  $report = ( new Reports\CreateReportVO( DBReports\Handler::TYPE_INFO ) )
104
  ->setMod( $this->getMod() )
105
  ->create();
@@ -110,7 +108,7 @@ class ReportingController {
110
  }
111
 
112
  /**
113
- * @param Modules\Reporting\Lib\Reports\ReportVO[] $reportVOs
114
  */
115
  private function sendEmail( array $reportVOs ) {
116
 
66
  * @param Modules\Reporting\Lib\Reports\ReportVO $report
67
  * @return bool
68
  */
69
+ private function storeReportRecord( Reports\ReportVO $report ) :bool {
70
  $record = new DBReports\EntryVO();
71
  $record->sent_at = Services::Request()->ts();
72
  $record->rid = $report->rid;
82
  }
83
 
84
  /**
 
85
  * @throws \Exception
86
  */
87
+ private function buildReportAlerts() :Reports\ReportVO {
88
  $report = ( new Reports\CreateReportVO( DBReports\Handler::TYPE_ALERT ) )
89
  ->setMod( $this->getMod() )
90
  ->create();
95
  }
96
 
97
  /**
 
98
  * @throws \Exception
99
  */
100
+ private function buildReportInfo() :Reports\ReportVO {
101
  $report = ( new Reports\CreateReportVO( DBReports\Handler::TYPE_INFO ) )
102
  ->setMod( $this->getMod() )
103
  ->create();
108
  }
109
 
110
  /**
111
+ * @param Reports\ReportVO[] $reportVOs
112
  */
113
  private function sendEmail( array $reportVOs ) {
114
 
src/lib/src/Modules/Reporting/Lib/Reports/CreateReportVO.php CHANGED
@@ -16,9 +16,6 @@ class CreateReportVO {
16
  */
17
  private $rep;
18
 
19
- /**
20
- * @param string $reportType
21
- */
22
  public function __construct( string $reportType ) {
23
  $this->rep = new ReportVO();
24
  $this->rep->type = $reportType;
@@ -28,7 +25,7 @@ class CreateReportVO {
28
  * @return ReportVO
29
  * @throws \Exception
30
  */
31
- public function create() {
32
  $this->setReportInterval()
33
  ->setPreviousReport()
34
  ->setIntervalBoundaries()
@@ -82,37 +79,38 @@ class CreateReportVO {
82
  private function setIntervalBoundaries() {
83
 
84
  $carbon = Services::Request()->carbon( true );
85
- $nAddition = -1; // the previous hour, day, week, month
86
 
87
  switch ( $this->rep->interval ) {
88
  // case 'realtime':
89
  // break;
90
- case 'no_time': // TODO
91
  $start = 0;
92
  $end = $carbon->timestamp;
93
  break;
94
  case 'hourly':
95
- $carbon->addHours( $nAddition );
96
  $start = $carbon->startOfHour()->timestamp;
97
  $end = $carbon->endOfHour()->timestamp;
98
  break;
99
  case 'daily':
100
- $carbon->addDays( $nAddition );
101
  $start = $carbon->startOfDay()->timestamp;
102
  $end = $carbon->endOfDay()->timestamp;
103
  break;
104
  case 'weekly':
105
- $carbon->addWeeks( $nAddition );
106
  $start = $carbon->startOfWeek()->timestamp;
107
  $end = $carbon->endOfWeek()->timestamp;
108
  break;
109
  case 'monthly':
110
- $carbon->addMonths( $nAddition );
 
111
  $start = $carbon->startOfMonth()->timestamp;
112
  $end = $carbon->endOfMonth()->timestamp;
113
  break;
114
  case 'yearly':
115
- $carbon->addYears( $nAddition );
116
  $start = $carbon->startOfYear()->timestamp;
117
  $end = $carbon->endOfYear()->timestamp;
118
  break;
@@ -138,10 +136,10 @@ class CreateReportVO {
138
  private function setReportId() {
139
  /** @var Reporting\ModCon $mod */
140
  $mod = $this->getMod();
141
- /** @var Reports\Select $oSel */
142
- $oSel = $mod->getDbHandler_Reports()->getQuerySelector();
143
- $nPrevID = $oSel->getLastReportId();
144
- $this->rep->rid = is_numeric( $nPrevID ) ? $nPrevID + 1 : 1;
145
  return $this;
146
  }
147
 
16
  */
17
  private $rep;
18
 
 
 
 
19
  public function __construct( string $reportType ) {
20
  $this->rep = new ReportVO();
21
  $this->rep->type = $reportType;
25
  * @return ReportVO
26
  * @throws \Exception
27
  */
28
+ public function create() :ReportVO {
29
  $this->setReportInterval()
30
  ->setPreviousReport()
31
  ->setIntervalBoundaries()
79
  private function setIntervalBoundaries() {
80
 
81
  $carbon = Services::Request()->carbon( true );
82
+ $addition = -1; // the previous hour, day, week, month
83
 
84
  switch ( $this->rep->interval ) {
85
  // case 'realtime':
86
  // break;
87
+ case 'lifetime': // TODO
88
  $start = 0;
89
  $end = $carbon->timestamp;
90
  break;
91
  case 'hourly':
92
+ $carbon->addHours( $addition );
93
  $start = $carbon->startOfHour()->timestamp;
94
  $end = $carbon->endOfHour()->timestamp;
95
  break;
96
  case 'daily':
97
+ $carbon->addDays( $addition );
98
  $start = $carbon->startOfDay()->timestamp;
99
  $end = $carbon->endOfDay()->timestamp;
100
  break;
101
  case 'weekly':
102
+ $carbon->addWeeks( $addition );
103
  $start = $carbon->startOfWeek()->timestamp;
104
  $end = $carbon->endOfWeek()->timestamp;
105
  break;
106
  case 'monthly':
107
+ $carbon->day( 15 );
108
+ $carbon->addMonths( $addition );
109
  $start = $carbon->startOfMonth()->timestamp;
110
  $end = $carbon->endOfMonth()->timestamp;
111
  break;
112
  case 'yearly':
113
+ $carbon->addYears( $addition );
114
  $start = $carbon->startOfYear()->timestamp;
115
  $end = $carbon->endOfYear()->timestamp;
116
  break;
136
  private function setReportId() {
137
  /** @var Reporting\ModCon $mod */
138
  $mod = $this->getMod();
139
+ /** @var Reports\Select $select */
140
+ $select = $mod->getDbHandler_Reports()->getQuerySelector();
141
+ $prevID = $select->getLastReportId();
142
+ $this->rep->rid = is_numeric( $prevID ) ? $prevID + 1 : 1;
143
  return $this;
144
  }
145
 
src/lib/src/Modules/Reporting/Options.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Reporting;
4
 
1
+ <?php declare( strict_types=1 );
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Reporting;
4
 
src/lib/src/Modules/SecurityAdmin/AjaxHandler.php CHANGED
@@ -37,28 +37,23 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
37
  private function ajaxExec_SecAdminCheck() :array {
38
  /** @var ModCon $mod */
39
  $mod = $this->getMod();
 
40
  return [
41
- 'timeleft' => $mod->getSecAdminTimeLeft(),
42
- 'success' => $mod->isSecAdminSessionValid()
43
  ];
44
  }
45
 
46
  private function ajaxExec_SecAdminLogin() :array {
47
  /** @var ModCon $mod */
48
  $mod = $this->getMod();
49
- $success = false;
50
- $html = '';
51
 
52
- if ( $mod->testSecAccessKeyRequest() ) {
 
53
 
54
- if ( $mod->setSecurityAdminStatusOnOff( true ) ) {
55
- $success = true;
56
- $msg = __( 'Security Admin PIN Accepted.', 'wp-simple-firewall' )
57
- .' '.__( 'Please wait', 'wp-simple-firewall' ).' ...';
58
- }
59
- else {
60
- $msg = __( 'Failed to process key - you may need to re-login to WordPress.', 'wp-simple-firewall' );
61
- }
62
  }
63
  else {
64
  $remaining = ( new Shield\Modules\IPs\Components\QueryRemainingOffenses() )
@@ -91,7 +86,7 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
91
  }
92
 
93
  private function ajaxExec_SendEmailRemove() :array {
94
- ( new Shield\Modules\SecurityAdmin\Lib\Actions\RemoveSecAdmin() )
95
  ->setMod( $this->getMod() )
96
  ->sendConfirmationEmail();
97
  return [
37
  private function ajaxExec_SecAdminCheck() :array {
38
  /** @var ModCon $mod */
39
  $mod = $this->getMod();
40
+ $secAdminCon = $mod->getSecurityAdminController();
41
  return [
42
+ 'time_remaining' => $secAdminCon->getSecAdminTimeRemaining(),
43
+ 'success' => $secAdminCon->isCurrentlySecAdmin()
44
  ];
45
  }
46
 
47
  private function ajaxExec_SecAdminLogin() :array {
48
  /** @var ModCon $mod */
49
  $mod = $this->getMod();
 
 
50
 
51
+ $success = $mod->getSecurityAdminController()->verifyPinRequest();
52
+ $html = '';
53
 
54
+ if ( $success ) {
55
+ $msg = __( 'Security Admin PIN Accepted.', 'wp-simple-firewall' )
56
+ .' '.__( 'Please wait', 'wp-simple-firewall' ).' ...';
 
 
 
 
 
57
  }
58
  else {
59
  $remaining = ( new Shield\Modules\IPs\Components\QueryRemainingOffenses() )
86
  }
87
 
88
  private function ajaxExec_SendEmailRemove() :array {
89
+ ( new Lib\SecurityAdmin\Ops\RemoveSecAdmin() )
90
  ->setMod( $this->getMod() )
91
  ->sendConfirmationEmail();
92
  return [
src/lib/src/Modules/SecurityAdmin/Insights/OverviewCards.php CHANGED
@@ -21,8 +21,8 @@ class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
21
 
22
  $cards = [];
23
 
24
- $bEnabled = $mod->isModuleEnabled() && $mod->isEnabledSecurityAdmin();
25
- if ( !$bEnabled ) {
26
  $cards[ 'mod' ] = [
27
  'name' => __( 'Security Admin', 'wp-simple-firewall' ),
28
  'state' => -1,
@@ -38,11 +38,11 @@ class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
38
  'href' => $mod->getUrl_DirectLinkToOption( 'admin_access_key' ),
39
  ];
40
 
41
- $bWpOpts = $opts->getAdminAccessArea_Options();
42
  $cards[ 'wpopts' ] = [
43
  'name' => __( 'Important Options', 'wp-simple-firewall' ),
44
- 'state' => $bWpOpts ? 1 : -1,
45
- 'summary' => $bWpOpts ?
46
  __( 'Important WP options are protected against tampering', 'wp-simple-firewall' )
47
  : __( "Important WP options aren't protected against tampering", 'wp-simple-firewall' ),
48
  'href' => $mod->getUrl_DirectLinkToOption( 'admin_access_restrict_options' ),
21
 
22
  $cards = [];
23
 
24
+ $enabled = $mod->getSecurityAdminController()->isEnabledSecAdmin();
25
+ if ( !$enabled ) {
26
  $cards[ 'mod' ] = [
27
  'name' => __( 'Security Admin', 'wp-simple-firewall' ),
28
  'state' => -1,
38
  'href' => $mod->getUrl_DirectLinkToOption( 'admin_access_key' ),
39
  ];
40
 
41
+ $isWPOptsRestricted = $opts->getAdminAccessArea_Options();
42
  $cards[ 'wpopts' ] = [
43
  'name' => __( 'Important Options', 'wp-simple-firewall' ),
44
+ 'state' => $isWPOptsRestricted ? 1 : -1,
45
+ 'summary' => $isWPOptsRestricted ?
46
  __( 'Important WP options are protected against tampering', 'wp-simple-firewall' )
47
  : __( "Important WP options aren't protected against tampering", 'wp-simple-firewall' ),
48
  'href' => $mod->getUrl_DirectLinkToOption( 'admin_access_restrict_options' ),
src/lib/src/Modules/SecurityAdmin/Lib/{Actions → SecurityAdmin/Ops}/RemoveSecAdmin.php RENAMED
@@ -1,6 +1,6 @@
1
  <?php
2
 
3
- namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Lib\Actions;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin;
@@ -40,7 +40,7 @@ class RemoveSecAdmin {
40
  sprintf( '%s: %s', __( 'Confirmation link', 'wp-simple-firewall' ),
41
  $mod->buildAdminActionNonceUrl( 'remove_secadmin_confirm' ) ),
42
  '',
43
- __( "Please understand that to reinstate the Security Admin features, you'll need to provide a new Security Admin password.", 'wp-simple-firewall' ),
44
  '',
45
  __( "Thank you.", 'wp-simple-firewall' )
46
  ]
@@ -58,7 +58,7 @@ class RemoveSecAdmin {
58
  __( 'This was done using a confirmation email sent to the Security Administrator email address.', 'wp-simple-firewall' ),
59
  __( 'All restrictions imposed by the Security Admin module have been lifted.', 'wp-simple-firewall' ),
60
  '',
61
- __( "Please understand that to reinstate the Security Admin features, you'll need to provide a new Security Admin password.", 'wp-simple-firewall' ),
62
  '',
63
  __( "Thank you.", 'wp-simple-firewall' )
64
  ]
1
  <?php
2
 
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Lib\SecurityAdmin\Ops;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin;
40
  sprintf( '%s: %s', __( 'Confirmation link', 'wp-simple-firewall' ),
41
  $mod->buildAdminActionNonceUrl( 'remove_secadmin_confirm' ) ),
42
  '',
43
+ __( "Please understand that to reinstate the Security Admin features, you'll need to provide a new Security Admin PIN.", 'wp-simple-firewall' ),
44
  '',
45
  __( "Thank you.", 'wp-simple-firewall' )
46
  ]
58
  __( 'This was done using a confirmation email sent to the Security Administrator email address.', 'wp-simple-firewall' ),
59
  __( 'All restrictions imposed by the Security Admin module have been lifted.', 'wp-simple-firewall' ),
60
  '',
61
+ __( "Please understand that to reinstate the Security Admin features, you'll need to provide a new Security Admin PIN.", 'wp-simple-firewall' ),
62
  '',
63
  __( "Thank you.", 'wp-simple-firewall' )
64
  ]
src/lib/src/Modules/SecurityAdmin/Lib/{Actions → SecurityAdmin/Ops}/SetSecAdminPin.php RENAMED
@@ -1,6 +1,6 @@
1
  <?php
2
 
3
- namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Lib\Actions;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
 
1
  <?php
2
 
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Lib\SecurityAdmin\Ops;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
 
src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Ops/ToggleSecAdminStatus.php ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Lib\SecurityAdmin\Ops;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Databases\Session\EntryVO;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Databases\Session\Update;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
8
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\ModCon;
9
+
10
+ class ToggleSecAdminStatus {
11
+
12
+ use ModConsumer;
13
+
14
+ public function turnOn() :bool {
15
+ try {
16
+ $success = $this->toggle( true );
17
+ }
18
+ catch ( \Exception $e ) {
19
+ $success = false;
20
+ }
21
+ return $success;
22
+ }
23
+
24
+ public function turnOff() :bool {
25
+ try {
26
+ $success = $this->toggle( false );
27
+ }
28
+ catch ( \Exception $e ) {
29
+ $success = false;
30
+ }
31
+ return $success;
32
+ }
33
+
34
+ /**
35
+ * @param bool $onOrOff
36
+ * @return bool
37
+ * @throws \Exception
38
+ */
39
+ private function toggle( bool $onOrOff ) :bool {
40
+ /** @var ModCon $mod */
41
+ $mod = $this->getMod();
42
+ $session = $this->getMod()->getSession();
43
+ if ( !$session instanceof EntryVO ) {
44
+ throw new \Exception( 'No session' );
45
+ }
46
+ /** @var Update $updater */
47
+ $updater = $mod->getDbHandler_Sessions()->getQueryUpdater();
48
+ return $onOrOff ? $updater->startSecurityAdmin( $session ) : $updater->terminateSecurityAdmin( $session );
49
+ }
50
+ }
src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Ops/VerifyPinRequest.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Lib\SecurityAdmin\Ops;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Options;
7
+ use FernleafSystems\Wordpress\Services\Services;
8
+
9
+ class VerifyPinRequest {
10
+
11
+ use ModConsumer;
12
+
13
+ public function run( string $pin = null ) :bool {
14
+ $valid = false;
15
+
16
+ if ( empty( $pin ) ) {
17
+ $pin = Services::Request()->post( 'sec_admin_key' );
18
+ }
19
+
20
+ if ( !empty( $pin ) ) {
21
+ /** @var Options $opts */
22
+ $opts = $this->getOptions();
23
+ $valid = hash_equals( $opts->getSecurityPIN(), md5( $pin ) );
24
+ $this->getCon()->fireEvent( $valid ? 'key_success' : 'key_fail' );
25
+
26
+ $valid = $valid && ( new ToggleSecAdminStatus() )
27
+ ->setMod( $this->getMod() )
28
+ ->turnOn();
29
+ }
30
+
31
+ return $valid;
32
+ }
33
+ }
src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/Base.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Lib\SecurityAdmin\Restrictions;
4
+
5
+ use FernleafSystems\Utilities\Logic\ExecOnce;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
+
8
+ class Base {
9
+
10
+ use ExecOnce;
11
+ use ModConsumer;
12
+ }
src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/BaseCapabilitiesRestrict.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Lib\SecurityAdmin\Restrictions;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Options;
6
+
7
+ class BaseCapabilitiesRestrict extends Base {
8
+
9
+ const AREA_SLUG = '';
10
+
11
+ protected function canRun() :bool {
12
+ return $this->hasRestrictedCapabilities();
13
+ }
14
+
15
+ protected function run() {
16
+ add_filter( 'user_has_cap', [ $this, 'removeCapabilities' ], 0, 3 );
17
+ }
18
+
19
+ /**
20
+ * @param array $allCaps
21
+ * @param $cap
22
+ * @param array $args
23
+ * @return array
24
+ */
25
+ public function removeCapabilities( $allCaps, $cap, $args ) {
26
+ /** @var string $requestedCap */
27
+ $requestedCap = $args[ 0 ];
28
+
29
+ if ( is_string( $requestedCap ) && $this->isCapabilityToBeRestricted( $requestedCap ) ) {
30
+ $allCaps[ $requestedCap ] = false;
31
+ }
32
+
33
+ return $allCaps;
34
+ }
35
+
36
+ protected function getApplicableCapabilities() :array {
37
+ return [];
38
+ }
39
+
40
+ protected function getRestrictedCapabilities() :array {
41
+ /** @var WpOptions $opts */
42
+ $opts = $this->getOptions();
43
+ return $opts->getSecAdminAreaCaps( static::AREA_SLUG );
44
+ }
45
+
46
+ protected function isCapabilityToBeRestricted( string $cap ) :bool {
47
+ return in_array( $cap, $this->getApplicableCapabilities() )
48
+ && in_array( $cap, $this->getRestrictedCapabilities() );
49
+ }
50
+
51
+ protected function hasRestrictedCapabilities() :bool {
52
+ return !empty( $this->getRestrictedCapabilities() );
53
+ }
54
+ }
src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/Plugins.php ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Lib\SecurityAdmin\Restrictions;
4
+
5
+ use FernleafSystems\Wordpress\Services\Services;
6
+
7
+ class Plugins extends BaseCapabilitiesRestrict {
8
+
9
+ const AREA_SLUG = 'plugins';
10
+
11
+ /**
12
+ * @param array $allCaps
13
+ * @param $cap
14
+ * @param array $args
15
+ * @return array
16
+ */
17
+ public function removeCapabilities( $allCaps, $cap, $args ) {
18
+ $req = Services::Request();
19
+
20
+ /** @var string $requestedCap */
21
+ $requestedCap = $args[ 0 ];
22
+
23
+ // special case for plugin info thickbox for changelog
24
+ $isChangelog = defined( 'IFRAME_REQUEST' )
25
+ && ( $requestedCap === 'install_plugins' )
26
+ && ( $req->query( 'section' ) == 'changelog' )
27
+ && $req->query( 'plugin' );
28
+
29
+ if ( !$isChangelog && is_string( $requestedCap ) && $this->isCapabilityToBeRestricted( $requestedCap ) ) {
30
+ $allCaps[ $requestedCap ] = false;
31
+ }
32
+
33
+ return $allCaps;
34
+ }
35
+
36
+ protected function getApplicableCapabilities() :array {
37
+ return [
38
+ 'activate_plugins',
39
+ 'delete_plugins',
40
+ 'install_plugins',
41
+ 'update_plugins'
42
+ ];
43
+ }
44
+ }
src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/Posts.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Lib\SecurityAdmin\Restrictions;
4
+
5
+ class Posts extends BaseCapabilitiesRestrict {
6
+
7
+ const AREA_SLUG = 'posts';
8
+
9
+ protected function isCapabilityToBeRestricted( string $cap ) :bool {
10
+ return in_array( $cap, $this->getApplicableCapabilities() )
11
+ && in_array(
12
+ str_replace( [
13
+ '_posts',
14
+ '_pages',
15
+ '_post',
16
+ '_page'
17
+ ], '', $cap ), //Order of items in this array is important!
18
+ $this->getRestrictedCapabilities()
19
+ );
20
+ }
21
+
22
+ protected function getApplicableCapabilities() :array {
23
+ return [
24
+ 'edit_post',
25
+ 'publish_post',
26
+ 'delete_post',
27
+ 'edit_posts',
28
+ 'publish_posts',
29
+ 'delete_posts',
30
+ 'edit_page',
31
+ 'publish_page',
32
+ 'delete_page',
33
+ 'edit_pages',
34
+ 'publish_pages',
35
+ 'delete_pages'
36
+ ];
37
+ }
38
+ }
src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/Themes.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Lib\SecurityAdmin\Restrictions;
4
+
5
+ class Themes extends BaseCapabilitiesRestrict {
6
+
7
+ const AREA_SLUG = 'themes';
8
+
9
+ protected function getApplicableCapabilities() :array {
10
+ return [
11
+ 'switch_themes',
12
+ 'edit_theme_options',
13
+ 'install_themes',
14
+ 'update_themes',
15
+ 'delete_themes'
16
+ ];
17
+ }
18
+ }
src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/Users.php ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Lib\SecurityAdmin\Restrictions;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Options;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
+
8
+ class Users extends Base {
9
+
10
+ protected function canRun() :bool {
11
+ /** @var Options $opts */
12
+ $opts = $this->getOptions();
13
+ return $opts->isSecAdminRestrictUsersEnabled();
14
+ }
15
+
16
+ protected function run() {
17
+ add_filter( 'editable_roles', [ $this, 'restrictEditableRoles' ], 100, 1 );
18
+ add_filter( 'user_has_cap', [ $this, 'restrictAdminUserChanges' ], 100, 3 );
19
+ add_action( 'delete_user', [ $this, 'restrictAdminUserDelete' ], 100, 1 );
20
+ add_action( 'add_user_role', [ $this, 'restrictAddUserRole' ], 100, 2 );
21
+ add_action( 'remove_user_role', [ $this, 'restrictRemoveUserRole' ], 100, 2 );
22
+ add_action( 'set_user_role', [ $this, 'restrictSetUserRole' ], 100, 3 );
23
+ }
24
+
25
+ /**
26
+ * @param int $userId
27
+ * @param string $role
28
+ */
29
+ public function restrictAddUserRole( $userId, $role ) {
30
+ $WPU = Services::WpUsers();
31
+
32
+ if ( $WPU->getCurrentWpUserId() !== $userId && strtolower( $role ) === 'administrator' ) {
33
+ $modifiedUser = $WPU->getUserById( $userId );
34
+
35
+ remove_action( 'remove_user_role', [ $this, 'restrictRemoveUserRole' ], 100 );
36
+ $modifiedUser->remove_role( 'administrator' );
37
+ add_action( 'remove_user_role', [ $this, 'restrictRemoveUserRole' ], 100, 2 );
38
+ }
39
+ }
40
+
41
+ /**
42
+ * @param int $userId
43
+ * @param string $role
44
+ * @param array $oldRoles
45
+ */
46
+ public function restrictSetUserRole( $userId, $role, $oldRoles = [] ) {
47
+ $WPU = Services::WpUsers();
48
+
49
+ $role = strtolower( $role );
50
+ if ( !is_array( $oldRoles ) ) {
51
+ $oldRoles = [];
52
+ }
53
+
54
+ if ( $WPU->getCurrentWpUserId() !== $userId ) {
55
+ $newRoleIsAdmin = $role == 'administrator';
56
+
57
+ // 1. Setting administrator role where it doesn't previously exist
58
+ if ( $newRoleIsAdmin && !in_array( 'administrator', $oldRoles ) ) {
59
+ $revert = true;
60
+ }
61
+ // 2. Setting non-administrator role when previous roles included administrator
62
+ elseif ( !$newRoleIsAdmin && in_array( 'administrator', $oldRoles ) ) {
63
+ $revert = true;
64
+ }
65
+ else {
66
+ $revert = false;
67
+ }
68
+
69
+ if ( $revert ) {
70
+ $modifiedUser = $WPU->getUserById( $userId );
71
+ remove_action( 'add_user_role', [ $this, 'restrictAddUserRole' ], 100 );
72
+ remove_action( 'remove_user_role', [ $this, 'restrictRemoveUserRole' ], 100 );
73
+ $modifiedUser->remove_role( $role );
74
+ foreach ( $oldRoles as $preExistingRoles ) {
75
+ $modifiedUser->add_role( $preExistingRoles );
76
+ }
77
+ add_action( 'add_user_role', [ $this, 'restrictAddUserRole' ], 100, 2 );
78
+ add_action( 'remove_user_role', [ $this, 'restrictRemoveUserRole' ], 100, 2 );
79
+ }
80
+ }
81
+ }
82
+
83
+ /**
84
+ * @param int $userId
85
+ * @param string $role
86
+ */
87
+ public function restrictRemoveUserRole( $userId, $role ) {
88
+ $WPU = Services::WpUsers();
89
+
90
+ if ( $WPU->getCurrentWpUserId() !== $userId && strtolower( $role ) === 'administrator' ) {
91
+ $modifiedUser = $WPU->getUserById( $userId );
92
+
93
+ remove_action( 'add_user_role', [ $this, 'restrictAddUserRole' ], 100 );
94
+ $modifiedUser->add_role( 'administrator' );
95
+ add_action( 'add_user_role', [ $this, 'restrictAddUserRole' ], 100, 2 );
96
+ }
97
+ }
98
+
99
+ /**
100
+ * @param int $userID
101
+ */
102
+ public function restrictAdminUserDelete( $userID ) {
103
+ $WPU = Services::WpUsers();
104
+ $userToDelete = $WPU->getUserById( $userID );
105
+ if ( $userToDelete && $WPU->isUserAdmin( $userToDelete ) ) {
106
+ Services::WpGeneral()
107
+ ->wpDie( __( 'Sorry, deleting administrators is currently restricted to your Security Admin', 'wp-simple-firewall' ) );
108
+ }
109
+ }
110
+
111
+ /**
112
+ * @param array[] $roles
113
+ * @return array[]
114
+ */
115
+ public function restrictEditableRoles( $roles ) {
116
+ if ( isset( $roles[ 'administrator' ] ) ) {
117
+ unset( $roles[ 'administrator' ] );
118
+ }
119
+ return $roles;
120
+ }
121
+
122
+ /**
123
+ * This hooked function captures the attempts to modify the user role using the standard
124
+ * WordPress profile edit pages. It doesn't sufficiently capture the AJAX request to
125
+ * modify user roles. (see user role hooks)
126
+ * @param array $allCaps
127
+ * @param $cap
128
+ * @param array $args
129
+ * @return array
130
+ */
131
+ public function restrictAdminUserChanges( $allCaps, $cap, $args ) {
132
+ /** @var string $userCap */
133
+ $userCap = $args[ 0 ];
134
+
135
+ if ( in_array( $userCap, [ 'edit_users', 'create_users' ] ) ) {
136
+ $blockCapability = false;
137
+
138
+ $req = Services::Request();
139
+ $WPU = Services::WpUsers();
140
+
141
+ $requestedUser = false;
142
+ $requestedUsername = $req->post( 'user_login' );
143
+
144
+ if ( empty( $requestedUsername ) ) {
145
+ $requestedUserId = $req->post( 'user_id' );
146
+ if ( !empty( $requestedUserId ) ) {
147
+ $requestedUser = $WPU->getUserById( $requestedUserId );
148
+ }
149
+ }
150
+ else {
151
+ $requestedUser = $WPU->getUserByUsername( $requestedUsername );
152
+ }
153
+
154
+ $requestedRole = strtolower( (string)$req->post( 'role', '' ) );
155
+
156
+ if ( $requestedUser instanceof \WP_User ) {
157
+ // editing an existing user other than yourself?
158
+ if ( $requestedUser->user_login != $WPU->getCurrentWpUsername() ) {
159
+
160
+ if ( $WPU->isUserAdmin( $requestedUser ) || $requestedRole == 'administrator' ) {
161
+ $blockCapability = true;
162
+ }
163
+ }
164
+ }
165
+ elseif ( $requestedRole == 'administrator' ) { //creating a new admin user?
166
+ $blockCapability = true;
167
+ }
168
+
169
+ if ( $blockCapability ) {
170
+ $allCaps[ $userCap ] = false;
171
+ }
172
+ }
173
+
174
+ return $allCaps;
175
+ }
176
+ }
src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/WpOptions.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Lib\SecurityAdmin\Restrictions;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Options;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
+
8
+ class WpOptions extends Base {
9
+
10
+ protected function canRun() :bool {
11
+ /** @var Options $opts */
12
+ $opts = $this->getOptions();
13
+ return $opts->getAdminAccessArea_Options()
14
+ && !$this->getMod()->isUpgrading() && !Services::WpGeneral()->isLoginRequest();
15
+ }
16
+
17
+ protected function run() {
18
+ add_filter( 'pre_update_option', [ $this, 'blockOptionsSaves' ], 1, 3 );
19
+ }
20
+
21
+ /**
22
+ * Need to always re-test isPluginAdmin() because there's a dynamic filter in there to
23
+ * permit saving by the plugin itself.
24
+ *
25
+ * Right before a plugin option is due to update it will check that we have permissions to do so
26
+ * and if not, will * revert the option to save to the previous one.
27
+ * @param mixed $newValue
28
+ * @param string $key
29
+ * @param mixed $oldValue
30
+ * @return mixed
31
+ * @deprecated 11.1
32
+ */
33
+ public function blockOptionsSaves( $newValue, $key, $oldValue ) {
34
+ /** @var Options $opts */
35
+ $opts = $this->getOptions();
36
+
37
+ if ( !$this->getCon()->isPluginAdmin() && is_string( $key )
38
+ && ( in_array( $key, $opts->getOptionsToRestrict() ) || $this->isPluginOption( $key ) ) ) {
39
+ $newValue = $oldValue;
40
+ }
41
+
42
+ return $newValue;
43
+ }
44
+
45
+ private function isPluginOption( string $key ) :bool {
46
+ return preg_match( sprintf( '/^%s.*_options$/', $this->getCon()->getOptionStoragePrefix() ), $key ) > 0;
47
+ }
48
+ }
src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/SecurityAdminController.php ADDED
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Lib\SecurityAdmin;
4
+
5
+ use FernleafSystems\Utilities\Logic\ExecOnce;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Controller\Assets\Enqueue;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
8
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\ModCon;
9
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Options;
10
+ use FernleafSystems\Wordpress\Services\Services;
11
+
12
+ class SecurityAdminController {
13
+
14
+ use ExecOnce;
15
+ use ModConsumer;
16
+
17
+ private $validPinRequest;
18
+
19
+ protected function canRun() :bool {
20
+ return $this->isEnabledSecAdmin();
21
+ }
22
+
23
+ protected function run() {
24
+
25
+ add_filter( $this->getCon()->prefix( 'is_plugin_admin' ), [ $this, 'adjustUserAdminPermissions' ] );
26
+ add_action( 'admin_init', function () {
27
+ $this->enqueueJS();
28
+ } );
29
+ add_action( 'init', function () {
30
+ if ( !$this->getCon()->isPluginAdmin() ) {
31
+ ( new Restrictions\WpOptions() )
32
+ ->setMod( $this->getMod() )
33
+ ->execute();
34
+ ( new Restrictions\Plugins() )
35
+ ->setMod( $this->getMod() )
36
+ ->execute();
37
+ ( new Restrictions\Themes() )
38
+ ->setMod( $this->getMod() )
39
+ ->execute();
40
+ ( new Restrictions\Posts() )
41
+ ->setMod( $this->getMod() )
42
+ ->execute();
43
+ ( new Restrictions\Users() )
44
+ ->setMod( $this->getMod() )
45
+ ->execute();
46
+
47
+ if ( !$this->getCon()->isThisPluginModuleRequest() ) {
48
+ add_action( 'admin_footer', [ $this, 'printPinLoginForm' ] );
49
+ }
50
+ }
51
+ } );
52
+ }
53
+
54
+ public function isEnabledSecAdmin() :bool {
55
+ /** @var Options $opts */
56
+ $opts = $this->getOptions();
57
+ return $this->getMod()->isModOptEnabled() &&
58
+ $opts->hasSecurityPIN() && $this->getSecAdminTimeout() > 0;
59
+ }
60
+
61
+ private function enqueueJS() {
62
+ add_filter( 'shield/custom_enqueues', function ( array $enqueues ) {
63
+ $enqueues[ Enqueue::JS ][] = 'shield/secadmin';
64
+
65
+ add_filter( 'shield/custom_localisations', function ( array $localz ) {
66
+ /** @var ModCon $mod */
67
+ $mod = $this->getMod();
68
+ /** @var Options $opts */
69
+ $opts = $this->getOptions();
70
+
71
+ $isCurrentlySecAdmin = $this->isCurrentlySecAdmin();
72
+ $localz[] = [
73
+ 'shield/secadmin',
74
+ 'shield_vars_secadmin',
75
+ [
76
+ 'ajax' => [
77
+ 'sec_admin_check' => $mod->getAjaxActionData( 'sec_admin_check' ),
78
+ 'sec_admin_login' => $mod->getAjaxActionData( 'sec_admin_login' ),
79
+ 'req_email_remove' => $mod->getAjaxActionData( 'req_email_remove' ),
80
+ ],
81
+ 'flags' => [
82
+ 'restrict_options' => !$isCurrentlySecAdmin && $opts->getAdminAccessArea_Options(),
83
+ 'run_checks' => $this->getCon()->getIsPage_PluginAdmin() && $isCurrentlySecAdmin,
84
+ ],
85
+ 'strings' => [
86
+ 'confirm' => __( 'Security Admin session has timed-out.', 'wp-simple-firewall' ).' '.__( 'Click OK to reload and re-authenticate.', 'wp-simple-firewall' ),
87
+ 'nearly' => __( 'Security Admin session has nearly timed-out.', 'wp-simple-firewall' ),
88
+ 'expired' => __( 'Security Admin session has timed-out.', 'wp-simple-firewall' ),
89
+ 'are_you_sure' => __( 'Are you sure?', 'wp-simple-firewall' ),
90
+ 'editing_restricted' => __( 'Editing this option is currently restricted.', 'wp-simple-firewall' ),
91
+ 'unlock_link' => sprintf(
92
+ '<a href="%1$s" title="%2$s" class="thickbox">%3$s</a>',
93
+ '#TB_inline?width=400&height=180&inlineId=WpsfAdminAccessLogin',
94
+ __( 'Security Admin Login', 'wp-simple-firewall' ),
95
+ __( 'Unlock', 'wp-simple-firewall' )
96
+ ),
97
+ ],
98
+ 'vars' => [
99
+ 'time_remaining' => $this->getSecAdminTimeRemaining(), // JS uses milliseconds
100
+ 'wp_options_to_restrict' => $opts->getOptionsToRestrict(),
101
+ ],
102
+ ]
103
+ ];
104
+ return $localz;
105
+ } );
106
+
107
+ return $enqueues;
108
+ } );
109
+ }
110
+
111
+ public function getSecAdminTimeout() :int {
112
+ return (int)$this->getOptions()->getOpt( 'admin_access_timeout' )*MINUTE_IN_SECONDS;
113
+ }
114
+
115
+ /**
116
+ * Only returns greater than 0 if you have a valid Sec admin session
117
+ */
118
+ public function getSecAdminTimeRemaining() :int {
119
+ $remaining = 0;
120
+ if ( $this->getCon()->getModule_Sessions()->getSessionCon()->hasSession() ) {
121
+
122
+ $secAdminAt = $this->getMod()->getSession()->getSecAdminAt();
123
+ if ( $this->isRegisteredSecAdminUser() ) {
124
+ $remaining = 0;
125
+ }
126
+ elseif ( $secAdminAt > 0 ) {
127
+ $remaining = $this->getSecAdminTimeout() - ( Services::Request()->ts() - $secAdminAt );
128
+ }
129
+ }
130
+ return (int)max( 0, $remaining );
131
+ }
132
+
133
+ /**
134
+ * @param \WP_User|null $user
135
+ * @return bool
136
+ */
137
+ public function isRegisteredSecAdminUser( $user = null ) :bool {
138
+ /** @var Options $opts */
139
+ $opts = $this->getOptions();
140
+ if ( !$user instanceof \WP_User ) {
141
+ $user = Services::WpUsers()->getCurrentWpUser();
142
+ }
143
+ return $user instanceof \WP_User && in_array( $user->user_login, $opts->getSecurityAdminUsers() );
144
+ }
145
+
146
+ public function isCurrentlySecAdmin() :bool {
147
+ return $this->isRegisteredSecAdminUser( Services::WpUsers()->getCurrentWpUser() )
148
+ || $this->getSecAdminTimeRemaining() > 0;
149
+ }
150
+
151
+ public function adjustUserAdminPermissions( $isPluginAdmin = true ) :bool {
152
+ return $isPluginAdmin &&
153
+ ( $this->isCurrentlySecAdmin() || $this->verifyPinRequest() );
154
+ }
155
+
156
+ public function printPinLoginForm() {
157
+ /** @var ModCon $mod */
158
+ $mod = $this->getMod();
159
+ /** @var Options $opts */
160
+ $opts = $this->getOptions();
161
+
162
+ add_thickbox();
163
+ echo $mod->renderTemplate( '/components/security_admin/login_box.twig', [
164
+ 'flags' => [
165
+ 'restrict_options' => $opts->getAdminAccessArea_Options()
166
+ ],
167
+ 'strings' => [
168
+ 'access_message' => __( 'Enter your Security Admin PIN', 'wp-simple-firewall' ),
169
+ ],
170
+ 'ajax' => [
171
+ 'sec_admin_login' => $mod->getAjaxActionData( 'sec_admin_login', true ),
172
+ 'sec_admin_login_box' => $mod->getAjaxActionData( 'sec_admin_login_box', true )
173
+ ]
174
+ ] );
175
+ }
176
+
177
+ public function verifyPinRequest() :bool {
178
+ if ( !isset( $this->validPinRequest ) ) {
179
+ $this->validPinRequest = ( new Ops\VerifyPinRequest() )
180
+ ->setMod( $this->getMod() )
181
+ ->run();
182
+ }
183
+ return $this->validPinRequest;
184
+ }
185
+ }
src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/VerifySecurityAdminList.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Lib\SecurityAdmin;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
+
8
+ class VerifySecurityAdminList {
9
+
10
+ use ModConsumer;
11
+
12
+ public function run( array $users ) :array {
13
+ $WPU = Services::WpUsers();
14
+
15
+ $filtered = [];
16
+ foreach ( array_map( 'trim', $users ) as $key => $usernameOrEmail ) {
17
+ $user = null;
18
+
19
+ if ( !empty( $usernameOrEmail ) ) {
20
+ if ( Services::Data()->validEmail( $usernameOrEmail ) ) {
21
+ $user = $WPU->getUserByEmail( $usernameOrEmail );
22
+ }
23
+ else {
24
+ $user = $WPU->getUserByUsername( $usernameOrEmail );
25
+ if ( is_null( $user ) && is_numeric( $usernameOrEmail ) ) {
26
+ $user = $WPU->getUserById( $usernameOrEmail );
27
+ }
28
+ }
29
+ }
30
+
31
+ if ( $user instanceof \WP_User && $user->ID > 0 && $WPU->isUserAdmin( $user ) ) {
32
+ $filtered[] = $user->user_login;
33
+ }
34
+ }
35
+
36
+ natsort( $filtered );
37
+ return array_unique( $filtered );
38
+ }
39
+ }
src/lib/src/Modules/SecurityAdmin/Lib/WhiteLabel/ApplyLabels.php CHANGED
@@ -65,9 +65,7 @@ class ApplyLabels {
65
  }
66
 
67
  public function hideFromPluginEditor() {
68
- $con = $this->getCon();
69
- $js = Services::Data()->readFileContentsUsingInclude( $con->getPath_AssetJs( 'whitelabel.js' ) );
70
- echo sprintf( '<script type="text/javascript">%s</script>', sprintf( $js, $con->base_file ) );
71
  }
72
 
73
  /**
@@ -81,12 +79,20 @@ class ApplyLabels {
81
  $labels = $mod->getWhitelabelOptions();
82
 
83
  // these are the old white labelling keys which will be replaced upon final release of white labelling.
84
- $sServiceName = $labels[ 'name_main' ];
85
- $pluginLabels[ 'Name' ] = $sServiceName;
86
- $pluginLabels[ 'Title' ] = $sServiceName;
87
- $pluginLabels[ 'Author' ] = $labels[ 'name_company' ];
88
- $pluginLabels[ 'AuthorName' ] = $labels[ 'name_company' ];
89
- $pluginLabels[ 'MenuTitle' ] = $labels[ 'name_menu' ];
 
 
 
 
 
 
 
 
90
 
91
  if ( !empty( $labels[ 'description' ] ) ) {
92
  $pluginLabels[ 'Description' ] = $labels[ 'description' ];
65
  }
66
 
67
  public function hideFromPluginEditor() {
68
+ // TODO
 
 
69
  }
70
 
71
  /**
79
  $labels = $mod->getWhitelabelOptions();
80
 
81
  // these are the old white labelling keys which will be replaced upon final release of white labelling.
82
+ $serviceName = $labels[ 'name_main' ];
83
+ if ( !empty( $serviceName ) ) {
84
+ $pluginLabels[ 'Name' ] = $serviceName;
85
+ $pluginLabels[ 'Title' ] = $serviceName;
86
+ }
87
+ $companyName = $labels[ 'name_company' ];
88
+ if ( !empty( $companyName ) ) {
89
+ $pluginLabels[ 'Author' ] = $labels[ 'name_company' ];
90
+ $pluginLabels[ 'AuthorName' ] = $labels[ 'name_company' ];
91
+ }
92
+ $menuName = empty( $labels[ 'name_menu' ] ) ? $serviceName : $labels[ 'name_menu' ];
93
+ if ( !empty( $menuName ) ) {
94
+ $pluginLabels[ 'MenuTitle' ] = $menuName;
95
+ }
96
 
97
  if ( !empty( $labels[ 'description' ] ) ) {
98
  $pluginLabels[ 'Description' ] = $labels[ 'description' ];
src/lib/src/Modules/SecurityAdmin/ModCon.php CHANGED
@@ -20,6 +20,11 @@ class ModCon extends BaseShield\ModCon {
20
  */
21
  private $whitelabelCon;
22
 
 
 
 
 
 
23
  protected function setupCustomHooks() {
24
  add_action( $this->prefix( 'pre_deactivate_plugin' ), [ $this, 'preDeactivatePlugin' ] );
25
  }
@@ -32,38 +37,22 @@ class ModCon extends BaseShield\ModCon {
32
  return $this->whitelabelCon;
33
  }
34
 
35
- public function getSecAdminLoginAjaxData() :array {
36
- return $this->getAjaxActionData( 'sec_admin_login' );
37
- }
38
-
39
- /**
40
- * @return bool
41
- * @throws \Exception
42
- */
43
- protected function isReadyToExecute() :bool {
44
- return $this->isEnabledSecurityAdmin() && parent::isReadyToExecute();
45
  }
46
 
47
- /**
48
- * No checking of admin capabilities in-case of infinite loop with
49
- * admin access caps check
50
- * @return bool
51
- */
52
- public function isRegisteredSecAdminUser() {
53
- /** @var Options $opts */
54
- $opts = $this->getOptions();
55
- $sUser = Services::WpUsers()->getCurrentWpUsername();
56
- return !empty( $sUser ) && in_array( $sUser, $opts->getSecurityAdminUsers() );
57
  }
58
 
59
  protected function preProcessOptions() {
60
  /** @var Options $opts */
61
  $opts = $this->getOptions();
62
 
63
- if ( $this->isValidSecAdminRequest() ) {
64
- $this->setSecurityAdminStatusOnOff( true );
65
- }
66
-
67
  // Verify whitelabel images
68
  if ( $this->isWlEnabled() ) {
69
  foreach ( [ 'wl_menuiconurl', 'wl_dashboardlogourl', 'wl_login2fa_logourl' ] as $key ) {
@@ -73,85 +62,26 @@ class ModCon extends BaseShield\ModCon {
73
  }
74
  }
75
 
76
- $opts->setOpt( 'sec_admin_users', $this->verifySecAdminUsers( $opts->getSecurityAdminUsers() ) );
 
 
 
 
77
 
78
  if ( hash_equals( $opts->getSecurityPIN(), self::HASH_DELETE ) ) {
79
  $opts->clearSecurityAdminKey();
80
- $this->setSecurityAdminStatusOnOff( false );
 
 
81
  // If you delete the PIN, you also delete the sec admins. Prevents a lock out bug.
82
  $opts->setOpt( 'sec_admin_users', [] );
83
  }
84
  }
85
 
86
- /**
87
- * Ensures that all entries are valid users.
88
- * @param string[] $aSecUsers
89
- * @return string[]
90
- */
91
- private function verifySecAdminUsers( $aSecUsers ) {
92
- /** @var Options $opts */
93
- $opts = $this->getOptions();
94
- $DP = Services::Data();
95
- $WPU = Services::WpUsers();
96
-
97
- $aFiltered = [];
98
- foreach ( $aSecUsers as $nCurrentKey => $usernameOrEmail ) {
99
- $user = null;
100
-
101
- if ( !empty( $usernameOrEmail ) ) {
102
- if ( $DP->validEmail( $usernameOrEmail ) ) {
103
- $user = $WPU->getUserByEmail( $usernameOrEmail );
104
- }
105
- else {
106
- $user = $WPU->getUserByUsername( $usernameOrEmail );
107
- if ( is_null( $user ) && is_numeric( $usernameOrEmail ) ) {
108
- $user = $WPU->getUserById( $usernameOrEmail );
109
- }
110
- }
111
- }
112
-
113
- if ( $user instanceof \WP_User && $user->ID > 0 && $WPU->isUserAdmin( $user ) ) {
114
- $aFiltered[] = $user->user_login;
115
- }
116
- }
117
-
118
- // We now run a bit of a sanity check to ensure that the current user is
119
- // not adding users here that aren't themselves without a key to still gain access
120
- $oCurrent = $WPU->getCurrentWpUser();
121
- if ( !empty( $aFiltered ) && !$opts->hasSecurityPIN() && !in_array( $oCurrent->user_login, $aFiltered ) ) {
122
- $aFiltered[] = $oCurrent->user_login;
123
- }
124
-
125
- natsort( $aFiltered );
126
- return array_unique( $aFiltered );
127
- }
128
-
129
- public function getSecAdminTimeout() :int {
130
- return (int)$this->getOptions()->getOpt( 'admin_access_timeout' )*MINUTE_IN_SECONDS;
131
- }
132
-
133
- /**
134
- * Only returns greater than 0 if you have a valid Sec admin session
135
- */
136
- public function getSecAdminTimeLeft() :int {
137
- $nLeft = 0;
138
- if ( $this->getCon()->getModule_Sessions()->getSessionCon()->hasSession() ) {
139
-
140
- $nSecAdminAt = $this->getSession()->getSecAdminAt();
141
- if ( $this->isRegisteredSecAdminUser() ) {
142
- $nLeft = 0;
143
- }
144
- elseif ( $nSecAdminAt > 0 ) {
145
- $nLeft = $this->getSecAdminTimeout() - ( Services::Request()->ts() - $nSecAdminAt );
146
- }
147
- }
148
- return (int)max( 0, $nLeft );
149
- }
150
-
151
  protected function handleModAction( string $action ) {
152
  switch ( $action ) {
153
  case 'remove_secadmin_confirm':
154
- ( new Lib\Actions\RemoveSecAdmin() )
155
  ->setMod( $this )
156
  ->remove();
157
  break;
@@ -161,72 +91,10 @@ class ModCon extends BaseShield\ModCon {
161
  }
162
  }
163
 
164
- public function isSecAdminSessionValid() :bool {
165
- return $this->getSecAdminTimeLeft() > 0;
166
- }
167
-
168
- public function isEnabledSecurityAdmin() :bool {
169
- /** @var Options $opts */
170
- $opts = $this->getOptions();
171
- return $this->isModOptEnabled() &&
172
- ( count( $opts->getSecurityAdminUsers() ) > 0 ||
173
- ( $opts->hasSecurityPIN() && $this->getSecAdminTimeout() > 0 )
174
- );
175
- }
176
-
177
  /**
178
- * @param bool $bSetOn
179
- * @return bool
180
  */
181
- public function setSecurityAdminStatusOnOff( $bSetOn = false ) {
182
- /** @var Shield\Databases\Session\Update $oUpdater */
183
- $oUpdater = $this->getDbHandler_Sessions()->getQueryUpdater();
184
- return $bSetOn ?
185
- $oUpdater->startSecurityAdmin( $this->getSession() )
186
- : $oUpdater->terminateSecurityAdmin( $this->getSession() );
187
- }
188
-
189
- public function isValidSecAdminRequest() :bool {
190
- return $this->isAccessKeyRequest() && $this->testSecAccessKeyRequest();
191
- }
192
-
193
- public function testSecAccessKeyRequest() :bool {
194
- if ( !isset( $this->bValidSecAdminRequest ) ) {
195
- $bValid = false;
196
- $sReqKey = Services::Request()->post( 'sec_admin_key' );
197
- if ( !empty( $sReqKey ) ) {
198
- /** @var Options $opts */
199
- $opts = $this->getOptions();
200
- $bValid = hash_equals( $opts->getSecurityPIN(), md5( $sReqKey ) );
201
- if ( !$bValid ) {
202
- $sEscaped = isset( $_POST[ 'sec_admin_key' ] ) ? $_POST[ 'sec_admin_key' ] : '';
203
- if ( !empty( $sEscaped ) ) {
204
- // Workaround for escaping of passwords
205
- $bValid = hash_equals( $opts->getSecurityPIN(), md5( $sEscaped ) );
206
- if ( $bValid ) {
207
- $opts->setOpt( 'admin_access_key', md5( $sReqKey ) );
208
- }
209
- }
210
- }
211
-
212
- $this->getCon()->fireEvent( $bValid ? 'key_success' : 'key_fail' );
213
- }
214
-
215
- $this->bValidSecAdminRequest = $bValid;
216
- }
217
- return $this->bValidSecAdminRequest;
218
- }
219
-
220
- private function isAccessKeyRequest() :bool {
221
- return strlen( Services::Request()->post( 'sec_admin_key', '' ) ) > 0;
222
- }
223
-
224
- public function verifyAccessKey( string $key ) :bool {
225
- /** @var Options $opts */
226
- $opts = $this->getOptions();
227
- return !empty( $key ) && hash_equals( $opts->getSecurityPIN(), md5( $key ) );
228
- }
229
-
230
  public function getWhitelabelOptions() :array {
231
  $opts = $this->getOptions();
232
  $main = $opts->getOpt( 'wl_pluginnamemain' );
@@ -288,6 +156,7 @@ class ModCon extends BaseShield\ModCon {
288
  }
289
 
290
  /**
 
291
  * @param string $pin
292
  * @return $this
293
  * @throws \Exception
@@ -302,44 +171,11 @@ class ModCon extends BaseShield\ModCon {
302
 
303
  $this->setIsMainFeatureEnabled( true );
304
  $this->getOptions()->setOpt( 'admin_access_key', md5( $pin ) );
305
- return $this->saveModOptions();
306
- }
307
-
308
- public function getScriptLocalisations() :array {
309
- $locals = parent::getScriptLocalisations();
310
-
311
- if ( $this->getSecAdminTimeLeft() > 0 ) {
312
- $data = [
313
- 'ajax' => [
314
- 'check' => $this->getSecAdminCheckAjaxData(),
315
- ],
316
- 'is_sec_admin' => true, // if $nSecTimeLeft > 0
317
- 'timeleft' => $this->getSecAdminTimeLeft(), // JS uses milliseconds
318
- 'strings' => [
319
- 'confirm' => __( 'Security Admin session has timed-out.', 'wp-simple-firewall' ).' '.__( 'Reload now?', 'wp-simple-firewall' ),
320
- 'nearly' => __( 'Security Admin session has nearly timed-out.', 'wp-simple-firewall' ),
321
- 'expired' => __( 'Security Admin session has timed-out.', 'wp-simple-firewall' )
322
- ]
323
- ];
324
- }
325
- else {
326
- $data = [
327
- 'ajax' => [
328
- 'req_email_remove' => $this->getAjaxActionData( 'req_email_remove' ),
329
- ],
330
- 'strings' => [
331
- 'are_you_sure' => __( 'Are you sure?', 'wp-simple-firewall' )
332
- ]
333
- ];
334
- }
335
-
336
- $locals[] = [
337
- 'plugin',
338
- 'icwp_wpsf_vars_secadmin',
339
- $data
340
- ];
341
 
342
- return $locals;
343
  }
344
 
345
  /**
@@ -350,11 +186,11 @@ class ModCon extends BaseShield\ModCon {
350
  $opts = $this->getOptions();
351
 
352
  // Restricting Activate Plugins also means restricting the rest.
353
- $aPluginsRestrictions = $opts->getAdminAccessArea_Plugins();
354
- if ( in_array( 'activate_plugins', $aPluginsRestrictions ) ) {
355
  $opts->setOpt(
356
  'admin_access_restrict_plugins',
357
- array_unique( array_merge( $aPluginsRestrictions, [
358
  'install_plugins',
359
  'update_plugins',
360
  'delete_plugins'
@@ -363,11 +199,11 @@ class ModCon extends BaseShield\ModCon {
363
  }
364
 
365
  // Restricting Switch (Activate) Themes also means restricting the rest.
366
- $aThemesRestrictions = $opts->getAdminAccessArea_Themes();
367
- if ( in_array( 'switch_themes', $aThemesRestrictions ) && in_array( 'edit_theme_options', $aThemesRestrictions ) ) {
368
  $opts->setOpt(
369
  'admin_access_restrict_themes',
370
- array_unique( array_merge( $aThemesRestrictions, [
371
  'install_themes',
372
  'update_themes',
373
  'delete_themes'
@@ -375,11 +211,11 @@ class ModCon extends BaseShield\ModCon {
375
  );
376
  }
377
 
378
- $aPostRestrictions = $opts->getAdminAccessArea_Posts();
379
- if ( in_array( 'edit', $aPostRestrictions ) ) {
380
  $opts->setOpt(
381
  'admin_access_restrict_posts',
382
- array_unique( array_merge( $aPostRestrictions, [ 'create', 'publish', 'delete' ] ) )
383
  );
384
  }
385
  }
@@ -395,4 +231,116 @@ class ModCon extends BaseShield\ModCon {
395
  );
396
  }
397
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
398
  }
20
  */
21
  private $whitelabelCon;
22
 
23
+ /**
24
+ * @var Lib\SecurityAdmin\SecurityAdminController
25
+ */
26
+ private $securityAdminCon;
27
+
28
  protected function setupCustomHooks() {
29
  add_action( $this->prefix( 'pre_deactivate_plugin' ), [ $this, 'preDeactivatePlugin' ] );
30
  }
37
  return $this->whitelabelCon;
38
  }
39
 
40
+ public function getSecurityAdminController() :Lib\SecurityAdmin\SecurityAdminController {
41
+ if ( !$this->securityAdminCon instanceof Lib\SecurityAdmin\SecurityAdminController ) {
42
+ $this->securityAdminCon = ( new Lib\SecurityAdmin\SecurityAdminController() )
43
+ ->setMod( $this );
44
+ }
45
+ return $this->securityAdminCon;
 
 
 
 
46
  }
47
 
48
+ public function getSecAdminLoginAjaxData() :array {
49
+ return $this->getAjaxActionData( 'sec_admin_login' );
 
 
 
 
 
 
 
 
50
  }
51
 
52
  protected function preProcessOptions() {
53
  /** @var Options $opts */
54
  $opts = $this->getOptions();
55
 
 
 
 
 
56
  // Verify whitelabel images
57
  if ( $this->isWlEnabled() ) {
58
  foreach ( [ 'wl_menuiconurl', 'wl_dashboardlogourl', 'wl_login2fa_logourl' ] as $key ) {
62
  }
63
  }
64
 
65
+ $opts->setOpt( 'sec_admin_users',
66
+ ( new Lib\SecurityAdmin\VerifySecurityAdminList() )
67
+ ->setMod( $this )
68
+ ->run( $opts->getSecurityAdminUsers() )
69
+ );
70
 
71
  if ( hash_equals( $opts->getSecurityPIN(), self::HASH_DELETE ) ) {
72
  $opts->clearSecurityAdminKey();
73
+ ( new Lib\SecurityAdmin\Ops\ToggleSecAdminStatus() )
74
+ ->setMod( $this )
75
+ ->turnOff();
76
  // If you delete the PIN, you also delete the sec admins. Prevents a lock out bug.
77
  $opts->setOpt( 'sec_admin_users', [] );
78
  }
79
  }
80
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  protected function handleModAction( string $action ) {
82
  switch ( $action ) {
83
  case 'remove_secadmin_confirm':
84
+ ( new Lib\SecurityAdmin\Ops\RemoveSecAdmin() )
85
  ->setMod( $this )
86
  ->remove();
87
  break;
91
  }
92
  }
93
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  /**
95
+ * @return array
96
+ * @deprecated 11.1
97
  */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  public function getWhitelabelOptions() :array {
99
  $opts = $this->getOptions();
100
  $main = $opts->getOpt( 'wl_pluginnamemain' );
156
  }
157
 
158
  /**
159
+ * Used by Wizard. TODO: sort out the wizard requests!
160
  * @param string $pin
161
  * @return $this
162
  * @throws \Exception
171
 
172
  $this->setIsMainFeatureEnabled( true );
173
  $this->getOptions()->setOpt( 'admin_access_key', md5( $pin ) );
174
+ ( new Lib\SecurityAdmin\Ops\ToggleSecAdminStatus() )
175
+ ->setMod( $this )
176
+ ->turnOn();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
 
178
+ return $this->saveModOptions();
179
  }
180
 
181
  /**
186
  $opts = $this->getOptions();
187
 
188
  // Restricting Activate Plugins also means restricting the rest.
189
+ $pluginsRestrictions = $opts->getAdminAccessArea_Plugins();
190
+ if ( in_array( 'activate_plugins', $pluginsRestrictions ) ) {
191
  $opts->setOpt(
192
  'admin_access_restrict_plugins',
193
+ array_unique( array_merge( $pluginsRestrictions, [
194
  'install_plugins',
195
  'update_plugins',
196
  'delete_plugins'
199
  }
200
 
201
  // Restricting Switch (Activate) Themes also means restricting the rest.
202
+ $themesRestrictions = $opts->getAdminAccessArea_Themes();
203
+ if ( in_array( 'switch_themes', $themesRestrictions ) && in_array( 'edit_theme_options', $themesRestrictions ) ) {
204
  $opts->setOpt(
205
  'admin_access_restrict_themes',
206
+ array_unique( array_merge( $themesRestrictions, [
207
  'install_themes',
208
  'update_themes',
209
  'delete_themes'
211
  );
212
  }
213
 
214
+ $postRestrictions = $opts->getAdminAccessArea_Posts();
215
+ if ( in_array( 'edit', $postRestrictions ) ) {
216
  $opts->setOpt(
217
  'admin_access_restrict_posts',
218
+ array_unique( array_merge( $postRestrictions, [ 'create', 'publish', 'delete' ] ) )
219
  );
220
  }
221
  }
231
  );
232
  }
233
  }
234
+
235
+ /**
236
+ * No checking of admin capabilities in-case of infinite loop with
237
+ * admin access caps check
238
+ * @return bool
239
+ * @deprecated 11.1
240
+ */
241
+ public function isRegisteredSecAdminUser() {
242
+ /** @var Options $opts */
243
+ $opts = $this->getOptions();
244
+ $sUser = Services::WpUsers()->getCurrentWpUsername();
245
+ return !empty( $sUser ) && in_array( $sUser, $opts->getSecurityAdminUsers() );
246
+ }
247
+
248
+ /**
249
+ * @return bool
250
+ * @deprecated 11.1
251
+ */
252
+ public function isEnabledSecurityAdmin() :bool {
253
+ /** @var Options $opts */
254
+ $opts = $this->getOptions();
255
+ return $this->isModOptEnabled() &&
256
+ ( count( $opts->getSecurityAdminUsers() ) > 0 ||
257
+ ( $opts->hasSecurityPIN() && $this->getSecAdminTimeout() > 0 )
258
+ );
259
+ }
260
+
261
+ /**
262
+ * @return bool
263
+ * @deprecated 11.1
264
+ */
265
+ public function isSecAdminSessionValid() :bool {
266
+ return $this->getSecAdminTimeLeft() > 0;
267
+ }
268
+
269
+ /**
270
+ * Only returns greater than 0 if you have a valid Sec admin session
271
+ * @deprecated 11.1
272
+ */
273
+ public function getSecAdminTimeLeft() :int {
274
+ $nLeft = 0;
275
+ if ( $this->getCon()->getModule_Sessions()->getSessionCon()->hasSession() ) {
276
+
277
+ $nSecAdminAt = $this->getSession()->getSecAdminAt();
278
+ if ( $this->isRegisteredSecAdminUser() ) {
279
+ $nLeft = 0;
280
+ }
281
+ elseif ( $nSecAdminAt > 0 ) {
282
+ $nLeft = $this->getSecAdminTimeout() - ( Services::Request()->ts() - $nSecAdminAt );
283
+ }
284
+ }
285
+ return (int)max( 0, $nLeft );
286
+ }
287
+
288
+ /**
289
+ * @return int
290
+ * @deprecated 11.1
291
+ */
292
+ public function getSecAdminTimeout() :int {
293
+ return (int)$this->getOptions()->getOpt( 'admin_access_timeout' )*MINUTE_IN_SECONDS;
294
+ }
295
+
296
+ /**
297
+ * Ensures that all entries are valid users.
298
+ * @param string[] $aSecUsers
299
+ * @return string[]
300
+ * @deprecated 11.1
301
+ */
302
+ private function verifySecAdminUsers( $aSecUsers ) {
303
+ return $aSecUsers;
304
+ }
305
+
306
+ /**
307
+ * @return bool
308
+ * @deprecated 11.1
309
+ */
310
+ private function isAccessKeyRequest() :bool {
311
+ return strlen( Services::Request()->post( 'sec_admin_key', '' ) ) > 0;
312
+ }
313
+
314
+ public function verifyAccessKey( string $key ) :bool {
315
+ /** @var Options $opts */
316
+ $opts = $this->getOptions();
317
+ return !empty( $key ) && hash_equals( $opts->getSecurityPIN(), md5( $key ) );
318
+ }
319
+
320
+ /**
321
+ * @return bool
322
+ * @deprecated 11.1
323
+ */
324
+ public function testSecAccessKeyRequest() :bool {
325
+ return ( new Lib\SecurityAdmin\Ops\VerifyPinRequest() )
326
+ ->setMod( $this )
327
+ ->run();
328
+ }
329
+
330
+ /**
331
+ * @return bool
332
+ * @deprecated 11.1
333
+ */
334
+ public function isValidSecAdminRequest() :bool {
335
+ return false;
336
+ }
337
+
338
+ /**
339
+ * @param bool $bSetOn
340
+ * @return bool
341
+ * @deprecated 11.1
342
+ */
343
+ public function setSecurityAdminStatusOnOff( $bSetOn = false ) {
344
+ return false;
345
+ }
346
  }
src/lib/src/Modules/SecurityAdmin/Options.php CHANGED
@@ -27,9 +27,20 @@ class Options extends BaseShield\Options {
27
  return $this->getAdminAccessArea( 'posts' );
28
  }
29
 
 
 
 
 
 
 
 
 
 
 
30
  /**
31
  * @param string $sArea one of plugins, themes
32
  * @return array
 
33
  */
34
  private function getAdminAccessArea( $sArea = 'plugins' ) :array {
35
  $d = $this->getOpt( 'admin_access_restrict_'.$sArea, [] );
@@ -48,8 +59,8 @@ class Options extends BaseShield\Options {
48
  */
49
  public function getOptionsToRestrict( $type = '' ) {
50
  $type = empty( $type ) ? ( Services::WpGeneral()->isMultisite() ? 'wpms' : 'wp' ) : 'wp';
51
- $aOptions = $this->getRestrictedOptions();
52
- return ( isset( $aOptions[ $type.'_options' ] ) && is_array( $aOptions[ $type.'_options' ] ) ) ? $aOptions[ $type.'_options' ] : [];
53
  }
54
 
55
  /**
27
  return $this->getAdminAccessArea( 'posts' );
28
  }
29
 
30
+ /**
31
+ * @param string $area one of plugins, themes
32
+ * @return array
33
+ * @since 11.1
34
+ */
35
+ public function getSecAdminAreaCaps( $area = 'plugins' ) :array {
36
+ $d = $this->getOpt( 'admin_access_restrict_'.$area, [] );
37
+ return is_array( $d ) ? $d : [];
38
+ }
39
+
40
  /**
41
  * @param string $sArea one of plugins, themes
42
  * @return array
43
+ * @deprecated 11.1
44
  */
45
  private function getAdminAccessArea( $sArea = 'plugins' ) :array {
46
  $d = $this->getOpt( 'admin_access_restrict_'.$sArea, [] );
59
  */
60
  public function getOptionsToRestrict( $type = '' ) {
61
  $type = empty( $type ) ? ( Services::WpGeneral()->isMultisite() ? 'wpms' : 'wp' ) : 'wp';
62
+ $options = $this->getRestrictedOptions();
63
+ return ( isset( $options[ $type.'_options' ] ) && is_array( $options[ $type.'_options' ] ) ) ? $options[ $type.'_options' ] : [];
64
  }
65
 
66
  /**
src/lib/src/Modules/SecurityAdmin/Processor.php CHANGED
@@ -3,167 +3,72 @@
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
6
- use FernleafSystems\Wordpress\Services\Services;
7
 
8
  class Processor extends BaseShield\Processor {
9
 
10
  protected function run() {
11
- add_filter( $this->getCon()->prefix( 'is_plugin_admin' ), [ $this, 'adjustUserAdminPermissions' ] );
 
12
 
13
  /** @var Options $opts */
14
  $opts = $this->getOptions();
15
  if ( $opts->isEnabledWhitelabel() ) {
16
- /** @var ModCon $mod */
17
- $mod = $this->getMod();
18
  $mod->getWhiteLabelController()->execute();
19
  }
 
 
20
  }
21
 
22
  /**
23
  * @param bool $bHasPermission
24
  * @return bool
 
25
  */
26
  public function adjustUserAdminPermissions( $bHasPermission = true ) :bool {
27
- /** @var ModCon $mod */
28
- $mod = $this->getMod();
29
- return $bHasPermission &&
30
- ( $mod->isRegisteredSecAdminUser() || $mod->isSecAdminSessionValid()
31
- || $mod->testSecAccessKeyRequest() );
32
  }
33
 
34
  public function onWpInit() {
35
- if ( !$this->getCon()->isPluginAdmin() ) {
36
- /** @var ModCon $mod */
37
- $mod = $this->getMod();
38
- /** @var Options $opts */
39
- $opts = $this->getOptions();
40
-
41
- if ( !$mod->isUpgrading() && !Services::WpGeneral()->isLoginRequest() ) {
42
- add_filter( 'pre_update_option', [ $this, 'blockOptionsSaves' ], 1, 3 );
43
- }
44
-
45
- if ( $opts->isSecAdminRestrictUsersEnabled() ) {
46
- add_filter( 'editable_roles', [ $this, 'restrictEditableRoles' ], 100, 1 );
47
- add_filter( 'user_has_cap', [ $this, 'restrictAdminUserChanges' ], 100, 3 );
48
- add_action( 'delete_user', [ $this, 'restrictAdminUserDelete' ], 100, 1 );
49
- add_action( 'add_user_role', [ $this, 'restrictAddUserRole' ], 100, 2 );
50
- add_action( 'remove_user_role', [ $this, 'restrictRemoveUserRole' ], 100, 2 );
51
- add_action( 'set_user_role', [ $this, 'restrictSetUserRole' ], 100, 3 );
52
- }
53
-
54
- $aPluginRestrictions = $opts->getAdminAccessArea_Plugins();
55
- if ( !empty( $aPluginRestrictions ) ) {
56
- add_filter( 'user_has_cap', [ $this, 'disablePluginManipulation' ], 0, 3 );
57
- }
58
-
59
- $aThemeRestrictions = $opts->getAdminAccessArea_Themes();
60
- if ( !empty( $aThemeRestrictions ) ) {
61
- add_filter( 'user_has_cap', [ $this, 'disableThemeManipulation' ], 0, 3 );
62
- }
63
-
64
- $aPostRestrictions = $opts->getAdminAccessArea_Posts();
65
- if ( !empty( $aPostRestrictions ) ) {
66
- add_filter( 'user_has_cap', [ $this, 'disablePostsManipulation' ], 0, 3 );
67
- }
68
-
69
- if ( !$this->getCon()->isThisPluginModuleRequest() ) {
70
- add_action( 'admin_footer', [ $this, 'printAdminAccessAjaxForm' ] );
71
- }
72
- }
73
  }
74
 
75
  /**
76
  * @param int $nUserId
77
  * @param string $sRole
 
78
  */
79
  public function restrictAddUserRole( $nUserId, $sRole ) {
80
- $oWpUsers = Services::WpUsers();
81
-
82
- if ( $oWpUsers->getCurrentWpUserId() !== $nUserId && strtolower( $sRole ) === 'administrator' ) {
83
- $oModUser = $oWpUsers->getUserById( $nUserId );
84
- remove_action( 'remove_user_role', [ $this, 'restrictRemoveUserRole' ], 100 );
85
- $oModUser->remove_role( 'administrator' );
86
- add_action( 'remove_user_role', [ $this, 'restrictRemoveUserRole' ], 100, 2 );
87
- }
88
  }
89
 
90
  /**
91
  * @param int $nUserId
92
  * @param string $sRole
93
  * @param array $aOldRoles
 
94
  */
95
  public function restrictSetUserRole( $nUserId, $sRole, $aOldRoles = [] ) {
96
- $oWpUsers = Services::WpUsers();
97
-
98
- $sRole = strtolower( $sRole );
99
- if ( !is_array( $aOldRoles ) ) {
100
- $aOldRoles = [];
101
- }
102
-
103
- if ( $oWpUsers->getCurrentWpUserId() !== $nUserId ) {
104
- $bNewRoleIsAdmin = $sRole == 'administrator';
105
-
106
- // 1. Setting administrator role where it doesn't previously exist
107
- if ( $bNewRoleIsAdmin && !in_array( 'administrator', $aOldRoles ) ) {
108
- $bRevert = true;
109
- }
110
- // 2. Setting non-administrator role when previous roles included administrator
111
- elseif ( !$bNewRoleIsAdmin && in_array( 'administrator', $aOldRoles ) ) {
112
- $bRevert = true;
113
- }
114
- else {
115
- $bRevert = false;
116
- }
117
-
118
- if ( $bRevert ) {
119
- $oModUser = $oWpUsers->getUserById( $nUserId );
120
- remove_action( 'add_user_role', [ $this, 'restrictAddUserRole' ], 100 );
121
- remove_action( 'remove_user_role', [ $this, 'restrictRemoveUserRole' ], 100 );
122
- $oModUser->remove_role( $sRole );
123
- foreach ( $aOldRoles as $sPreExistingRoles ) {
124
- $oModUser->add_role( $sPreExistingRoles );
125
- }
126
- add_action( 'add_user_role', [ $this, 'restrictAddUserRole' ], 100, 2 );
127
- add_action( 'remove_user_role', [ $this, 'restrictRemoveUserRole' ], 100, 2 );
128
- }
129
- }
130
  }
131
 
132
  /**
133
  * @param int $nUserId
134
  * @param string $sRole
 
135
  */
136
  public function restrictRemoveUserRole( $nUserId, $sRole ) {
137
- $oWpUsers = Services::WpUsers();
138
-
139
- if ( $oWpUsers->getCurrentWpUserId() !== $nUserId && strtolower( $sRole ) === 'administrator' ) {
140
- $oModUser = $oWpUsers->getUserById( $nUserId );
141
- remove_action( 'add_user_role', [ $this, 'restrictAddUserRole' ], 100 );
142
- $oModUser->add_role( 'administrator' );
143
- add_action( 'add_user_role', [ $this, 'restrictAddUserRole' ], 100, 2 );
144
- }
145
  }
146
 
147
  /**
148
  * @param int $nId
 
149
  */
150
  public function restrictAdminUserDelete( $nId ) {
151
- $WPU = Services::WpUsers();
152
- $oUserToDelete = $WPU->getUserById( $nId );
153
- if ( $oUserToDelete && $WPU->isUserAdmin( $oUserToDelete ) ) {
154
- Services::WpGeneral()
155
- ->wpDie( __( 'Sorry, deleting administrators is currently restricted to your Security Admin', 'wp-simple-firewall' ) );
156
- }
157
  }
158
 
159
  /**
160
  * @param array[] $roles
161
  * @return array[]
 
162
  */
163
  public function restrictEditableRoles( $roles ) {
164
- if ( isset( $roles[ 'administrator' ] ) ) {
165
- unset( $roles[ 'administrator' ] );
166
- }
167
  return $roles;
168
  }
169
 
@@ -175,88 +80,29 @@ class Processor extends BaseShield\Processor {
175
  * @param $cap
176
  * @param array $args
177
  * @return array
 
178
  */
179
  public function restrictAdminUserChanges( $allCaps, $cap, $args ) {
180
- /** @var string $userCap */
181
- $userCap = $args[ 0 ];
182
-
183
- $aRelevantCaps = [ 'edit_users', 'create_users' ];
184
-
185
- // If we're registered with Admin Access we don't modify anything
186
- if ( in_array( $userCap, $aRelevantCaps ) ) {
187
- $bBlockCapability = false;
188
-
189
- $req = Services::Request();
190
- $oWpUsers = Services::WpUsers();
191
-
192
- $oPostUser = false;
193
- $sPostUserlogin = $req->post( 'user_login' );
194
- if ( empty( $sPostUserlogin ) ) {
195
- $nPostUserId = $req->post( 'user_id' );
196
- if ( !empty( $nPostUserId ) ) {
197
- $oPostUser = $oWpUsers->getUserById( $nPostUserId );
198
- }
199
- }
200
- else {
201
- $oPostUser = $oWpUsers->getUserByUsername( $sPostUserlogin );
202
- }
203
-
204
- $sRequestRole = strtolower( $req->post( 'role', '' ) );
205
-
206
- if ( $oPostUser instanceof \WP_User ) {
207
- // editing an existing user other than yourself?
208
- if ( $oPostUser->user_login != $oWpUsers->getCurrentWpUsername() ) {
209
-
210
- if ( $oWpUsers->isUserAdmin( $oPostUser ) || ( $sRequestRole == 'administrator' ) ) {
211
- $bBlockCapability = true;
212
- }
213
- }
214
- }
215
- elseif ( $sRequestRole == 'administrator' ) { //creating a new admin user?
216
- $bBlockCapability = true;
217
- }
218
-
219
- if ( $bBlockCapability ) {
220
- $allCaps[ $userCap ] = false;
221
- }
222
- }
223
-
224
  return $allCaps;
225
  }
226
 
227
- protected function getUserPagesToRestrict() :array {
228
- return [
229
- /* 'user-new.php', */
230
- 'user-edit.php',
231
- 'users.php',
232
- ];
233
- }
234
-
235
  /**
236
- * Need to always re-test isPluginAdmin() because there's a dynamic filter in there to
237
- * permit saving by the plugin itself.
238
- *
239
- * Right before a plugin option is due to update it will check that we have permissions to do so
240
- * and if not, will * revert the option to save to the previous one.
241
- * @param mixed $mNewOptionValue
242
- * @param string $key
243
- * @param mixed $mOldValue
244
- * @return mixed
245
  */
246
  public function blockOptionsSaves( $mNewOptionValue, $key, $mOldValue ) {
247
-
248
- if ( !$this->getCon()->isPluginAdmin() && is_string( $key )
249
- && ( $this->isOptionForThisPlugin( $key ) || $this->isOptionRestricted( $key ) ) ) {
250
- $mNewOptionValue = $mOldValue;
251
- }
252
-
253
  return $mNewOptionValue;
254
  }
255
 
 
 
 
256
  private function isOptionForThisPlugin( string $key ) :bool {
257
  return preg_match( $this->getOptionRegexPattern(), $key ) > 0;
258
  }
259
 
 
 
 
260
  private function isOptionRestricted( string $key ) :bool {
261
  /** @var Options $opts */
262
  $opts = $this->getOptions();
@@ -269,33 +115,9 @@ class Processor extends BaseShield\Processor {
269
  * @param $cap
270
  * @param array $aArgs
271
  * @return array
 
272
  */
273
  public function disablePluginManipulation( $aAllCaps, $cap, $aArgs ) {
274
- /** @var Options $opts */
275
- $opts = $this->getOptions();
276
- $req = Services::Request();
277
-
278
- /** @var string $sRequestedCapability */
279
- $sRequestedCapability = $aArgs[ 0 ];
280
-
281
- // special case for plugin info thickbox for changelog
282
- $bIsChangelog = defined( 'IFRAME_REQUEST' )
283
- && ( $sRequestedCapability === 'install_plugins' )
284
- && ( $req->query( 'section' ) == 'changelog' )
285
- && $req->query( 'plugin' );
286
- if ( $bIsChangelog ) {
287
- return $aAllCaps;
288
- }
289
-
290
- $aEditCapabilities = [ 'activate_plugins', 'delete_plugins', 'install_plugins', 'update_plugins' ];
291
-
292
- if ( in_array( $sRequestedCapability, $aEditCapabilities ) ) {
293
- $aAreaRestrictions = $opts->getAdminAccessArea_Plugins();
294
- if ( in_array( $sRequestedCapability, $aAreaRestrictions ) ) {
295
- $aAllCaps[ $sRequestedCapability ] = false;
296
- }
297
- }
298
-
299
  return $aAllCaps;
300
  }
301
 
@@ -304,6 +126,7 @@ class Processor extends BaseShield\Processor {
304
  * @param $cap
305
  * @param array $aArgs
306
  * @return array
 
307
  */
308
  public function disableThemeManipulation( $aAllCaps, $cap, $aArgs ) {
309
  // If we're registered with Admin Access we don't modify anything
@@ -311,26 +134,6 @@ class Processor extends BaseShield\Processor {
311
  return $aAllCaps;
312
  }
313
 
314
- /** @var Options $opts */
315
- $opts = $this->getOptions();
316
-
317
- /** @var string $sRequestedCapability */
318
- $sRequestedCapability = $aArgs[ 0 ];
319
- $aEditCapabilities = [
320
- 'switch_themes',
321
- 'edit_theme_options',
322
- 'install_themes',
323
- 'update_themes',
324
- 'delete_themes'
325
- ];
326
-
327
- if ( in_array( $sRequestedCapability, $aEditCapabilities ) ) {
328
- $aAreaRestrictions = $opts->getAdminAccessArea_Themes();
329
- if ( in_array( $sRequestedCapability, $aAreaRestrictions ) ) {
330
- $aAllCaps[ $sRequestedCapability ] = false;
331
- }
332
- }
333
-
334
  return $aAllCaps;
335
  }
336
 
@@ -339,88 +142,31 @@ class Processor extends BaseShield\Processor {
339
  * @param $cap
340
  * @param array $args
341
  * @return array
 
342
  */
343
  public function disablePostsManipulation( $aAllCaps, $cap, $args ) {
344
- if ( $this->getCon()->isPluginAdmin() ) {
345
- return $aAllCaps;
346
- }
347
-
348
- /** @var Options $opts */
349
- $opts = $this->getOptions();
350
-
351
- /** @var string $sRequestedCapability */
352
- $sRequestedCapability = $args[ 0 ];
353
- $aEditCapabilities = [
354
- 'edit_post',
355
- 'publish_post',
356
- 'delete_post',
357
- 'edit_posts',
358
- 'publish_posts',
359
- 'delete_posts',
360
- 'edit_page',
361
- 'publish_page',
362
- 'delete_page',
363
- 'edit_pages',
364
- 'publish_pages',
365
- 'delete_pages'
366
- ];
367
- if ( in_array( $sRequestedCapability, $aEditCapabilities ) ) {
368
- $sRequestedCapabilityTrimmed = str_replace( [
369
- '_posts',
370
- '_pages',
371
- '_post',
372
- '_page'
373
- ], '', $sRequestedCapability ); //Order of items in this array is important!
374
- $aAreaRestrictions = $opts->getAdminAccessArea_Posts();
375
- if ( in_array( $sRequestedCapabilityTrimmed, $aAreaRestrictions ) ) {
376
- $aAllCaps[ $sRequestedCapability ] = false;
377
- }
378
- }
379
  return $aAllCaps;
380
  }
381
 
 
 
 
382
  private function getOptionRegexPattern() :string {
383
  return sprintf( '/^%s.*_options$/', $this->getCon()->getOptionStoragePrefix() );
384
  }
385
 
 
 
 
386
  public function printAdminAccessAjaxForm() {
387
- /** @var ModCon $mod */
388
- $mod = $this->getMod();
389
- /** @var Options $opts */
390
- $opts = $this->getOptions();
391
-
392
- $aRenderData = [
393
- 'flags' => [
394
- 'restrict_options' => $opts->getAdminAccessArea_Options()
395
- ],
396
- 'strings' => [
397
- 'editing_restricted' => __( 'Editing this option is currently restricted.', 'wp-simple-firewall' ),
398
- 'unlock_link' => $this->getUnlockLinkHtml(),
399
- ],
400
- 'js_snippets' => [
401
- 'options_to_restrict' => "'".implode( "','", $opts->getOptionsToRestrict() )."'",
402
- ],
403
- 'ajax' => [
404
- 'sec_admin_login_box' => $mod->getAjaxActionData( 'sec_admin_login_box', true )
405
- ]
406
- ];
407
- add_thickbox();
408
- echo $mod->renderTemplate( 'snippets/admin_access_login_box.php', $aRenderData );
409
  }
410
 
411
  /**
412
  * @param string $sLinkText
413
  * @return string
 
414
  */
415
  protected function getUnlockLinkHtml( $sLinkText = '' ) {
416
- if ( empty( $sLinkText ) ) {
417
- $sLinkText = __( 'Unlock', 'wp-simple-firewall' );
418
- }
419
- return sprintf(
420
- '<a href="%1$s" title="%2$s" class="thickbox">%3$s</a>',
421
- '#TB_inline?width=400&height=180&inlineId=WpsfAdminAccessLogin',
422
- __( 'Security Admin Login', 'wp-simple-firewall' ),
423
- $sLinkText
424
- );
425
  }
426
  }
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
 
6
 
7
  class Processor extends BaseShield\Processor {
8
 
9
  protected function run() {
10
+ /** @var ModCon $mod */
11
+ $mod = $this->getMod();
12
 
13
  /** @var Options $opts */
14
  $opts = $this->getOptions();
15
  if ( $opts->isEnabledWhitelabel() ) {
 
 
16
  $mod->getWhiteLabelController()->execute();
17
  }
18
+
19
+ $mod->getSecurityAdminController()->execute();
20
  }
21
 
22
  /**
23
  * @param bool $bHasPermission
24
  * @return bool
25
+ * @deprecated 11.1
26
  */
27
  public function adjustUserAdminPermissions( $bHasPermission = true ) :bool {
28
+ return $bHasPermission;
 
 
 
 
29
  }
30
 
31
  public function onWpInit() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  }
33
 
34
  /**
35
  * @param int $nUserId
36
  * @param string $sRole
37
+ * @deprecated 11.1
38
  */
39
  public function restrictAddUserRole( $nUserId, $sRole ) {
 
 
 
 
 
 
 
 
40
  }
41
 
42
  /**
43
  * @param int $nUserId
44
  * @param string $sRole
45
  * @param array $aOldRoles
46
+ * @deprecated 11.1
47
  */
48
  public function restrictSetUserRole( $nUserId, $sRole, $aOldRoles = [] ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  }
50
 
51
  /**
52
  * @param int $nUserId
53
  * @param string $sRole
54
+ * @deprecated 11.1
55
  */
56
  public function restrictRemoveUserRole( $nUserId, $sRole ) {
 
 
 
 
 
 
 
 
57
  }
58
 
59
  /**
60
  * @param int $nId
61
+ * @deprecated 11.1
62
  */
63
  public function restrictAdminUserDelete( $nId ) {
 
 
 
 
 
 
64
  }
65
 
66
  /**
67
  * @param array[] $roles
68
  * @return array[]
69
+ * @deprecated 11.1
70
  */
71
  public function restrictEditableRoles( $roles ) {
 
 
 
72
  return $roles;
73
  }
74
 
80
  * @param $cap
81
  * @param array $args
82
  * @return array
83
+ * @deprecated 11.1
84
  */
85
  public function restrictAdminUserChanges( $allCaps, $cap, $args ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  return $allCaps;
87
  }
88
 
 
 
 
 
 
 
 
 
89
  /**
90
+ * @deprecated 11.1
 
 
 
 
 
 
 
 
91
  */
92
  public function blockOptionsSaves( $mNewOptionValue, $key, $mOldValue ) {
 
 
 
 
 
 
93
  return $mNewOptionValue;
94
  }
95
 
96
+ /**
97
+ * @deprecated 11.1
98
+ */
99
  private function isOptionForThisPlugin( string $key ) :bool {
100
  return preg_match( $this->getOptionRegexPattern(), $key ) > 0;
101
  }
102
 
103
+ /**
104
+ * @deprecated 11.1
105
+ */
106
  private function isOptionRestricted( string $key ) :bool {
107
  /** @var Options $opts */
108
  $opts = $this->getOptions();
115
  * @param $cap
116
  * @param array $aArgs
117
  * @return array
118
+ * @deprecated 11.1
119
  */
120
  public function disablePluginManipulation( $aAllCaps, $cap, $aArgs ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  return $aAllCaps;
122
  }
123
 
126
  * @param $cap
127
  * @param array $aArgs
128
  * @return array
129
+ * @deprecated 11.1
130
  */
131
  public function disableThemeManipulation( $aAllCaps, $cap, $aArgs ) {
132
  // If we're registered with Admin Access we don't modify anything
134
  return $aAllCaps;
135
  }
136
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  return $aAllCaps;
138
  }
139
 
142
  * @param $cap
143
  * @param array $args
144
  * @return array
145
+ * @deprecated 11.1
146
  */
147
  public function disablePostsManipulation( $aAllCaps, $cap, $args ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  return $aAllCaps;
149
  }
150
 
151
+ /**
152
+ * @deprecated 11.1
153
+ */
154
  private function getOptionRegexPattern() :string {
155
  return sprintf( '/^%s.*_options$/', $this->getCon()->getOptionStoragePrefix() );
156
  }
157
 
158
+ /**
159
+ * @deprecated 11.1
160
+ */
161
  public function printAdminAccessAjaxForm() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  }
163
 
164
  /**
165
  * @param string $sLinkText
166
  * @return string
167
+ * @deprecated 11.1
168
  */
169
  protected function getUnlockLinkHtml( $sLinkText = '' ) {
170
+ return '';
 
 
 
 
 
 
 
 
171
  }
172
  }
src/lib/src/Modules/SecurityAdmin/Strings.php CHANGED
@@ -40,7 +40,7 @@ class Strings extends Base\Strings {
40
  ];
41
  break;
42
 
43
- case 'section_admin_access_restriction_settings' :
44
  $sTitle = __( 'Security Admin Restriction Settings', 'wp-simple-firewall' );
45
  $aSummary = [
46
  sprintf( '%s - %s', __( 'Purpose', 'wp-simple-firewall' ), __( 'Restricts access to this plugin preventing unauthorized changes to your security settings.', 'wp-simple-firewall' ) ),
@@ -196,7 +196,7 @@ class Strings extends Base\Strings {
196
  case 'whitelabel_enable' :
197
  $name = sprintf( '%s: %s', __( 'Enable', 'wp-simple-firewall' ), __( 'White Label', 'wp-simple-firewall' ) );
198
  $summary = __( 'Activate Your White Label Settings', 'wp-simple-firewall' );
199
- $description = __( 'Turn on/off the application of your White Label settings.', 'wp-simple-firewall' );
200
  break;
201
  case 'wl_hide_updates' :
202
  $name = __( 'Hide Updates', 'wp-simple-firewall' );
40
  ];
41
  break;
42
 
43
+ case 'section_security_admin_settings' :
44
  $sTitle = __( 'Security Admin Restriction Settings', 'wp-simple-firewall' );
45
  $aSummary = [
46
  sprintf( '%s - %s', __( 'Purpose', 'wp-simple-firewall' ), __( 'Restricts access to this plugin preventing unauthorized changes to your security settings.', 'wp-simple-firewall' ) ),
196
  case 'whitelabel_enable' :
197
  $name = sprintf( '%s: %s', __( 'Enable', 'wp-simple-firewall' ), __( 'White Label', 'wp-simple-firewall' ) );
198
  $summary = __( 'Activate Your White Label Settings', 'wp-simple-firewall' );
199
+ $description = __( 'Turn your White Label settings on/off.', 'wp-simple-firewall' );
200
  break;
201
  case 'wl_hide_updates' :
202
  $name = __( 'Hide Updates', 'wp-simple-firewall' );
src/lib/src/Modules/SecurityAdmin/UI.php CHANGED
@@ -14,7 +14,7 @@ class UI extends BaseShield\UI {
14
 
15
  switch ( $section ) {
16
  case 'section_whitelabel':
17
- if ( !$mod->isEnabledSecurityAdmin() ) {
18
  $warning[] = __( 'Please also supply a Security Admin PIN, as whitelabel settings are only applied when the Security Admin feature is active.', 'wp-simple-firewall' );
19
  }
20
  break;
@@ -26,6 +26,6 @@ class UI extends BaseShield\UI {
26
  public function isEnabledForUiSummary() :bool {
27
  /** @var ModCon $mod */
28
  $mod = $this->getMod();
29
- return $mod->isModuleEnabled() && $mod->isEnabledSecurityAdmin();
30
  }
31
  }
14
 
15
  switch ( $section ) {
16
  case 'section_whitelabel':
17
+ if ( !$mod->getSecurityAdminController()->isEnabledSecAdmin() ) {
18
  $warning[] = __( 'Please also supply a Security Admin PIN, as whitelabel settings are only applied when the Security Admin feature is active.', 'wp-simple-firewall' );
19
  }
20
  break;
26
  public function isEnabledForUiSummary() :bool {
27
  /** @var ModCon $mod */
28
  $mod = $this->getMod();
29
+ return $mod->getSecurityAdminController()->isEnabledSecAdmin();
30
  }
31
  }
src/lib/src/Modules/SecurityAdmin/WpCli/Pin.php CHANGED
@@ -3,7 +3,7 @@
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\WpCli;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\WpCli\BaseWpCliCmd;
6
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Lib\Actions;
7
  use WP_CLI;
8
 
9
  class Pin extends BaseWpCliCmd {
@@ -51,14 +51,14 @@ class Pin extends BaseWpCliCmd {
51
  }
52
 
53
  if ( $isRemove ) {
54
- ( new Actions\RemoveSecAdmin() )
55
  ->setMod( $this->getMod() )
56
  ->remove();
57
  WP_CLI::success( __( 'Security admin pin removed.', 'wp-simple-firewall' ) );
58
  }
59
  else {
60
  try {
61
- ( new Actions\SetSecAdminPin() )
62
  ->setMod( $this->getMod() )
63
  ->run( $newPIN );
64
  WP_CLI::success(
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\WpCli;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\WpCli\BaseWpCliCmd;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Lib\SecurityAdmin\Ops;
7
  use WP_CLI;
8
 
9
  class Pin extends BaseWpCliCmd {
51
  }
52
 
53
  if ( $isRemove ) {
54
+ ( new Ops\RemoveSecAdmin() )
55
  ->setMod( $this->getMod() )
56
  ->remove();
57
  WP_CLI::success( __( 'Security admin pin removed.', 'wp-simple-firewall' ) );
58
  }
59
  else {
60
  try {
61
+ ( new Ops\SetSecAdminPin() )
62
  ->setMod( $this->getMod() )
63
  ->run( $newPIN );
64
  WP_CLI::success(
src/lib/src/Modules/Sessions/ModCon.php CHANGED
@@ -22,8 +22,7 @@ class ModCon extends BaseShield\ModCon {
22
  }
23
 
24
  public function getDbHandler_Sessions() :Databases\Session\Handler {
25
- $new = $this->getDbH( 'sessions' );
26
- return empty( $new ) ? $this->getDbH( 'session' ) : $new;
27
  }
28
 
29
  public function isAutoAddSessions() :bool {
22
  }
23
 
24
  public function getDbHandler_Sessions() :Databases\Session\Handler {
25
+ return $this->getDbH( 'sessions' );
 
26
  }
27
 
28
  public function isAutoAddSessions() :bool {
src/lib/src/Modules/Traffic/UI.php CHANGED
@@ -74,14 +74,4 @@ class UI extends BaseShield\UI {
74
 
75
  return $warning;
76
  }
77
-
78
- protected function getSettingsRelatedLinks() :array {
79
- $modInsights = $this->getCon()->getModule_Insights();
80
- return [
81
- [
82
- 'href' => $modInsights->getUrl_SubInsightsPage( 'traffic' ),
83
- 'title' => __( 'Traffic Log', 'wp-simple-firewall' ),
84
- ]
85
- ];
86
- }
87
  }
74
 
75
  return $warning;
76
  }
 
 
 
 
 
 
 
 
 
 
77
  }
src/lib/src/Modules/UserManagement/Lib/Registration/EmailValidate.php CHANGED
@@ -61,7 +61,7 @@ class EmailValidate {
61
  }
62
 
63
  if ( !empty( $sInvalidBecause ) ) {
64
- $sOpt = $opts->getValidateEmailOnRegistration();
65
  $this->getCon()->fireEvent(
66
  'reg_email_invalid',
67
  [
@@ -69,12 +69,12 @@ class EmailValidate {
69
  'email' => sanitize_email( $email ),
70
  'reason' => sanitize_key( $sInvalidBecause ),
71
  ],
72
- 'offense_count' => $sOpt == 'log' ? 0 : 1,
73
- 'block' => $sOpt == 'block',
74
  ]
75
  );
76
 
77
- if ( $sOpt == 'block' ) {
78
  wp_die( 'Attempted user registration with invalid email address has been blocked.' );
79
  }
80
  }
61
  }
62
 
63
  if ( !empty( $sInvalidBecause ) ) {
64
+ $opt = $opts->getValidateEmailOnRegistration();
65
  $this->getCon()->fireEvent(
66
  'reg_email_invalid',
67
  [
69
  'email' => sanitize_email( $email ),
70
  'reason' => sanitize_key( $sInvalidBecause ),
71
  ],
72
+ 'offense_count' => $opt == 'log' ? 0 : 1,
73
+ 'block' => $opt == 'block',
74
  ]
75
  );
76
 
77
+ if ( $opt == 'block' ) {
78
  wp_die( 'Attempted user registration with invalid email address has been blocked.' );
79
  }
80
  }
src/lib/src/Modules/UserManagement/UI.php CHANGED
@@ -34,23 +34,7 @@ class UI extends BaseShield\UI {
34
  'vars' => [
35
  'unique_ips' => $dbSel->getDistinctIps(),
36
  'unique_users' => $dbSel->getDistinctUsernames(),
37
- 'related_hrefs' => [
38
- [
39
- 'href' => $con->getModule_UserManagement()->getUrl_AdminPage(),
40
- 'title' => __( 'User Settings', 'wp-simple-firewall' ),
41
- ]
42
- ]
43
  ],
44
  ];
45
  }
46
-
47
- protected function getSettingsRelatedLinks() :array {
48
- $modInsights = $this->getCon()->getModule_Insights();
49
- return [
50
- [
51
- 'href' => $modInsights->getUrl_SubInsightsPage( 'users' ),
52
- 'title' => __( 'User Sessions', 'wp-simple-firewall' ),
53
- ]
54
- ];
55
- }
56
  }
34
  'vars' => [
35
  'unique_ips' => $dbSel->getDistinctIps(),
36
  'unique_users' => $dbSel->getDistinctUsernames(),
 
 
 
 
 
 
37
  ],
38
  ];
39
  }
 
 
 
 
 
 
 
 
 
 
40
  }
src/lib/src/Scans/Base/Table/BaseEntryFormatter.php CHANGED
@@ -15,15 +15,12 @@ abstract class BaseEntryFormatter {
15
  use Scan\Controller\ScanControllerConsumer;
16
  use ModConsumer;
17
 
18
- /**
19
- * @return array
20
- */
21
- abstract public function format();
22
 
23
  /**
24
  * @return string[]
25
  */
26
- protected function getSupportedActions() {
27
  return [
28
  'ignore'
29
  ];
@@ -32,7 +29,7 @@ abstract class BaseEntryFormatter {
32
  /**
33
  * @return array[]
34
  */
35
- protected function getActionDefinitions() {
36
  return [
37
  'ignore' => [
38
  'text' => __( 'Ignore', 'wp-simple-firewall' ),
@@ -57,10 +54,7 @@ abstract class BaseEntryFormatter {
57
  ];
58
  }
59
 
60
- /**
61
- * @return array
62
- */
63
- protected function getBaseData() {
64
  return $this->getEntryVO()->getRawData();
65
  }
66
 
@@ -74,15 +68,15 @@ abstract class BaseEntryFormatter {
74
  }
75
 
76
  /**
77
- * @param int $nTimestamp
78
  * @return string
79
  */
80
- protected function formatTimestampField( $nTimestamp ) {
81
  return Services::Request()
82
  ->carbon()
83
- ->setTimestamp( $nTimestamp )
84
  ->diffForHumans()
85
  .'<br/><span class="timestamp-small">'
86
- .Services::WpGeneral()->getTimeStringForDisplay( $nTimestamp ).'</span>';
87
  }
88
  }
15
  use Scan\Controller\ScanControllerConsumer;
16
  use ModConsumer;
17
 
18
+ abstract public function format() :array;
 
 
 
19
 
20
  /**
21
  * @return string[]
22
  */
23
+ protected function getSupportedActions() :array {
24
  return [
25
  'ignore'
26
  ];
29
  /**
30
  * @return array[]
31
  */
32
+ protected function getActionDefinitions() :array {
33
  return [
34
  'ignore' => [
35
  'text' => __( 'Ignore', 'wp-simple-firewall' ),
54
  ];
55
  }
56
 
57
+ protected function getBaseData() :array {
 
 
 
58
  return $this->getEntryVO()->getRawData();
59
  }
60
 
68
  }
69
 
70
  /**
71
+ * @param int $ts
72
  * @return string
73
  */
74
+ protected function formatTimestampField( $ts ) {
75
  return Services::Request()
76
  ->carbon()
77
+ ->setTimestamp( $ts )
78
  ->diffForHumans()
79
  .'<br/><span class="timestamp-small">'
80
+ .Services::WpGeneral()->getTimeStringForDisplay( $ts ).'</span>';
81
  }
82
  }
src/lib/src/Scans/Base/Table/BaseFileEntryFormatter.php CHANGED
@@ -8,45 +8,42 @@ use FernleafSystems\Wordpress\Services\Services;
8
 
9
  abstract class BaseFileEntryFormatter extends BaseEntryFormatter {
10
 
11
- /**
12
- * @return array
13
- */
14
- protected function getBaseData() {
15
- $aData = parent::getBaseData();
16
  $item = $this->getResultItem();
17
- $aData[ 'explanation' ] = $this->getExplanation();
18
- $aData[ 'path' ] = $item->path_fragment;
19
- $aData[ 'path_relabs' ] = Services::WpFs()->getPathRelativeToAbsPath( $item->path_full );
20
- $aData[ 'path_details' ] = [];
21
- $aData[ 'created_at' ] = $this->formatTimestampField( $this->getEntryVO()->created_at );
22
- $aData[ 'custom_row' ] = false;
23
 
24
- $aActionDefs = array_intersect_key(
25
  $this->getActionDefinitions(),
26
  array_flip( array_unique( $this->getSupportedActions() ) )
27
  );
28
- foreach ( $aActionDefs as $sKey => $aActionDef ) {
29
- $aActionDefs[ $sKey ][ 'data' ] = array_merge(
30
- $aActionDef[ 'data' ],
31
  [
32
  'rid' => $this->getEntryVO()->id,
33
- 'item_action' => $sKey,
34
  ]
35
  );
36
- $aActionDefs[ $sKey ][ 'classes' ] = array_merge(
37
- $aActionDef[ 'classes' ],
38
  [ 'action', 'item_action' ]
39
  );
40
  }
41
- $aData[ 'actions' ] = $aActionDefs;
42
 
43
- return $aData;
44
  }
45
 
46
  /**
47
  * @return array[]
48
  */
49
- protected function getActionDefinitions() {
50
  return [
51
  'ignore' => [
52
  'text' => sprintf( __( 'Ignore %s', 'wp-simple-firewall' ), __( 'File', 'wp-simple-firewall' ) ),
@@ -74,7 +71,7 @@ abstract class BaseFileEntryFormatter extends BaseEntryFormatter {
74
  /**
75
  * @return string[]
76
  */
77
- protected function getExplanation() {
78
  return [];
79
  }
80
  }
8
 
9
  abstract class BaseFileEntryFormatter extends BaseEntryFormatter {
10
 
11
+ protected function getBaseData() :array {
12
+ $data = parent::getBaseData();
 
 
 
13
  $item = $this->getResultItem();
14
+ $data[ 'explanation' ] = $this->getExplanation();
15
+ $data[ 'path' ] = $item->path_fragment;
16
+ $data[ 'path_relabs' ] = Services::WpFs()->getPathRelativeToAbsPath( $item->path_full );
17
+ $data[ 'path_details' ] = [];
18
+ $data[ 'created_at' ] = $this->formatTimestampField( $this->getEntryVO()->created_at );
19
+ $data[ 'custom_row' ] = false;
20
 
21
+ $actionDefs = array_intersect_key(
22
  $this->getActionDefinitions(),
23
  array_flip( array_unique( $this->getSupportedActions() ) )
24
  );
25
+ foreach ( $actionDefs as $key => $actionDef ) {
26
+ $actionDefs[ $key ][ 'data' ] = array_merge(
27
+ $actionDef[ 'data' ],
28
  [
29
  'rid' => $this->getEntryVO()->id,
30
+ 'item_action' => $key,
31
  ]
32
  );
33
+ $actionDefs[ $key ][ 'classes' ] = array_merge(
34
+ $actionDef[ 'classes' ],
35
  [ 'action', 'item_action' ]
36
  );
37
  }
38
+ $data[ 'actions' ] = $actionDefs;
39
 
40
+ return $data;
41
  }
42
 
43
  /**
44
  * @return array[]
45
  */
46
+ protected function getActionDefinitions() :array {
47
  return [
48
  'ignore' => [
49
  'text' => sprintf( __( 'Ignore %s', 'wp-simple-firewall' ), __( 'File', 'wp-simple-firewall' ) ),
71
  /**
72
  * @return string[]
73
  */
74
+ protected function getExplanation() :array {
75
  return [];
76
  }
77
  }
src/lib/src/Scans/Mal/Table/EntryFormatter.php CHANGED
@@ -8,49 +8,45 @@ use FernleafSystems\Wordpress\Plugin\Shield\Scans\Mal;
8
 
9
  class EntryFormatter extends BaseFileEntryFormatter {
10
 
11
- /**
12
- * @return array
13
- */
14
- public function format() {
15
- $aE = $this->getBaseData();
16
- $aE[ 'status' ] = __( 'Potential Malware Detected', 'wp-simple-firewall' );
17
- if ( !array_key_exists( 'repair', $aE[ 'actions' ] ) ) {
18
- $aE[ 'explanation' ][] = __( 'Repair Unavailable', 'wp-simple-firewall' );
19
  }
20
-
21
- return $aE;
22
  }
23
 
24
  /**
25
  * @return string[]
26
  */
27
- protected function getExplanation() {
28
- /** @var Mal\ResultItem $oIt */
29
- $oIt = $this->getResultItem();
30
 
31
- $aExpl = [
32
- sprintf( '%s: %s', __( 'Pattern Detected' ), $this->getPatternForDisplay( base64_decode( $oIt->mal_sig ) ) ),
33
  sprintf( '%s: %s', __( 'Affected line numbers' ),
34
  implode( ', ', array_map(
35
  function ( $nLineNumber ) {
36
  return $nLineNumber + 1;
37
  },
38
- $oIt->file_lines // because lines start at ZERO
39
  ) )
40
  ),
41
  ];
42
 
43
- /** @var HackGuard\Options $oOpts */
44
- $oOpts = $this->getOptions();
45
- if ( $oOpts->isMalUseNetworkIntelligence() ) {
46
- $aExpl[] = sprintf( '%s: %s/100 [%s]',
47
  __( 'Likelihood That This Is A False Positive' ),
48
- sprintf( '<strong>%s</strong>', (int)$oIt->fp_confidence ),
49
  sprintf( '<a href="%s" target="_blank">%s</a>', 'https://shsec.io/isthismalware', __( 'more info', 'wp-simple-firewall' ) )
50
  );
51
  }
52
 
53
- return $aExpl;
54
  }
55
 
56
  /**
@@ -79,7 +75,7 @@ class EntryFormatter extends BaseFileEntryFormatter {
79
  /**
80
  * @inheritDoc
81
  */
82
- protected function getSupportedActions() {
83
  $actions = parent::getSupportedActions();
84
 
85
  /** @var Mal\ResultItem $item */
8
 
9
  class EntryFormatter extends BaseFileEntryFormatter {
10
 
11
+ public function format() :array {
12
+ $e = $this->getBaseData();
13
+ $e[ 'status' ] = __( 'Potential Malware Detected', 'wp-simple-firewall' );
14
+ if ( !array_key_exists( 'repair', $e[ 'actions' ] ) ) {
15
+ $e[ 'explanation' ][] = __( 'Repair Unavailable', 'wp-simple-firewall' );
 
 
 
16
  }
17
+ return $e;
 
18
  }
19
 
20
  /**
21
  * @return string[]
22
  */
23
+ protected function getExplanation() :array {
24
+ /** @var Mal\ResultItem $item */
25
+ $item = $this->getResultItem();
26
 
27
+ $expl = [
28
+ sprintf( '%s: %s', __( 'Pattern Detected' ), $this->getPatternForDisplay( base64_decode( $item->mal_sig ) ) ),
29
  sprintf( '%s: %s', __( 'Affected line numbers' ),
30
  implode( ', ', array_map(
31
  function ( $nLineNumber ) {
32
  return $nLineNumber + 1;
33
  },
34
+ $item->file_lines // because lines start at ZERO
35
  ) )
36
  ),
37
  ];
38
 
39
+ /** @var HackGuard\Options $opts */
40
+ $opts = $this->getOptions();
41
+ if ( $opts->isMalUseNetworkIntelligence() ) {
42
+ $expl[] = sprintf( '%s: %s/100 [%s]',
43
  __( 'Likelihood That This Is A False Positive' ),
44
+ sprintf( '<strong>%s</strong>', (int)$item->fp_confidence ),
45
  sprintf( '<a href="%s" target="_blank">%s</a>', 'https://shsec.io/isthismalware', __( 'more info', 'wp-simple-firewall' ) )
46
  );
47
  }
48
 
49
+ return $expl;
50
  }
51
 
52
  /**
75
  /**
76
  * @inheritDoc
77
  */
78
+ protected function getSupportedActions() :array {
79
  $actions = parent::getSupportedActions();
80
 
81
  /** @var Mal\ResultItem $item */
src/lib/src/Scans/Ptg/Table/EntryFormatter.php CHANGED
@@ -8,63 +8,57 @@ use FernleafSystems\Wordpress\Services\Services;
8
 
9
  class EntryFormatter extends BaseFileEntryFormatter {
10
 
11
- /**
12
- * @return array
13
- */
14
- protected function getBaseData() {
15
- $aData = parent::getBaseData();
16
- /** @var Ptg\ResultItem $oIt */
17
- $oIt = $this->getResultItem();
18
-
19
- if ( $oIt->context == 'plugins' ) {
20
- $oAsset = Services::WpPlugins()->getPluginAsVo( $oIt->slug );
21
- if ( !empty( $oAsset ) ) {
22
- $aData[ 'path_details' ][] = sprintf( '%s: %s v%s',
23
- __( 'Plugin', 'wp-simple-firewall' ), $oAsset->Name, $oAsset->version );
24
  }
25
  }
26
  else {
27
- $oAsset = Services::WpThemes()->getThemeAsVo( $oIt->slug );
28
- if ( !empty( $oAsset ) ) {
29
- $aData[ 'path_details' ][] = sprintf( '%s: %s v%s',
30
- __( 'Theme', 'wp-simple-firewall' ), $oAsset->wp_theme->get( 'Name' ), $oAsset->version );
31
  }
32
  }
33
 
34
- return $aData;
35
  }
36
 
37
- /**
38
- * @return array
39
- */
40
- public function format() {
41
- /** @var Ptg\ResultItem $oIt */
42
- $oIt = $this->getResultItem();
43
-
44
- $aE = $this->getBaseData();
45
- $aE[ 'status' ] = $oIt->is_different ? __( 'Modified', 'wp-simple-firewall' )
46
- : ( $oIt->is_missing ? __( 'Missing', 'wp-simple-firewall' ) : __( 'Unrecognised', 'wp-simple-firewall' ) );
47
- return $aE;
48
  }
49
 
50
  /**
51
  * @inheritDoc
52
  */
53
- protected function getActionDefinitions() {
54
- /** @var Ptg\ResultItem $oIt */
55
- $oIt = $this->getResultItem();
56
- $sAssetType = ( $oIt->context == 'plugins' ? __( 'Plugin', 'wp-simple-firewall' ) : __( 'Theme', 'wp-simple-firewall' ) );
57
  return array_merge(
58
  parent::getActionDefinitions(),
59
  [
60
  'asset_accept' => [
61
- 'text' => sprintf( __( 'Accept %s', 'wp-simple-firewall' ), $sAssetType ),
62
- 'title' => sprintf( __( 'Accept all current scan results for this %s.' ), $sAssetType ),
63
  'classes' => [ 'asset_accept' ],
64
  'data' => [],
65
  ],
66
  'asset_reinstall' => [
67
- 'text' => sprintf( __( 'Re-Install %s', 'wp-simple-firewall' ), $sAssetType ),
68
  'classes' => [ 'asset_reinstall' ],
69
  'data' => []
70
  ],
@@ -75,12 +69,12 @@ class EntryFormatter extends BaseFileEntryFormatter {
75
  /**
76
  * @return string[]
77
  */
78
- protected function getExplanation() {
79
- /** @var Ptg\ResultItem $oIt */
80
- $oIt = $this->getResultItem();
81
 
82
- if ( $oIt->is_different ) {
83
- $aExpl = [
84
  __( "This file appears to have been modified from its original content.", 'wp-simple-firewall' )
85
  .' '.__( "This may be okay if you're editing files directly on your site.", 'wp-simple-firewall' ),
86
  __( "You may want to download it to ensure that the contents are as you expect.", 'wp-simple-firewall' )
@@ -88,8 +82,8 @@ class EntryFormatter extends BaseFileEntryFormatter {
88
  __( 'Ignore', 'wp-simple-firewall' ) ),
89
  ];
90
  }
91
- elseif ( $oIt->is_missing ) {
92
- $aExpl = [
93
  __( "This file appears to have been removed from your site.", 'wp-simple-firewall' )
94
  .' '.__( "This may be okay if you're editing files directly on your site.", 'wp-simple-firewall' ),
95
  __( "If you're unsure, you should check whether this is okay.", 'wp-simple-firewall' )
@@ -98,7 +92,7 @@ class EntryFormatter extends BaseFileEntryFormatter {
98
  ];
99
  }
100
  else {
101
- $aExpl = [
102
  __( "This file appears to have been added to your site.", 'wp-simple-firewall' ),
103
  __( "This is not normal in the vast majority of cases.", 'wp-simple-firewall' ),
104
  __( "You may want to download it to ensure that the contents are what you expect.", 'wp-simple-firewall' )
@@ -107,51 +101,51 @@ class EntryFormatter extends BaseFileEntryFormatter {
107
  ];
108
  }
109
 
110
- return $aExpl;
111
  }
112
 
113
  /**
114
  * @inheritDoc
115
  */
116
- protected function getSupportedActions() {
117
- /** @var Ptg\ResultItem $oIt */
118
- $oIt = $this->getResultItem();
119
 
120
- $aExtras = [
121
  'asset_accept'
122
  ];
123
 
124
- if ( $oIt->context == 'plugins' ) {
125
- $oAsset = Services::WpPlugins()->getPluginAsVo( $oIt->slug );
126
  }
127
  else {
128
- $oAsset = Services::WpThemes()->getThemeAsVo( $oIt->slug );
129
  }
130
 
131
- $bCanRepair = ( new Ptg\Utilities\Repair() )
132
- ->setScanItem( $oIt )
133
  ->canRepair();
134
- $bHasUpdate = $oAsset->hasUpdate();
135
 
136
- if ( $bHasUpdate ) {
137
- $aExtras[] = 'update';
138
  }
139
 
140
- if ( $oIt->is_unrecognised ) {
141
- $aExtras[] = 'delete';
142
  }
143
- elseif ( $bCanRepair ) {
144
- $aExtras[] = 'repair';
145
  }
146
 
147
- if ( $bCanRepair && !$bHasUpdate ) {
148
- $aExtras[] = 'asset_reinstall';
149
  }
150
 
151
- if ( !$oIt->is_missing ) {
152
- $aExtras[] = 'download';
153
  }
154
 
155
- return array_merge( parent::getSupportedActions(), $aExtras );
156
  }
157
  }
8
 
9
  class EntryFormatter extends BaseFileEntryFormatter {
10
 
11
+ protected function getBaseData() :array {
12
+ $data = parent::getBaseData();
13
+ /** @var Ptg\ResultItem $item */
14
+ $item = $this->getResultItem();
15
+
16
+ if ( $item->context == 'plugins' ) {
17
+ $asset = Services::WpPlugins()->getPluginAsVo( $item->slug );
18
+ if ( !empty( $asset ) ) {
19
+ $data[ 'path_details' ][] = sprintf( '%s: %s v%s',
20
+ __( 'Plugin', 'wp-simple-firewall' ), $asset->Name, $asset->version );
 
 
 
21
  }
22
  }
23
  else {
24
+ $asset = Services::WpThemes()->getThemeAsVo( $item->slug );
25
+ if ( !empty( $asset ) ) {
26
+ $data[ 'path_details' ][] = sprintf( '%s: %s v%s',
27
+ __( 'Theme', 'wp-simple-firewall' ), $asset->wp_theme->get( 'Name' ), $asset->version );
28
  }
29
  }
30
 
31
+ return $data;
32
  }
33
 
34
+ public function format() :array {
35
+ /** @var Ptg\ResultItem $item */
36
+ $item = $this->getResultItem();
37
+
38
+ $e = $this->getBaseData();
39
+ $e[ 'status' ] = $item->is_different ? __( 'Modified', 'wp-simple-firewall' )
40
+ : ( $item->is_missing ? __( 'Missing', 'wp-simple-firewall' ) : __( 'Unrecognised', 'wp-simple-firewall' ) );
41
+ return $e;
 
 
 
42
  }
43
 
44
  /**
45
  * @inheritDoc
46
  */
47
+ protected function getActionDefinitions() :array {
48
+ /** @var Ptg\ResultItem $item */
49
+ $item = $this->getResultItem();
50
+ $assetType = ( $item->context == 'plugins' ? __( 'Plugin', 'wp-simple-firewall' ) : __( 'Theme', 'wp-simple-firewall' ) );
51
  return array_merge(
52
  parent::getActionDefinitions(),
53
  [
54
  'asset_accept' => [
55
+ 'text' => sprintf( __( 'Accept %s', 'wp-simple-firewall' ), $assetType ),
56
+ 'title' => sprintf( __( 'Accept all current scan results for this %s.' ), $assetType ),
57
  'classes' => [ 'asset_accept' ],
58
  'data' => [],
59
  ],
60
  'asset_reinstall' => [
61
+ 'text' => sprintf( __( 'Re-Install %s', 'wp-simple-firewall' ), $assetType ),
62
  'classes' => [ 'asset_reinstall' ],
63
  'data' => []
64
  ],
69
  /**
70
  * @return string[]
71
  */
72
+ protected function getExplanation() :array {
73
+ /** @var Ptg\ResultItem $item */
74
+ $item = $this->getResultItem();
75
 
76
+ if ( $item->is_different ) {
77
+ $expl = [
78
  __( "This file appears to have been modified from its original content.", 'wp-simple-firewall' )
79
  .' '.__( "This may be okay if you're editing files directly on your site.", 'wp-simple-firewall' ),
80
  __( "You may want to download it to ensure that the contents are as you expect.", 'wp-simple-firewall' )
82
  __( 'Ignore', 'wp-simple-firewall' ) ),
83
  ];
84
  }
85
+ elseif ( $item->is_missing ) {
86
+ $expl = [
87
  __( "This file appears to have been removed from your site.", 'wp-simple-firewall' )
88
  .' '.__( "This may be okay if you're editing files directly on your site.", 'wp-simple-firewall' ),
89
  __( "If you're unsure, you should check whether this is okay.", 'wp-simple-firewall' )
92
  ];
93
  }
94
  else {
95
+ $expl = [
96
  __( "This file appears to have been added to your site.", 'wp-simple-firewall' ),
97
  __( "This is not normal in the vast majority of cases.", 'wp-simple-firewall' ),
98
  __( "You may want to download it to ensure that the contents are what you expect.", 'wp-simple-firewall' )
101
  ];
102
  }
103
 
104
+ return $expl;
105
  }
106
 
107
  /**
108
  * @inheritDoc
109
  */
110
+ protected function getSupportedActions() :array {
111
+ /** @var Ptg\ResultItem $item */
112
+ $item = $this->getResultItem();
113
 
114
+ $extras = [
115
  'asset_accept'
116
  ];
117
 
118
+ if ( $item->context == 'plugins' ) {
119
+ $asset = Services::WpPlugins()->getPluginAsVo( $item->slug );
120
  }
121
  else {
122
+ $asset = Services::WpThemes()->getThemeAsVo( $item->slug );
123
  }
124
 
125
+ $canRepair = ( new Ptg\Utilities\Repair() )
126
+ ->setScanItem( $item )
127
  ->canRepair();
128
+ $hasUpdate = $asset->hasUpdate();
129
 
130
+ if ( $hasUpdate ) {
131
+ $extras[] = 'update';
132
  }
133
 
134
+ if ( $item->is_unrecognised ) {
135
+ $extras[] = 'delete';
136
  }
137
+ elseif ( $canRepair ) {
138
+ $extras[] = 'repair';
139
  }
140
 
141
+ if ( $canRepair && !$hasUpdate ) {
142
+ $extras[] = 'asset_reinstall';
143
  }
144
 
145
+ if ( !$item->is_missing ) {
146
+ $extras[] = 'download';
147
  }
148
 
149
+ return array_merge( parent::getSupportedActions(), $extras );
150
  }
151
  }
src/lib/src/Scans/Ufc/BuildScanAction.php CHANGED
@@ -19,13 +19,13 @@ class BuildScanAction extends Shield\Scans\Base\BaseBuildScanAction {
19
  }
20
 
21
  protected function setCustomFields() {
22
- /** @var ScanActionVO $oAction */
23
- $oAction = $this->getScanActionVO();
24
- /** @var Shield\Modules\HackGuard\Options $oOpts */
25
- $oOpts = $this->getOptions();
26
 
27
- $aExcls = $oOpts->getOpt( 'ufc_exclusions', [] );
28
- $oAction->exclusions = is_array( $aExcls ) ? $aExcls : [];
29
- $oAction->scan_dirs = $oOpts->getUfcScanDirectories();
30
  }
31
  }
19
  }
20
 
21
  protected function setCustomFields() {
22
+ /** @var ScanActionVO $action */
23
+ $action = $this->getScanActionVO();
24
+ /** @var Shield\Modules\HackGuard\Options $opts */
25
+ $opts = $this->getOptions();
26
 
27
+ $exclusions = $opts->getOpt( 'ufc_exclusions', [] );
28
+ $action->exclusions = is_array( $exclusions ) ? $exclusions : [];
29
+ $action->scan_dirs = $opts->getUfcScanDirectories();
30
  }
31
  }
src/lib/src/Scans/Ufc/FileScanner.php CHANGED
@@ -5,10 +5,6 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Ufc;
5
  use FernleafSystems\Wordpress\Plugin\Shield;
6
  use FernleafSystems\Wordpress\Services\Services;
7
 
8
- /**
9
- * Class FileScanner
10
- * @package FernleafSystems\Wordpress\Plugin\Shield\Scans\Ufc
11
- */
12
  class FileScanner extends Shield\Scans\Base\Files\BaseFileScanner {
13
 
14
  /**
@@ -29,38 +25,34 @@ class FileScanner extends Shield\Scans\Base\Files\BaseFileScanner {
29
  return $item;
30
  }
31
 
32
- /**
33
- * @param string $sFullPath
34
- * @return bool
35
- */
36
- private function isExcluded( $sFullPath ) {
37
- /** @var ScanActionVO $oAction */
38
- $oAction = $this->getScanActionVO();
39
 
40
- $sFilePath = wp_normalize_path( $sFullPath );
41
- $sFileName = basename( $sFilePath );
42
 
43
- $bExcluded = false;
44
 
45
- foreach ( $oAction->exclusions as $sExclusion ) {
46
 
47
- if ( preg_match( '/^#(.+)#[a-z]*$/i', $sExclusion, $aMatches ) ) { // it's regex
48
- $bExcluded = @preg_match( stripslashes( $sExclusion ), $sFilePath );
49
  }
50
  else {
51
- $sExclusion = wp_normalize_path( $sExclusion );
52
- if ( strpos( $sExclusion, '/' ) === false ) { // filename only
53
- $bExcluded = ( $sFileName == $sExclusion );
54
  }
55
  else {
56
- $bExcluded = strpos( $sFilePath, $sExclusion );
57
  }
58
  }
59
 
60
- if ( $bExcluded ) {
61
  break;
62
  }
63
  }
64
- return (bool)$bExcluded;
65
  }
66
  }
5
  use FernleafSystems\Wordpress\Plugin\Shield;
6
  use FernleafSystems\Wordpress\Services\Services;
7
 
 
 
 
 
8
  class FileScanner extends Shield\Scans\Base\Files\BaseFileScanner {
9
 
10
  /**
25
  return $item;
26
  }
27
 
28
+ private function isExcluded( string $fullPath ) :bool {
29
+ /** @var ScanActionVO $action */
30
+ $action = $this->getScanActionVO();
 
 
 
 
31
 
32
+ $path = wp_normalize_path( $fullPath );
33
+ $filename = basename( $path );
34
 
35
+ $excluded = false;
36
 
37
+ foreach ( $action->exclusions as $exclusion ) {
38
 
39
+ if ( preg_match( '/^#(.+)#[a-z]*$/i', $exclusion, $aMatches ) ) { // it's regex
40
+ $excluded = @preg_match( stripslashes( $exclusion ), $path );
41
  }
42
  else {
43
+ $exclusion = wp_normalize_path( $exclusion );
44
+ if ( strpos( $exclusion, '/' ) === false ) { // filename only
45
+ $excluded = $filename === $exclusion;
46
  }
47
  else {
48
+ $excluded = strpos( $path, $exclusion ) !== false;
49
  }
50
  }
51
 
52
+ if ( $excluded ) {
53
  break;
54
  }
55
  }
56
+ return (bool)$excluded;
57
  }
58
  }
src/lib/src/Scans/Ufc/Table/EntryFormatter.php CHANGED
@@ -6,19 +6,16 @@ use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\Table\BaseFileEntryFormat
6
 
7
  class EntryFormatter extends BaseFileEntryFormatter {
8
 
9
- /**
10
- * @return array
11
- */
12
- public function format() {
13
- $aE = $this->getBaseData();
14
- $aE[ 'status' ] = __( 'Unrecognised', 'wp-simple-firewall' );
15
- return $aE;
16
  }
17
 
18
  /**
19
  * @return string[]
20
  */
21
- protected function getExplanation() {
22
  return [
23
  __( 'This file was discovered within one of your core WordPress directories.', 'wp-simple-firewall' ),
24
  __( "But it isn't part of the official WordPress distribution for this version.", 'wp-simple-firewall' ),
@@ -31,7 +28,7 @@ class EntryFormatter extends BaseFileEntryFormatter {
31
  /**
32
  * @inheritDoc
33
  */
34
- protected function getSupportedActions() {
35
  return array_merge( parent::getSupportedActions(), [ 'delete', 'download' ] );
36
  }
37
  }
6
 
7
  class EntryFormatter extends BaseFileEntryFormatter {
8
 
9
+ public function format() :array {
10
+ $e = $this->getBaseData();
11
+ $e[ 'status' ] = __( 'Unrecognised', 'wp-simple-firewall' );
12
+ return $e;
 
 
 
13
  }
14
 
15
  /**
16
  * @return string[]
17
  */
18
+ protected function getExplanation() :array {
19
  return [
20
  __( 'This file was discovered within one of your core WordPress directories.', 'wp-simple-firewall' ),
21
  __( "But it isn't part of the official WordPress distribution for this version.", 'wp-simple-firewall' ),
28
  /**
29
  * @inheritDoc
30
  */
31
+ protected function getSupportedActions() :array {
32
  return array_merge( parent::getSupportedActions(), [ 'delete', 'download' ] );
33
  }
34
  }
src/lib/src/Scans/Wcf/Table/EntryFormatter.php CHANGED
@@ -7,20 +7,17 @@ use FernleafSystems\Wordpress\Plugin\Shield\Scans\Wcf\ResultItem;
7
 
8
  class EntryFormatter extends BaseFileEntryFormatter {
9
 
10
- /**
11
- * @return array
12
- */
13
- public function format() {
14
- /** @var ResultItem $oIt */
15
- $oIt = $this->getResultItem();
16
 
17
- $aE = $this->getBaseData();
18
 
19
- $aE[ 'status' ] = $oIt->is_checksumfail ? __( 'Modified', 'wp-simple-firewall' )
20
- : ( $oIt->is_missing ? __( 'Missing', 'wp-simple-firewall' ) : __( 'Unknown', 'wp-simple-firewall' ) );
21
 
22
- if ( $oIt->is_checksumfail ) {
23
- $aE[ 'explanation' ] = [
24
  __( 'This file is an official WordPress core file.', 'wp-simple-firewall' ),
25
  __( "But, it appears to have been modified when compared to the official WordPress distribution.", 'wp-simple-firewall' )
26
  .' '.__( "This is not normal in the vast majority of cases.", 'wp-simple-firewall' ),
@@ -29,8 +26,8 @@ class EntryFormatter extends BaseFileEntryFormatter {
29
  __( 'Ignore', 'wp-simple-firewall' ), __( 'Repair', 'wp-simple-firewall' ) ),
30
  ];
31
  }
32
- elseif ( $oIt->is_missing ) {
33
- $aE[ 'explanation' ] = [
34
  __( 'This file is an official WordPress core file.', 'wp-simple-firewall' ),
35
  __( "But, it appears to be missing from your site.", 'wp-simple-firewall' ),
36
  __( "You may want to check why this might be missing.", 'wp-simple-firewall' )
@@ -39,18 +36,18 @@ class EntryFormatter extends BaseFileEntryFormatter {
39
  ];
40
  }
41
 
42
- return $aE;
43
  }
44
 
45
  /**
46
  * @return string[]
47
  */
48
- protected function getExplanation() {
49
  /** @var ResultItem $oIt */
50
  $oIt = $this->getResultItem();
51
 
52
  if ( $oIt->is_checksumfail ) {
53
- $aExpl = [
54
  __( 'This file is an official WordPress core file.', 'wp-simple-firewall' ),
55
  __( "But, it appears to have been modified when compared to the official WordPress distribution.", 'wp-simple-firewall' )
56
  .' '.__( "This is not normal in the vast majority of cases.", 'wp-simple-firewall' ),
@@ -60,7 +57,7 @@ class EntryFormatter extends BaseFileEntryFormatter {
60
  ];
61
  }
62
  elseif ( $oIt->is_missing ) {
63
- $aExpl = [
64
  __( 'This file is an official WordPress core file.', 'wp-simple-firewall' ),
65
  __( "But, it appears to be missing from your site.", 'wp-simple-firewall' ),
66
  __( "You may want to check why this might be missing.", 'wp-simple-firewall' )
@@ -69,24 +66,24 @@ class EntryFormatter extends BaseFileEntryFormatter {
69
  ];
70
  }
71
  else {
72
- $aExpl = [];
73
  }
74
 
75
- return $aExpl;
76
  }
77
 
78
  /**
79
  * @inheritDoc
80
  */
81
- protected function getSupportedActions() {
82
- $aExtras = [ 'repair' ];
83
 
84
  /** @var ResultItem $oIt */
85
  $oIt = $this->getResultItem();
86
  if ( $oIt->is_checksumfail ) {
87
- $aExtras[] = 'download';
88
  }
89
 
90
- return array_merge( parent::getSupportedActions(), $aExtras );
91
  }
92
  }
7
 
8
  class EntryFormatter extends BaseFileEntryFormatter {
9
 
10
+ public function format() :array {
11
+ /** @var ResultItem $item */
12
+ $item = $this->getResultItem();
 
 
 
13
 
14
+ $e = $this->getBaseData();
15
 
16
+ $e[ 'status' ] = $item->is_checksumfail ? __( 'Modified', 'wp-simple-firewall' )
17
+ : ( $item->is_missing ? __( 'Missing', 'wp-simple-firewall' ) : __( 'Unknown', 'wp-simple-firewall' ) );
18
 
19
+ if ( $item->is_checksumfail ) {
20
+ $e[ 'explanation' ] = [
21
  __( 'This file is an official WordPress core file.', 'wp-simple-firewall' ),
22
  __( "But, it appears to have been modified when compared to the official WordPress distribution.", 'wp-simple-firewall' )
23
  .' '.__( "This is not normal in the vast majority of cases.", 'wp-simple-firewall' ),
26
  __( 'Ignore', 'wp-simple-firewall' ), __( 'Repair', 'wp-simple-firewall' ) ),
27
  ];
28
  }
29
+ elseif ( $item->is_missing ) {
30
+ $e[ 'explanation' ] = [
31
  __( 'This file is an official WordPress core file.', 'wp-simple-firewall' ),
32
  __( "But, it appears to be missing from your site.", 'wp-simple-firewall' ),
33
  __( "You may want to check why this might be missing.", 'wp-simple-firewall' )
36
  ];
37
  }
38
 
39
+ return $e;
40
  }
41
 
42
  /**
43
  * @return string[]
44
  */
45
+ protected function getExplanation() :array {
46
  /** @var ResultItem $oIt */
47
  $oIt = $this->getResultItem();
48
 
49
  if ( $oIt->is_checksumfail ) {
50
+ $expl = [
51
  __( 'This file is an official WordPress core file.', 'wp-simple-firewall' ),
52
  __( "But, it appears to have been modified when compared to the official WordPress distribution.", 'wp-simple-firewall' )
53
  .' '.__( "This is not normal in the vast majority of cases.", 'wp-simple-firewall' ),
57
  ];
58
  }
59
  elseif ( $oIt->is_missing ) {
60
+ $expl = [
61
  __( 'This file is an official WordPress core file.', 'wp-simple-firewall' ),
62
  __( "But, it appears to be missing from your site.", 'wp-simple-firewall' ),
63
  __( "You may want to check why this might be missing.", 'wp-simple-firewall' )
66
  ];
67
  }
68
  else {
69
+ $expl = [];
70
  }
71
 
72
+ return $expl;
73
  }
74
 
75
  /**
76
  * @inheritDoc
77
  */
78
+ protected function getSupportedActions() :array {
79
+ $extras = [ 'repair' ];
80
 
81
  /** @var ResultItem $oIt */
82
  $oIt = $this->getResultItem();
83
  if ( $oIt->is_checksumfail ) {
84
+ $extras[] = 'download';
85
  }
86
 
87
+ return array_merge( parent::getSupportedActions(), $extras );
88
  }
89
  }
src/lib/src/Scans/Wpv/WpVulnDb/WpVulnVO.php CHANGED
@@ -40,12 +40,4 @@ class WpVulnVO extends DynPropertiesClass {
40
 
41
  return $val;
42
  }
43
-
44
- /**
45
- * @return string
46
- * @deprecated 10.2
47
- */
48
- public function getUrl() {
49
- return sprintf( 'https://wpvulndb.com/vulnerabilities/%s', $this->id );
50
- }
51
  }
40
 
41
  return $val;
42
  }
 
 
 
 
 
 
 
 
43
  }
src/lib/src/Tables/Build/BaseBuild.php CHANGED
@@ -157,18 +157,12 @@ class BaseBuild {
157
  return $this->aBuildParams;
158
  }
159
 
160
- /**
161
- * @return array
162
- */
163
- private function getFormParams() {
164
- parse_str( Services::Request()->post( 'form_params', '' ), $aFormParams );
165
- return Services::DataManipulation()->arrayMapRecursive( $aFormParams, 'trim' );
166
  }
167
 
168
- /**
169
- * @return array
170
- */
171
- protected function getParamDefaults() {
172
  return array_merge(
173
  [
174
  'paged' => 1,
157
  return $this->aBuildParams;
158
  }
159
 
160
+ private function getFormParams() :array {
161
+ parse_str( Services::Request()->post( 'form_params', '' ), $formParams );
162
+ return Services::DataManipulation()->arrayMapRecursive( $formParams, 'trim' );
 
 
 
163
  }
164
 
165
+ protected function getParamDefaults() :array {
 
 
 
166
  return array_merge(
167
  [
168
  'paged' => 1,
src/lib/src/Tables/Build/ScanAggregate.php CHANGED
@@ -3,9 +3,9 @@
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Tables\Build;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield;
6
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Scanner;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Scanner\EntryVO;
 
9
 
10
  /**
11
  * Class ScanAggregate
@@ -32,20 +32,20 @@ class ScanAggregate extends ScanBase {
32
  */
33
  public function getEntriesFormatted() :array {
34
  // first filter out PTG results as we process them a bit separately.
35
- $aPtgScanEntries = [];
36
- $aRaw = $this->getEntriesRaw();
37
- /** @var $oEntry Scanner\EntryVO */
38
- foreach ( $aRaw as $nKeyId => $oEntry ) {
39
- if ( $oEntry->scan == 'ptg' ) {
40
- unset( $aRaw[ $nKeyId ] );
41
- $aPtgScanEntries[ $nKeyId ] = $oEntry;
42
  }
43
  }
44
 
45
- $aEntries = $this->processEntriesGroup( $aRaw );
46
 
47
  // Group all PTG entries together
48
- usort( $aPtgScanEntries, function ( $oE1, $oE2 ) {
49
  /** @var $oE1 EntryVO */
50
  /** @var $oE2 EntryVO */
51
  return strcasecmp( $oE1->meta[ 'path_full' ], $oE2->meta[ 'path_full' ] );
@@ -53,47 +53,44 @@ class ScanAggregate extends ScanBase {
53
 
54
  return array_merge(
55
  $aEntries,
56
- $this->processEntriesGroup( $aPtgScanEntries )
57
  );
58
  }
59
 
60
  /**
61
- * @param Scanner\EntryVO[] $aEntries
62
  * @return array[]
63
  */
64
- private function processEntriesGroup( $aEntries ) {
65
- $aProcessedEntries = [];
66
 
67
  /** @var HackGuard\ModCon $mod */
68
  $mod = $this->getMod();
69
- /** @var HackGuard\Strings $oStrings */
70
- $oStrings = $mod->getStrings();
71
- $aScanNames = $oStrings->getScanNames();
72
 
73
  $aScanRowTracker = [];
74
- foreach ( $aEntries as $nKey => $oEntry ) {
75
- if ( empty( $aScanRowTracker[ $oEntry->scan ] ) ) {
76
- $aScanRowTracker[ $oEntry->scan ] = $oEntry->scan;
77
- $aProcessedEntries[ $oEntry->scan ] = [
78
  'custom_row' => true,
79
- 'title' => $aScanNames[ $oEntry->scan ],
80
  ];
81
  }
82
- $aProcessedEntries[ $nKey ] = $mod
83
- ->getScanCon( $oEntry->scan )
84
  ->getTableEntryFormatter()
85
  ->setMod( $this->getMod() )
86
- ->setEntryVO( $oEntry )
87
  ->format();
88
  }
89
 
90
- return $aProcessedEntries;
91
  }
92
 
93
- /**
94
- * @return array
95
- */
96
- protected function getParamDefaults() {
97
  return array_merge(
98
  parent::getParamDefaults(),
99
  [ 'orderby' => 'scan', ]
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Tables\Build;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield;
 
6
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Scanner;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Scanner\EntryVO;
8
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard;
9
 
10
  /**
11
  * Class ScanAggregate
32
  */
33
  public function getEntriesFormatted() :array {
34
  // first filter out PTG results as we process them a bit separately.
35
+ $ptgScanEntries = [];
36
+ /** @var Scanner\EntryVO[] $raw */
37
+ $raw = $this->getEntriesRaw();
38
+ foreach ( $raw as $key => $entry ) {
39
+ if ( $entry->scan == 'ptg' ) {
40
+ unset( $raw[ $key ] );
41
+ $ptgScanEntries[ $key ] = $entry;
42
  }
43
  }
44
 
45
+ $aEntries = $this->processEntriesGroup( $raw );
46
 
47
  // Group all PTG entries together
48
+ usort( $ptgScanEntries, function ( $oE1, $oE2 ) {
49
  /** @var $oE1 EntryVO */
50
  /** @var $oE2 EntryVO */
51
  return strcasecmp( $oE1->meta[ 'path_full' ], $oE2->meta[ 'path_full' ] );
53
 
54
  return array_merge(
55
  $aEntries,
56
+ $this->processEntriesGroup( $ptgScanEntries )
57
  );
58
  }
59
 
60
  /**
61
+ * @param Scanner\EntryVO[] $entries
62
  * @return array[]
63
  */
64
+ private function processEntriesGroup( array $entries ) {
65
+ $processed = [];
66
 
67
  /** @var HackGuard\ModCon $mod */
68
  $mod = $this->getMod();
69
+ /** @var HackGuard\Strings $strings */
70
+ $strings = $mod->getStrings();
71
+ $scanNames = $strings->getScanNames();
72
 
73
  $aScanRowTracker = [];
74
+ foreach ( $entries as $key => $entry ) {
75
+ if ( empty( $aScanRowTracker[ $entry->scan ] ) ) {
76
+ $aScanRowTracker[ $entry->scan ] = $entry->scan;
77
+ $processed[ $entry->scan ] = [
78
  'custom_row' => true,
79
+ 'title' => $scanNames[ $entry->scan ],
80
  ];
81
  }
82
+ $processed[ $key ] = $mod
83
+ ->getScanCon( $entry->scan )
84
  ->getTableEntryFormatter()
85
  ->setMod( $this->getMod() )
86
+ ->setEntryVO( $entry )
87
  ->format();
88
  }
89
 
90
+ return $processed;
91
  }
92
 
93
+ protected function getParamDefaults() :array {
 
 
 
94
  return array_merge(
95
  parent::getParamDefaults(),
96
  [ 'orderby' => 'scan', ]
src/lib/src/Tables/Build/ScanBase.php CHANGED
@@ -22,19 +22,19 @@ class ScanBase extends BaseBuild {
22
  * @return array[]
23
  */
24
  public function getEntriesFormatted() :array {
25
- $aEntries = [];
26
 
27
  /** @var ModCon $mod */
28
  $mod = $this->getMod();
29
- foreach ( $this->getEntriesRaw() as $nKey => $oEntry ) {
30
- /** @var Scanner\EntryVO $oEntry */
31
- $aEntries[ $nKey ] = $mod->getScanCon( $oEntry->scan )
32
- ->getTableEntryFormatter()
33
- ->setEntryVO( $oEntry )
34
- ->format();
35
  }
36
 
37
- return $aEntries;
38
  }
39
 
40
  /**
@@ -63,10 +63,7 @@ class ScanBase extends BaseBuild {
63
  ];
64
  }
65
 
66
- /**
67
- * @return array
68
- */
69
- protected function getParamDefaults() {
70
  return array_merge(
71
  parent::getParamDefaults(),
72
  [ 'limit' => PHP_INT_MAX ]
@@ -74,11 +71,11 @@ class ScanBase extends BaseBuild {
74
  }
75
 
76
  /**
77
- * @param Scanner\EntryVO $oEntry
78
  * @return string
79
  */
80
- protected function formatIsIgnored( $oEntry ) {
81
- return ( $oEntry->ignored_at > 0 && Services::Request()->ts() > $oEntry->ignored_at ) ?
82
  __( 'Yes' ) : __( 'No' );
83
  }
84
  }
22
  * @return array[]
23
  */
24
  public function getEntriesFormatted() :array {
25
+ $entries = [];
26
 
27
  /** @var ModCon $mod */
28
  $mod = $this->getMod();
29
+ foreach ( $this->getEntriesRaw() as $key => $entry ) {
30
+ /** @var Scanner\EntryVO $entry */
31
+ $entries[ $key ] = $mod->getScanCon( $entry->scan )
32
+ ->getTableEntryFormatter()
33
+ ->setEntryVO( $entry )
34
+ ->format();
35
  }
36
 
37
+ return $entries;
38
  }
39
 
40
  /**
63
  ];
64
  }
65
 
66
+ protected function getParamDefaults() :array {
 
 
 
67
  return array_merge(
68
  parent::getParamDefaults(),
69
  [ 'limit' => PHP_INT_MAX ]
71
  }
72
 
73
  /**
74
+ * @param Scanner\EntryVO $entry
75
  * @return string
76
  */
77
+ protected function formatIsIgnored( $entry ) {
78
+ return ( $entry->ignored_at > 0 && Services::Request()->ts() > $entry->ignored_at ) ?
79
  __( 'Yes' ) : __( 'No' );
80
  }
81
  }
src/lib/src/Tables/Render/WpListTable/ScanAggregate.php CHANGED
@@ -7,20 +7,20 @@ use FernleafSystems\Wordpress\Plugin\Shield\Scans;
7
  class ScanAggregate extends ScanBase {
8
 
9
  /**
10
- * @param array $aItem
11
  * @return string
12
  */
13
- public function column_path( $aItem ) {
14
 
15
- $sContent = parent::column_path( $aItem );
16
 
17
- if ( !empty( $aItem[ 'actions' ] ) ) {
18
  $sContent .= $this->buildActions(
19
  array_map(
20
  function ( $aActionDef ) {
21
  return $this->buildActionButton_CustomArray( $aActionDef );
22
  },
23
- $aItem[ 'actions' ]
24
  )
25
  );
26
  }
@@ -29,15 +29,15 @@ class ScanAggregate extends ScanBase {
29
  }
30
 
31
  /**
32
- * @param array $aItem
33
  * @return string
34
  */
35
- public function column_status( $aItem ) {
36
- $sStatus = sprintf( '<strong>%s</strong>', $aItem[ 'status' ] );
37
- if ( !empty( $aItem[ 'explanation' ] ) ) {
38
- $sStatus .= '<ul><li>'.implode( '</li><li>', $aItem[ 'explanation' ] ).'</li></ul>';
39
  }
40
- return $sStatus;
41
  }
42
 
43
  /**
7
  class ScanAggregate extends ScanBase {
8
 
9
  /**
10
+ * @param array $item
11
  * @return string
12
  */
13
+ public function column_path( $item ) {
14
 
15
+ $sContent = parent::column_path( $item );
16
 
17
+ if ( !empty( $item[ 'actions' ] ) ) {
18
  $sContent .= $this->buildActions(
19
  array_map(
20
  function ( $aActionDef ) {
21
  return $this->buildActionButton_CustomArray( $aActionDef );
22
  },
23
+ $item[ 'actions' ]
24
  )
25
  );
26
  }
29
  }
30
 
31
  /**
32
+ * @param array $item
33
  * @return string
34
  */
35
+ public function column_status( $item ) {
36
+ $status = sprintf( '<strong>%s</strong>', $item[ 'status' ] );
37
+ if ( !empty( $item[ 'explanation' ] ) ) {
38
+ $status .= '<ul><li>'.implode( '</li><li>', $item[ 'explanation' ] ).'</li></ul>';
39
  }
40
+ return $status;
41
  }
42
 
43
  /**
src/lib/src/Tables/Render/WpListTable/ScanBase.php CHANGED
@@ -7,16 +7,16 @@ use FernleafSystems\Wordpress\Plugin\Shield\Scans;
7
  class ScanBase extends Base {
8
 
9
  /**
10
- * @param array $aItem
11
  * @return string
12
  */
13
- public function column_path( $aItem ) {
14
  $sOut = sprintf( '<code><span class="font-weight-bolder text-dark" style="font-size: larger">%s</span></code><code>[%s]</code>',
15
- $aItem[ 'path' ],
16
- sprintf( '%s: %s', __( 'Path', 'wp-simple-firewall' ), trailingslashit( dirname( $aItem[ 'path_relabs' ] ) ) )
17
  );
18
- if ( !empty( $aItem[ 'path_details' ] ) ) {
19
- $sOut .= '<p class="mb-0">'.implode( '; ', $aItem[ 'path_details' ] ).'</p>';
20
  }
21
  return $sOut;
22
  }
7
  class ScanBase extends Base {
8
 
9
  /**
10
+ * @param array $item
11
  * @return string
12
  */
13
+ public function column_path( $item ) {
14
  $sOut = sprintf( '<code><span class="font-weight-bolder text-dark" style="font-size: larger">%s</span></code><code>[%s]</code>',
15
+ $item[ 'path' ],
16
+ sprintf( '%s: %s', __( 'Path', 'wp-simple-firewall' ), trailingslashit( dirname( $item[ 'path_relabs' ] ) ) )
17
  );
18
+ if ( !empty( $item[ 'path_details' ] ) ) {
19
+ $sOut .= '<p class="mb-0">'.implode( '; ', $item[ 'path_details' ] ).'</p>';
20
  }
21
  return $sOut;
22
  }
src/lib/src/Tables/Render/WpListTable/ScanMal.php CHANGED
@@ -7,23 +7,23 @@ use FernleafSystems\Wordpress\Plugin\Shield\Scans;
7
  class ScanMal extends ScanBase {
8
 
9
  /**
10
- * @param array $aItem
11
  * @return string
12
  */
13
- public function column_path( $aItem ) {
14
  $aButtons = [
15
- $this->getActionButton_Ignore( $aItem[ 'id' ] ),
16
  ];
17
- if ( $aItem[ 'can_repair' ] ) {
18
- $aButtons[] = $this->getActionButton_Repair( $aItem[ 'id' ] );
19
  }
20
  else {
21
- $aButtons[] = $this->getActionButton_Delete( $aItem[ 'id' ] );
22
  }
23
- if ( !empty( $aItem[ 'href_download' ] ) ) {
24
- $aButtons[] = $this->getActionButton_DownloadFile( $aItem[ 'href_download' ] );
25
  }
26
- return parent::column_path( $aItem ).$this->buildActions( $aButtons );
27
  }
28
 
29
  /**
7
  class ScanMal extends ScanBase {
8
 
9
  /**
10
+ * @param array $item
11
  * @return string
12
  */
13
+ public function column_path( $item ) {
14
  $aButtons = [
15
+ $this->getActionButton_Ignore( $item[ 'id' ] ),
16
  ];
17
+ if ( $item[ 'can_repair' ] ) {
18
+ $aButtons[] = $this->getActionButton_Repair( $item[ 'id' ] );
19
  }
20
  else {
21
+ $aButtons[] = $this->getActionButton_Delete( $item[ 'id' ] );
22
  }
23
+ if ( !empty( $item[ 'href_download' ] ) ) {
24
+ $aButtons[] = $this->getActionButton_DownloadFile( $item[ 'href_download' ] );
25
  }
26
+ return parent::column_path( $item ).$this->buildActions( $aButtons );
27
  }
28
 
29
  /**
src/lib/src/Tables/Render/WpListTable/ScanPtg.php CHANGED
@@ -7,15 +7,15 @@ use FernleafSystems\Wordpress\Plugin\Shield\Scans;
7
  class ScanPtg extends ScanBase {
8
 
9
  /**
10
- * @param array $aItem
11
  * @return string
12
  */
13
- public function column_path( $aItem ) {
14
  $aButtons = [];
15
- if ( !empty( $aItem[ 'href_download' ] ) ) {
16
- $aButtons[] = $this->getActionButton_DownloadFile( $aItem[ 'href_download' ] );
17
  }
18
- return parent::column_path( $aItem ).$this->buildActions( $aButtons );
19
  }
20
 
21
  /**
7
  class ScanPtg extends ScanBase {
8
 
9
  /**
10
+ * @param array $item
11
  * @return string
12
  */
13
+ public function column_path( $item ) {
14
  $aButtons = [];
15
+ if ( !empty( $item[ 'href_download' ] ) ) {
16
+ $aButtons[] = $this->getActionButton_DownloadFile( $item[ 'href_download' ] );
17
  }
18
+ return parent::column_path( $item ).$this->buildActions( $aButtons );
19
  }
20
 
21
  /**
src/lib/src/Tables/Render/WpListTable/ScanUfc.php CHANGED
@@ -7,18 +7,18 @@ use FernleafSystems\Wordpress\Plugin\Shield\Scans;
7
  class ScanUfc extends ScanBase {
8
 
9
  /**
10
- * @param array $aItem
11
  * @return string
12
  */
13
- public function column_path( $aItem ) {
14
  $aButtons = [
15
- $this->getActionButton_Ignore( $aItem[ 'id' ] ),
16
- $this->getActionButton_Delete( $aItem[ 'id' ] ),
17
  ];
18
- if ( !empty( $aItem[ 'href_download' ] ) ) {
19
- $aButtons[] = $this->getActionButton_DownloadFile( $aItem[ 'href_download' ] );
20
  }
21
- return parent::column_path( $aItem ).$this->buildActions( $aButtons );
22
  }
23
 
24
  /**
7
  class ScanUfc extends ScanBase {
8
 
9
  /**
10
+ * @param array $item
11
  * @return string
12
  */
13
+ public function column_path( $item ) {
14
  $aButtons = [
15
+ $this->getActionButton_Ignore( $item[ 'id' ] ),
16
+ $this->getActionButton_Delete( $item[ 'id' ] ),
17
  ];
18
+ if ( !empty( $item[ 'href_download' ] ) ) {
19
+ $aButtons[] = $this->getActionButton_DownloadFile( $item[ 'href_download' ] );
20
  }
21
+ return parent::column_path( $item ).$this->buildActions( $aButtons );
22
  }
23
 
24
  /**
src/lib/src/Tables/Render/WpListTable/ScanWcf.php CHANGED
@@ -7,18 +7,18 @@ use FernleafSystems\Wordpress\Plugin\Shield\Scans;
7
  class ScanWcf extends ScanBase {
8
 
9
  /**
10
- * @param array $aItem
11
  * @return string
12
  */
13
- public function column_path( $aItem ) {
14
  $aButtons = [
15
- $this->getActionButton_Ignore( $aItem[ 'id' ] ),
16
- $this->getActionButton_Repair( $aItem[ 'id' ] ),
17
  ];
18
- if ( !empty( $aItem[ 'href_download' ] ) ) {
19
- $aButtons[] = $this->getActionButton_DownloadFile( $aItem[ 'href_download' ] );
20
  }
21
- return parent::column_path( $aItem ).$this->buildActions( $aButtons );
22
  }
23
 
24
  /**
7
  class ScanWcf extends ScanBase {
8
 
9
  /**
10
+ * @param array $item
11
  * @return string
12
  */
13
+ public function column_path( $item ) {
14
  $aButtons = [
15
+ $this->getActionButton_Ignore( $item[ 'id' ] ),
16
+ $this->getActionButton_Repair( $item[ 'id' ] ),
17
  ];
18
+ if ( !empty( $item[ 'href_download' ] ) ) {
19
+ $aButtons[] = $this->getActionButton_DownloadFile( $item[ 'href_download' ] );
20
  }
21
+ return parent::column_path( $item ).$this->buildActions( $aButtons );
22
  }
23
 
24
  /**
src/lib/src/Utilities/Nonce/Handler.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Utilities\Nonce;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\PluginControllerConsumer;
6
+ use FernleafSystems\Wordpress\Services\Utilities\Options\Transient;
7
+
8
+ class Handler {
9
+
10
+ use PluginControllerConsumer;
11
+
12
+ public function create( string $action, int $ttl = 0 ) :string {
13
+ $nonce = hash_hmac( 'sha1', $action, $this->getCon()->getSiteInstallationId() );
14
+ Transient::Set( 'apto-nonce-'.$action, $nonce, $ttl );
15
+ return $nonce;
16
+ }
17
+
18
+ public function verify( string $action, string $nonce ) :bool {
19
+ $valid = hash_equals(
20
+ (string)Transient::Get( 'apto-nonce-'.$action, '' ),
21
+ hash_hmac( 'sha1', $action, $this->getCon()->getSiteInstallationId() )
22
+ );
23
+ Transient::Delete( 'apto-nonce-'.$action );
24
+ return $valid;
25
+ }
26
+ }
src/lib/vendor/composer/autoload_classmap.php CHANGED
@@ -215,6 +215,7 @@ return array(
215
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\AjaxHandler' => $baseDir . '/src/Modules/Base/AjaxHandler.php',
216
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Debug' => $baseDir . '/src/Modules/Base/Debug.php',
217
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Insights\\OverviewCards' => $baseDir . '/src/Modules/Base/Insights/OverviewCards.php',
 
218
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\ModCon' => $baseDir . '/src/Modules/Base/ModCon.php',
219
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Options' => $baseDir . '/src/Modules/Base/Options.php',
220
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Options\\OptValueSanitize' => $baseDir . '/src/Modules/Base/Options/OptValueSanitize.php',
@@ -264,7 +265,14 @@ return array(
264
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Processor' => $baseDir . '/src/Modules/Events/Processor.php',
265
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Reporting' => $baseDir . '/src/Modules/Events/Reporting.php',
266
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Strings' => $baseDir . '/src/Modules/Events/Strings.php',
 
267
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\Insights\\OverviewCards' => $baseDir . '/src/Modules/Firewall/Insights/OverviewCards.php',
 
 
 
 
 
 
268
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\ModCon' => $baseDir . '/src/Modules/Firewall/ModCon.php',
269
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\Options' => $baseDir . '/src/Modules/Firewall/Options.php',
270
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\Processor' => $baseDir . '/src/Modules/Firewall/Processor.php',
@@ -373,11 +381,11 @@ return array(
373
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\AutoUnblock' => $baseDir . '/src/Modules/IPs/Lib/AutoUnblock.php',
374
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\BlacklistHandler' => $baseDir . '/src/Modules/IPs/Lib/BlacklistHandler.php',
375
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\BlockRequest' => $baseDir . '/src/Modules/IPs/Lib/BlockRequest.php',
 
376
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\BotSignalsController' => $baseDir . '/src/Modules/IPs/Lib/Bots/BotSignalsController.php',
377
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\BotSignalsRecord' => $baseDir . '/src/Modules/IPs/Lib/Bots/BotSignalsRecord.php',
378
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\Calculator\\BuildScores' => $baseDir . '/src/Modules/IPs/Lib/Bots/Calculator/BuildScores.php',
379
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\Calculator\\CalculateVisitorBotScores' => $baseDir . '/src/Modules/IPs/Lib/Bots/Calculator/CalculateVisitorBotScores.php',
380
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\EventListener' => $baseDir . '/src/Modules/IPs/Lib/Bots/EventListener.php',
381
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\NotBot\\InsertNotBotJs' => $baseDir . '/src/Modules/IPs/Lib/Bots/NotBot/InsertNotBotJs.php',
382
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\NotBot\\NotBotHandler' => $baseDir . '/src/Modules/IPs/Lib/Bots/NotBot/NotBotHandler.php',
383
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\IpAnalyse\\BuildDisplay' => $baseDir . '/src/Modules/IPs/Lib/IpAnalyse/BuildDisplay.php',
@@ -399,7 +407,10 @@ return array(
399
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\WpCli\\BaseAddRemove' => $baseDir . '/src/Modules/IPs/WpCli/BaseAddRemove.php',
400
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\WpCli\\Enumerate' => $baseDir . '/src/Modules/IPs/WpCli/Enumerate.php',
401
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\WpCli\\Remove' => $baseDir . '/src/Modules/IPs/WpCli/Remove.php',
 
402
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Lib\\OverviewCards' => $baseDir . '/src/Modules/Insights/Lib/OverviewCards.php',
 
 
403
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\ModCon' => $baseDir . '/src/Modules/Insights/ModCon.php',
404
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Options' => $baseDir . '/src/Modules/Insights/Options.php',
405
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Strings' => $baseDir . '/src/Modules/Insights/Strings.php',
@@ -579,8 +590,19 @@ return array(
579
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\AdminNotices' => $baseDir . '/src/Modules/SecurityAdmin/AdminNotices.php',
580
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\AjaxHandler' => $baseDir . '/src/Modules/SecurityAdmin/AjaxHandler.php',
581
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Insights\\OverviewCards' => $baseDir . '/src/Modules/SecurityAdmin/Insights/OverviewCards.php',
582
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\Actions\\RemoveSecAdmin' => $baseDir . '/src/Modules/SecurityAdmin/Lib/Actions/RemoveSecAdmin.php',
583
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\Actions\\SetSecAdminPin' => $baseDir . '/src/Modules/SecurityAdmin/Lib/Actions/SetSecAdminPin.php',
 
 
 
 
 
 
 
 
 
 
 
584
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\WhiteLabel\\ApplyLabels' => $baseDir . '/src/Modules/SecurityAdmin/Lib/WhiteLabel/ApplyLabels.php',
585
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\ModCon' => $baseDir . '/src/Modules/SecurityAdmin/ModCon.php',
586
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Options' => $baseDir . '/src/Modules/SecurityAdmin/Options.php',
@@ -779,6 +801,7 @@ return array(
779
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Github\\ListTags' => $baseDir . '/src/Utilities/Github/ListTags.php',
780
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\HCaptcha\\TestRequest' => $baseDir . '/src/Utilities/HCaptcha/TestRequest.php',
781
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\HumanSpam\\TestContent' => $baseDir . '/src/Utilities/HumanSpam/TestContent.php',
 
782
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Options\\CleanStorage' => $baseDir . '/src/Utilities/Options/CleanStorage.php',
783
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\ReCaptcha\\Enqueue' => $baseDir . '/src/Utilities/ReCaptcha/Enqueue.php',
784
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\ReCaptcha\\TestRequest' => $baseDir . '/src/Utilities/ReCaptcha/TestRequest.php',
215
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\AjaxHandler' => $baseDir . '/src/Modules/Base/AjaxHandler.php',
216
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Debug' => $baseDir . '/src/Modules/Base/Debug.php',
217
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Insights\\OverviewCards' => $baseDir . '/src/Modules/Base/Insights/OverviewCards.php',
218
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Request\\FormParams' => $baseDir . '/src/Modules/Base/Lib/Request/FormParams.php',
219
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\ModCon' => $baseDir . '/src/Modules/Base/ModCon.php',
220
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Options' => $baseDir . '/src/Modules/Base/Options.php',
221
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Options\\OptValueSanitize' => $baseDir . '/src/Modules/Base/Options/OptValueSanitize.php',
265
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Processor' => $baseDir . '/src/Modules/Events/Processor.php',
266
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Reporting' => $baseDir . '/src/Modules/Events/Reporting.php',
267
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Strings' => $baseDir . '/src/Modules/Events/Strings.php',
268
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\UI' => $baseDir . '/src/Modules/Events/UI.php',
269
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\Insights\\OverviewCards' => $baseDir . '/src/Modules/Firewall/Insights/OverviewCards.php',
270
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\Lib\\Scan\\CanScan' => $baseDir . '/src/Modules/Firewall/Lib/Scan/CanScan.php',
271
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\Lib\\Scan\\Checks\\Base' => $baseDir . '/src/Modules/Firewall/Lib/Scan/Checks/Base.php',
272
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\Lib\\Scan\\Checks\\ExeFiles' => $baseDir . '/src/Modules/Firewall/Lib/Scan/Checks/ExeFiles.php',
273
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\Lib\\Scan\\Checks\\Standard' => $baseDir . '/src/Modules/Firewall/Lib/Scan/Checks/Standard.php',
274
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\Lib\\Scan\\ParametersToScan' => $baseDir . '/src/Modules/Firewall/Lib/Scan/ParametersToScan.php',
275
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\Lib\\Scan\\PerformScan' => $baseDir . '/src/Modules/Firewall/Lib/Scan/PerformScan.php',
276
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\ModCon' => $baseDir . '/src/Modules/Firewall/ModCon.php',
277
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\Options' => $baseDir . '/src/Modules/Firewall/Options.php',
278
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\Processor' => $baseDir . '/src/Modules/Firewall/Processor.php',
381
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\AutoUnblock' => $baseDir . '/src/Modules/IPs/Lib/AutoUnblock.php',
382
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\BlacklistHandler' => $baseDir . '/src/Modules/IPs/Lib/BlacklistHandler.php',
383
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\BlockRequest' => $baseDir . '/src/Modules/IPs/Lib/BlockRequest.php',
384
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\BotEventListener' => $baseDir . '/src/Modules/IPs/Lib/Bots/BotEventListener.php',
385
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\BotSignalsController' => $baseDir . '/src/Modules/IPs/Lib/Bots/BotSignalsController.php',
386
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\BotSignalsRecord' => $baseDir . '/src/Modules/IPs/Lib/Bots/BotSignalsRecord.php',
387
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\Calculator\\BuildScores' => $baseDir . '/src/Modules/IPs/Lib/Bots/Calculator/BuildScores.php',
388
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\Calculator\\CalculateVisitorBotScores' => $baseDir . '/src/Modules/IPs/Lib/Bots/Calculator/CalculateVisitorBotScores.php',
 
389
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\NotBot\\InsertNotBotJs' => $baseDir . '/src/Modules/IPs/Lib/Bots/NotBot/InsertNotBotJs.php',
390
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\NotBot\\NotBotHandler' => $baseDir . '/src/Modules/IPs/Lib/Bots/NotBot/NotBotHandler.php',
391
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\IpAnalyse\\BuildDisplay' => $baseDir . '/src/Modules/IPs/Lib/IpAnalyse/BuildDisplay.php',
407
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\WpCli\\BaseAddRemove' => $baseDir . '/src/Modules/IPs/WpCli/BaseAddRemove.php',
408
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\WpCli\\Enumerate' => $baseDir . '/src/Modules/IPs/WpCli/Enumerate.php',
409
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\WpCli\\Remove' => $baseDir . '/src/Modules/IPs/WpCli/Remove.php',
410
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\AjaxHandler' => $baseDir . '/src/Modules/Insights/AjaxHandler.php',
411
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Lib\\OverviewCards' => $baseDir . '/src/Modules/Insights/Lib/OverviewCards.php',
412
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Lib\\Requests\\DynamicPageLoader' => $baseDir . '/src/Modules/Insights/Lib/Requests/DynamicPageLoader.php',
413
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Lib\\SideMenuBuilder' => $baseDir . '/src/Modules/Insights/Lib/SideMenuBuilder.php',
414
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\ModCon' => $baseDir . '/src/Modules/Insights/ModCon.php',
415
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Options' => $baseDir . '/src/Modules/Insights/Options.php',
416
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Strings' => $baseDir . '/src/Modules/Insights/Strings.php',
590
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\AdminNotices' => $baseDir . '/src/Modules/SecurityAdmin/AdminNotices.php',
591
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\AjaxHandler' => $baseDir . '/src/Modules/SecurityAdmin/AjaxHandler.php',
592
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Insights\\OverviewCards' => $baseDir . '/src/Modules/SecurityAdmin/Insights/OverviewCards.php',
593
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\Ops\\RemoveSecAdmin' => $baseDir . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Ops/RemoveSecAdmin.php',
594
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\Ops\\SetSecAdminPin' => $baseDir . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Ops/SetSecAdminPin.php',
595
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\Ops\\ToggleSecAdminStatus' => $baseDir . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Ops/ToggleSecAdminStatus.php',
596
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\Ops\\VerifyPinRequest' => $baseDir . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Ops/VerifyPinRequest.php',
597
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\Restrictions\\Base' => $baseDir . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/Base.php',
598
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\Restrictions\\BaseCapabilitiesRestrict' => $baseDir . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/BaseCapabilitiesRestrict.php',
599
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\Restrictions\\Plugins' => $baseDir . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/Plugins.php',
600
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\Restrictions\\Posts' => $baseDir . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/Posts.php',
601
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\Restrictions\\Themes' => $baseDir . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/Themes.php',
602
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\Restrictions\\Users' => $baseDir . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/Users.php',
603
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\Restrictions\\WpOptions' => $baseDir . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/WpOptions.php',
604
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\SecurityAdminController' => $baseDir . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/SecurityAdminController.php',
605
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\VerifySecurityAdminList' => $baseDir . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/VerifySecurityAdminList.php',
606
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\WhiteLabel\\ApplyLabels' => $baseDir . '/src/Modules/SecurityAdmin/Lib/WhiteLabel/ApplyLabels.php',
607
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\ModCon' => $baseDir . '/src/Modules/SecurityAdmin/ModCon.php',
608
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Options' => $baseDir . '/src/Modules/SecurityAdmin/Options.php',
801
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Github\\ListTags' => $baseDir . '/src/Utilities/Github/ListTags.php',
802
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\HCaptcha\\TestRequest' => $baseDir . '/src/Utilities/HCaptcha/TestRequest.php',
803
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\HumanSpam\\TestContent' => $baseDir . '/src/Utilities/HumanSpam/TestContent.php',
804
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Nonce\\Handler' => $baseDir . '/src/Utilities/Nonce/Handler.php',
805
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Options\\CleanStorage' => $baseDir . '/src/Utilities/Options/CleanStorage.php',
806
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\ReCaptcha\\Enqueue' => $baseDir . '/src/Utilities/ReCaptcha/Enqueue.php',
807
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\ReCaptcha\\TestRequest' => $baseDir . '/src/Utilities/ReCaptcha/TestRequest.php',
src/lib/vendor/composer/autoload_static.php CHANGED
@@ -383,6 +383,7 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
383
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\AjaxHandler' => __DIR__ . '/../..' . '/src/Modules/Base/AjaxHandler.php',
384
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Debug' => __DIR__ . '/../..' . '/src/Modules/Base/Debug.php',
385
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Insights\\OverviewCards' => __DIR__ . '/../..' . '/src/Modules/Base/Insights/OverviewCards.php',
 
386
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\ModCon' => __DIR__ . '/../..' . '/src/Modules/Base/ModCon.php',
387
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Options' => __DIR__ . '/../..' . '/src/Modules/Base/Options.php',
388
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Options\\OptValueSanitize' => __DIR__ . '/../..' . '/src/Modules/Base/Options/OptValueSanitize.php',
@@ -432,7 +433,14 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
432
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Processor' => __DIR__ . '/../..' . '/src/Modules/Events/Processor.php',
433
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Reporting' => __DIR__ . '/../..' . '/src/Modules/Events/Reporting.php',
434
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Strings' => __DIR__ . '/../..' . '/src/Modules/Events/Strings.php',
 
435
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\Insights\\OverviewCards' => __DIR__ . '/../..' . '/src/Modules/Firewall/Insights/OverviewCards.php',
 
 
 
 
 
 
436
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\ModCon' => __DIR__ . '/../..' . '/src/Modules/Firewall/ModCon.php',
437
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\Options' => __DIR__ . '/../..' . '/src/Modules/Firewall/Options.php',
438
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\Processor' => __DIR__ . '/../..' . '/src/Modules/Firewall/Processor.php',
@@ -541,11 +549,11 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
541
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\AutoUnblock' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/AutoUnblock.php',
542
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\BlacklistHandler' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/BlacklistHandler.php',
543
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\BlockRequest' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/BlockRequest.php',
 
544
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\BotSignalsController' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/Bots/BotSignalsController.php',
545
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\BotSignalsRecord' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/Bots/BotSignalsRecord.php',
546
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\Calculator\\BuildScores' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/Bots/Calculator/BuildScores.php',
547
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\Calculator\\CalculateVisitorBotScores' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/Bots/Calculator/CalculateVisitorBotScores.php',
548
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\EventListener' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/Bots/EventListener.php',
549
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\NotBot\\InsertNotBotJs' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/Bots/NotBot/InsertNotBotJs.php',
550
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\NotBot\\NotBotHandler' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/Bots/NotBot/NotBotHandler.php',
551
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\IpAnalyse\\BuildDisplay' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/IpAnalyse/BuildDisplay.php',
@@ -567,7 +575,10 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
567
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\WpCli\\BaseAddRemove' => __DIR__ . '/../..' . '/src/Modules/IPs/WpCli/BaseAddRemove.php',
568
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\WpCli\\Enumerate' => __DIR__ . '/../..' . '/src/Modules/IPs/WpCli/Enumerate.php',
569
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\WpCli\\Remove' => __DIR__ . '/../..' . '/src/Modules/IPs/WpCli/Remove.php',
 
570
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Lib\\OverviewCards' => __DIR__ . '/../..' . '/src/Modules/Insights/Lib/OverviewCards.php',
 
 
571
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\ModCon' => __DIR__ . '/../..' . '/src/Modules/Insights/ModCon.php',
572
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Options' => __DIR__ . '/../..' . '/src/Modules/Insights/Options.php',
573
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Strings' => __DIR__ . '/../..' . '/src/Modules/Insights/Strings.php',
@@ -747,8 +758,19 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
747
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\AdminNotices' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/AdminNotices.php',
748
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\AjaxHandler' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/AjaxHandler.php',
749
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Insights\\OverviewCards' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Insights/OverviewCards.php',
750
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\Actions\\RemoveSecAdmin' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/Actions/RemoveSecAdmin.php',
751
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\Actions\\SetSecAdminPin' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/Actions/SetSecAdminPin.php',
 
 
 
 
 
 
 
 
 
 
 
752
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\WhiteLabel\\ApplyLabels' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/WhiteLabel/ApplyLabels.php',
753
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\ModCon' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/ModCon.php',
754
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Options' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Options.php',
@@ -947,6 +969,7 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
947
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Github\\ListTags' => __DIR__ . '/../..' . '/src/Utilities/Github/ListTags.php',
948
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\HCaptcha\\TestRequest' => __DIR__ . '/../..' . '/src/Utilities/HCaptcha/TestRequest.php',
949
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\HumanSpam\\TestContent' => __DIR__ . '/../..' . '/src/Utilities/HumanSpam/TestContent.php',
 
950
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Options\\CleanStorage' => __DIR__ . '/../..' . '/src/Utilities/Options/CleanStorage.php',
951
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\ReCaptcha\\Enqueue' => __DIR__ . '/../..' . '/src/Utilities/ReCaptcha/Enqueue.php',
952
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\ReCaptcha\\TestRequest' => __DIR__ . '/../..' . '/src/Utilities/ReCaptcha/TestRequest.php',
383
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\AjaxHandler' => __DIR__ . '/../..' . '/src/Modules/Base/AjaxHandler.php',
384
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Debug' => __DIR__ . '/../..' . '/src/Modules/Base/Debug.php',
385
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Insights\\OverviewCards' => __DIR__ . '/../..' . '/src/Modules/Base/Insights/OverviewCards.php',
386
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Request\\FormParams' => __DIR__ . '/../..' . '/src/Modules/Base/Lib/Request/FormParams.php',
387
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\ModCon' => __DIR__ . '/../..' . '/src/Modules/Base/ModCon.php',
388
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Options' => __DIR__ . '/../..' . '/src/Modules/Base/Options.php',
389
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Options\\OptValueSanitize' => __DIR__ . '/../..' . '/src/Modules/Base/Options/OptValueSanitize.php',
433
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Processor' => __DIR__ . '/../..' . '/src/Modules/Events/Processor.php',
434
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Reporting' => __DIR__ . '/../..' . '/src/Modules/Events/Reporting.php',
435
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Strings' => __DIR__ . '/../..' . '/src/Modules/Events/Strings.php',
436
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\UI' => __DIR__ . '/../..' . '/src/Modules/Events/UI.php',
437
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\Insights\\OverviewCards' => __DIR__ . '/../..' . '/src/Modules/Firewall/Insights/OverviewCards.php',
438
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\Lib\\Scan\\CanScan' => __DIR__ . '/../..' . '/src/Modules/Firewall/Lib/Scan/CanScan.php',
439
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\Lib\\Scan\\Checks\\Base' => __DIR__ . '/../..' . '/src/Modules/Firewall/Lib/Scan/Checks/Base.php',
440
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\Lib\\Scan\\Checks\\ExeFiles' => __DIR__ . '/../..' . '/src/Modules/Firewall/Lib/Scan/Checks/ExeFiles.php',
441
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\Lib\\Scan\\Checks\\Standard' => __DIR__ . '/../..' . '/src/Modules/Firewall/Lib/Scan/Checks/Standard.php',
442
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\Lib\\Scan\\ParametersToScan' => __DIR__ . '/../..' . '/src/Modules/Firewall/Lib/Scan/ParametersToScan.php',
443
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\Lib\\Scan\\PerformScan' => __DIR__ . '/../..' . '/src/Modules/Firewall/Lib/Scan/PerformScan.php',
444
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\ModCon' => __DIR__ . '/../..' . '/src/Modules/Firewall/ModCon.php',
445
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\Options' => __DIR__ . '/../..' . '/src/Modules/Firewall/Options.php',
446
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Firewall\\Processor' => __DIR__ . '/../..' . '/src/Modules/Firewall/Processor.php',
549
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\AutoUnblock' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/AutoUnblock.php',
550
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\BlacklistHandler' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/BlacklistHandler.php',
551
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\BlockRequest' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/BlockRequest.php',
552
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\BotEventListener' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/Bots/BotEventListener.php',
553
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\BotSignalsController' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/Bots/BotSignalsController.php',
554
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\BotSignalsRecord' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/Bots/BotSignalsRecord.php',
555
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\Calculator\\BuildScores' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/Bots/Calculator/BuildScores.php',
556
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\Calculator\\CalculateVisitorBotScores' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/Bots/Calculator/CalculateVisitorBotScores.php',
 
557
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\NotBot\\InsertNotBotJs' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/Bots/NotBot/InsertNotBotJs.php',
558
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\NotBot\\NotBotHandler' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/Bots/NotBot/NotBotHandler.php',
559
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\IpAnalyse\\BuildDisplay' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/IpAnalyse/BuildDisplay.php',
575
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\WpCli\\BaseAddRemove' => __DIR__ . '/../..' . '/src/Modules/IPs/WpCli/BaseAddRemove.php',
576
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\WpCli\\Enumerate' => __DIR__ . '/../..' . '/src/Modules/IPs/WpCli/Enumerate.php',
577
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\WpCli\\Remove' => __DIR__ . '/../..' . '/src/Modules/IPs/WpCli/Remove.php',
578
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\AjaxHandler' => __DIR__ . '/../..' . '/src/Modules/Insights/AjaxHandler.php',
579
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Lib\\OverviewCards' => __DIR__ . '/../..' . '/src/Modules/Insights/Lib/OverviewCards.php',
580
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Lib\\Requests\\DynamicPageLoader' => __DIR__ . '/../..' . '/src/Modules/Insights/Lib/Requests/DynamicPageLoader.php',
581
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Lib\\SideMenuBuilder' => __DIR__ . '/../..' . '/src/Modules/Insights/Lib/SideMenuBuilder.php',
582
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\ModCon' => __DIR__ . '/../..' . '/src/Modules/Insights/ModCon.php',
583
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Options' => __DIR__ . '/../..' . '/src/Modules/Insights/Options.php',
584
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Strings' => __DIR__ . '/../..' . '/src/Modules/Insights/Strings.php',
758
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\AdminNotices' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/AdminNotices.php',
759
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\AjaxHandler' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/AjaxHandler.php',
760
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Insights\\OverviewCards' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Insights/OverviewCards.php',
761
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\Ops\\RemoveSecAdmin' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Ops/RemoveSecAdmin.php',
762
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\Ops\\SetSecAdminPin' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Ops/SetSecAdminPin.php',
763
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\Ops\\ToggleSecAdminStatus' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Ops/ToggleSecAdminStatus.php',
764
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\Ops\\VerifyPinRequest' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Ops/VerifyPinRequest.php',
765
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\Restrictions\\Base' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/Base.php',
766
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\Restrictions\\BaseCapabilitiesRestrict' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/BaseCapabilitiesRestrict.php',
767
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\Restrictions\\Plugins' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/Plugins.php',
768
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\Restrictions\\Posts' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/Posts.php',
769
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\Restrictions\\Themes' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/Themes.php',
770
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\Restrictions\\Users' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/Users.php',
771
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\Restrictions\\WpOptions' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/WpOptions.php',
772
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\SecurityAdminController' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/SecurityAdminController.php',
773
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\VerifySecurityAdminList' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/VerifySecurityAdminList.php',
774
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\WhiteLabel\\ApplyLabels' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/WhiteLabel/ApplyLabels.php',
775
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\ModCon' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/ModCon.php',
776
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Options' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Options.php',
969
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Github\\ListTags' => __DIR__ . '/../..' . '/src/Utilities/Github/ListTags.php',
970
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\HCaptcha\\TestRequest' => __DIR__ . '/../..' . '/src/Utilities/HCaptcha/TestRequest.php',
971
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\HumanSpam\\TestContent' => __DIR__ . '/../..' . '/src/Utilities/HumanSpam/TestContent.php',
972
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Nonce\\Handler' => __DIR__ . '/../..' . '/src/Utilities/Nonce/Handler.php',
973
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Options\\CleanStorage' => __DIR__ . '/../..' . '/src/Utilities/Options/CleanStorage.php',
974
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\ReCaptcha\\Enqueue' => __DIR__ . '/../..' . '/src/Utilities/ReCaptcha/Enqueue.php',
975
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\ReCaptcha\\TestRequest' => __DIR__ . '/../..' . '/src/Utilities/ReCaptcha/TestRequest.php',
src/lib/vendor/fernleafsystems/wordpress-services/src/Core/Request.php CHANGED
@@ -3,38 +3,19 @@
3
  namespace FernleafSystems\Wordpress\Services\Core;
4
 
5
  use Carbon\Carbon;
 
6
  use FernleafSystems\Wordpress\Services\Services;
7
 
8
  /**
9
  * Class Request
10
  * @package FernleafSystems\Wordpress\Services\Core
 
 
 
 
 
11
  */
12
- class Request {
13
-
14
- /**
15
- * @var array
16
- */
17
- private $post;
18
-
19
- /**
20
- * @var array
21
- */
22
- private $query;
23
-
24
- /**
25
- * @var array
26
- */
27
- private $cookie;
28
-
29
- /**
30
- * @var array
31
- */
32
- private $server;
33
-
34
- /**
35
- * @var array
36
- */
37
- private $env;
38
 
39
  /**
40
  * @var int
@@ -57,12 +38,7 @@ class Request {
57
  public function __construct() {
58
  $this->post = is_array( $_POST ) ? $_POST : [];
59
  $this->query = is_array( $_GET ) ? $_GET : [];
60
- if ( is_array( $_COOKIE ) ) {
61
- $this->cookie = &$_COOKIE;
62
- }
63
- else {
64
- $this->cookie = [];
65
- }
66
  $this->server = is_array( $_SERVER ) ? $_SERVER : [];
67
  $this->env = is_array( $_ENV ) ? $_ENV : [];
68
  $this->ts();
@@ -240,7 +216,7 @@ class Request {
240
  }
241
 
242
  /**
243
- * @param array $container
244
  * @param string $key
245
  * @param mixed $default
246
  * @return mixed|null
3
  namespace FernleafSystems\Wordpress\Services\Core;
4
 
5
  use Carbon\Carbon;
6
+ use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
7
  use FernleafSystems\Wordpress\Services\Services;
8
 
9
  /**
10
  * Class Request
11
  * @package FernleafSystems\Wordpress\Services\Core
12
+ * @property array $post
13
+ * @property array $query
14
+ * @property array $cookie
15
+ * @property array $server
16
+ * @property array $env
17
  */
18
+ class Request extends DynPropertiesClass {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
  /**
21
  * @var int
38
  public function __construct() {
39
  $this->post = is_array( $_POST ) ? $_POST : [];
40
  $this->query = is_array( $_GET ) ? $_GET : [];
41
+ $this->cookie = is_array( $_COOKIE ) ? $_COOKIE : [];
 
 
 
 
 
42
  $this->server = is_array( $_SERVER ) ? $_SERVER : [];
43
  $this->env = is_array( $_ENV ) ? $_ENV : [];
44
  $this->ts();
216
  }
217
 
218
  /**
219
+ * @param array $container
220
  * @param string $key
221
  * @param mixed $default
222
  * @return mixed|null
src/wizards/base.php CHANGED
@@ -272,9 +272,7 @@ abstract class ICWP_WPSF_Wizard_Base {
272
  'mod_wizards' => $wizards
273
  ],
274
  'hrefs' => [
275
- 'dashboard' => $this->getCon()
276
- ->getModule_Insights()
277
- ->getUrl_SubInsightsPage( 'dashboard' ),
278
  'goprofooter' => 'https://shsec.io/goprofooter',
279
  ],
280
  'ajax' => [
@@ -314,9 +312,7 @@ abstract class ICWP_WPSF_Wizard_Base {
314
  'wizard_first_step' => json_encode( $this->getWizardFirstStep() ),
315
  ],
316
  'hrefs' => [
317
- 'dashboard' => $this->getCon()
318
- ->getModule_Insights()
319
- ->getUrl_SubInsightsPage( 'dashboard' ),
320
  'goprofooter' => 'https://shsec.io/goprofooter',
321
  ],
322
  'ajax' => [
@@ -405,9 +401,7 @@ abstract class ICWP_WPSF_Wizard_Base {
405
  'has_other_wizards' => false
406
  ],
407
  'hrefs' => [
408
- 'dashboard' => $this->getCon()
409
- ->getModule_Insights()
410
- ->getUrl_SubInsightsPage( 'dashboard' ),
411
  'gopro' => 'https://shsec.io/ap',
412
  ],
413
  'imgs' => [],
272
  'mod_wizards' => $wizards
273
  ],
274
  'hrefs' => [
275
+ 'dashboard' => $this->getCon()->getPluginUrl_DashboardHome(),
 
 
276
  'goprofooter' => 'https://shsec.io/goprofooter',
277
  ],
278
  'ajax' => [
312
  'wizard_first_step' => json_encode( $this->getWizardFirstStep() ),
313
  ],
314
  'hrefs' => [
315
+ 'dashboard' => $this->getCon()->getPluginUrl_DashboardHome(),
 
 
316
  'goprofooter' => 'https://shsec.io/goprofooter',
317
  ],
318
  'ajax' => [
401
  'has_other_wizards' => false
402
  ],
403
  'hrefs' => [
404
+ 'dashboard' => $this->getCon()->getPluginUrl_DashboardHome(),
 
 
405
  'gopro' => 'https://shsec.io/ap',
406
  ],
407
  'imgs' => [],
src/wizards/base_wpsf.php CHANGED
@@ -93,29 +93,26 @@ abstract class ICWP_WPSF_Wizard_BaseWpsf extends ICWP_WPSF_Wizard_Base {
93
  * @return \FernleafSystems\Utilities\Response
94
  */
95
  private function wizardSecurityAdminVerify() {
96
- $sKey = Services::Request()->post( 'AccessKey' );
97
 
98
- $oResponse = new \FernleafSystems\Utilities\Response();
 
 
99
 
100
- $bSuccess = false;
101
- $mod = $this->getCon()->getModule_SecAdmin();
102
-
103
- $sMessage = '';
104
- if ( empty( $sKey ) ) {
105
- $sMessage = 'Security Admin PIN was empty.';
106
  }
107
- elseif ( !$mod->verifyAccessKey( $sKey ) ) {
108
- $sMessage = __( 'Security Admin PIN was not correct.', 'wp-simple-firewall' );
109
  }
110
  else {
111
- $bSuccess = $mod->setSecurityAdminStatusOnOff( true );
112
- $aData = [
113
  'rerender' => true
114
- ];
115
- $oResponse->setData( $aData );
116
  }
117
 
118
- return $oResponse->setSuccessful( $bSuccess )
119
- ->setMessageText( $sMessage );
120
  }
121
  }
93
  * @return \FernleafSystems\Utilities\Response
94
  */
95
  private function wizardSecurityAdminVerify() {
96
+ $pin = Services::Request()->post( 'sec_admin_key' );
97
 
98
+ $response = new \FernleafSystems\Utilities\Response();
99
+ $success = false;
100
+ $msg = '';
101
 
102
+ if ( empty( $pin ) ) {
103
+ $msg = 'Security Admin PIN was empty.';
 
 
 
 
104
  }
105
+ elseif ( !$this->getCon()->getModule_SecAdmin()->getSecurityAdminController()->verifyPinRequest() ) {
106
+ $msg = __( 'Security Admin PIN was not correct.', 'wp-simple-firewall' );
107
  }
108
  else {
109
+ $success = true;
110
+ $response->setData( [
111
  'rerender' => true
112
+ ] );
 
113
  }
114
 
115
+ return $response->setSuccessful( $success )
116
+ ->setMessageText( $msg );
117
  }
118
  }
src/wizards/plugin.php CHANGED
@@ -370,8 +370,8 @@ class ICWP_WPSF_Wizard_Plugin extends ICWP_WPSF_Wizard_BaseWpsf {
370
  $mod = $this->getCon()->getModule_License();
371
  try {
372
  $success = $mod->getLicenseHandler()
373
- ->verify( true )
374
- ->hasValidWorkingLicense();
375
  if ( $success ) {
376
  $msg = __( 'License was found and successfully installed.', 'wp-simple-firewall' );
377
  }
@@ -432,33 +432,32 @@ class ICWP_WPSF_Wizard_Plugin extends ICWP_WPSF_Wizard_BaseWpsf {
432
  * @return \FernleafSystems\Utilities\Response
433
  */
434
  private function wizardSecurityAdmin() {
435
- $oReq = Services::Request();
436
- $pin = $oReq->post( 'AccessKey' );
437
- $sConfirm = $oReq->post( 'AccessKeyConfirm' );
438
 
439
- $bSuccess = false;
440
  if ( empty( $pin ) ) {
441
- $sMessage = __( "Security Admin PIN was empty.", 'wp-simple-firewall' );
442
  }
443
- elseif ( $pin != $sConfirm ) {
444
- $sMessage = __( "Security PINs don't match.", 'wp-simple-firewall' );
445
  }
446
  else {
447
  $mod = $this->getCon()->getModule_SecAdmin();
448
  try {
449
- $mod->setNewPinManually( $pin )
450
- ->setSecurityAdminStatusOnOff( true );
451
- $bSuccess = true;
452
- $sMessage = __( 'Security Admin PIN setup was successful.', 'wp-simple-firewall' );
453
  }
454
  catch ( \Exception $e ) {
455
- $sMessage = __( $e->getMessage(), 'wp-simple-firewall' );
456
  }
457
  }
458
 
459
  return ( new \FernleafSystems\Utilities\Response() )
460
- ->setSuccessful( $bSuccess )
461
- ->setMessageText( $sMessage );
462
  }
463
 
464
  /**
370
  $mod = $this->getCon()->getModule_License();
371
  try {
372
  $success = $mod->getLicenseHandler()
373
+ ->verify( true )
374
+ ->hasValidWorkingLicense();
375
  if ( $success ) {
376
  $msg = __( 'License was found and successfully installed.', 'wp-simple-firewall' );
377
  }
432
  * @return \FernleafSystems\Utilities\Response
433
  */
434
  private function wizardSecurityAdmin() {
435
+ $req = Services::Request();
436
+ $pin = $req->post( 'sec_admin_key' );
437
+ $confirm = $req->post( 'AccessKeyConfirm' );
438
 
439
+ $success = false;
440
  if ( empty( $pin ) ) {
441
+ $msg = __( "Security Admin PIN was empty.", 'wp-simple-firewall' );
442
  }
443
+ elseif ( $pin != $confirm ) {
444
+ $msg = __( "Security PINs don't match.", 'wp-simple-firewall' );
445
  }
446
  else {
447
  $mod = $this->getCon()->getModule_SecAdmin();
448
  try {
449
+ $mod->setNewPinManually( $pin );
450
+ $success = true;
451
+ $msg = __( 'Security Admin PIN setup was successful.', 'wp-simple-firewall' );
 
452
  }
453
  catch ( \Exception $e ) {
454
+ $msg = __( $e->getMessage(), 'wp-simple-firewall' );
455
  }
456
  }
457
 
458
  return ( new \FernleafSystems\Utilities\Response() )
459
+ ->setSuccessful( $success )
460
+ ->setMessageText( $msg );
461
  }
462
 
463
  /**
templates/php/snippets/plugin-deactivate-survey.php DELETED
@@ -1,14 +0,0 @@
1
- <div id="icwpWpsfSurvey" class="hidden icwp-wpsf-dialog">
2
- <p>Deactivating Shield makes us sad, but you can help us improve by letting us know why.</p>
3
- <p>This is optional - will you take a second to tell us why you're deactivating Shield?</p>
4
- <form id="icwpWpsfSurveyForm">
5
- <ul>
6
- <?php foreach ( $inputs[ 'checkboxes' ] as $sKey => $sOpt ) : ?>
7
- <li><label><input name="<?php echo $sKey; ?>" type="checkbox" value="Y">
8
- <?php echo $sOpt; ?></label></li>
9
- <?php endforeach; ?>
10
- </ul>
11
- <textarea name="reason_comments" style="width: 360px;" rows="3"
12
- placeholder="If you got errors, for example, could you outline the problems you had?"></textarea>
13
- </form>
14
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
templates/twig/components/events/stats/stat_box.twig ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <div class="card h-100 stat_box">
2
+ <div class="card-header">
3
+ {{ stat.name }}
4
+ </div>
5
+ <div class="card-body d-flex flex-row text-center justify-content-center">
6
+ <div class="stat_count">{{ attribute(stat.counts, stat_to_show|default('lifetime')) }}</div>
7
+ </div>
8
+ </div>
templates/twig/components/events/stats/stats_collection.twig ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+
2
+ {% for stats_section in vars.stats %}
3
+ <div class="row row-cols-md-3 row-cols-lg-4 row-cols-xl-6 ">
4
+ {% for stat in stats_section %}
5
+ <div class=" col mb-4">
6
+ {% include '/components/events/stats/stat_box.twig' %}
7
+ </div>
8
+ {% endfor %}
9
+ </div>
10
+ {% endfor %}
templates/twig/components/options_form/main.twig CHANGED
@@ -1,5 +1,9 @@
1
- <form action="{{ form_action }}" method="post" class="icwpOptionsForm form" novalidate="novalidate"
2
- autocomplete="off">
 
 
 
 
3
 
4
  <div id="ModuleOptionsNav" class="insights-sub-nav" aria-orientation="horizontal">
5
  <ul class="nav nav-tabs" role="tablist">
@@ -25,20 +29,25 @@
25
 
26
  <div class="row">
27
  <div class="col-12">
28
- <h5 class="mb-3 mt-3">
29
- {{ opt_section.title }}
30
 
31
  {% if ( opt_section.summary is defined ) and opt_section.summary|length %}
32
  <a class="section_title_info"
33
- data-toggle="popover"
34
- data-content="<ul>
35
- {% for item in opt_section.summary %}
36
- <li class='mt-2'>{{ item|raw|escape }}</li>
37
- {% endfor %}
38
- </ul>">
39
- <span class="dashicons dashicons-info"></span></a>
 
 
 
 
 
 
40
  {% endif %}
41
-
42
  </h5>
43
  </div>
44
  </div>
1
+ <form action="{{ form_action }}" method="post"
2
+ class="icwpOptionsForm form"
3
+ novalidate="novalidate"
4
+ autocomplete="off"
5
+ data-mod_slug="{{ vars.mod_slug }}"
6
+ >
7
 
8
  <div id="ModuleOptionsNav" class="insights-sub-nav" aria-orientation="horizontal">
9
  <ul class="nav nav-tabs" role="tablist">
29
 
30
  <div class="row">
31
  <div class="col-12">
32
+ <h5 class="mt-3">
33
+ <span class="mb-3 d-inline-block">{{ opt_section.title }}</span>
34
 
35
  {% if ( opt_section.summary is defined ) and opt_section.summary|length %}
36
  <a class="section_title_info"
37
+ data-toggle="collapse"
38
+ data-target="#collapse-{{ opt_section.slug }}"
39
+ ><span class="dashicons dashicons-info"></span></a>
40
+ <br />
41
+ <div class="collapse mb-3" id="collapse-{{ opt_section.slug }}">
42
+ <div class="card">
43
+ <div class="card-body">
44
+ {% for item in opt_section.summary %}
45
+ <p class="card-text">{{ item|raw }}</p>
46
+ {% endfor %}
47
+ </div>
48
+ </div>
49
+ </div>
50
  {% endif %}
 
51
  </h5>
52
  </div>
53
  </div>
templates/twig/components/search/dialog.twig ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="modal fade"
2
+ role="dialog"
3
+ id="SearchDialog"
4
+ tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true"
5
+ >
6
+ <div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
7
+ <div class="modal-content">
8
+ <div class="modal-header">
9
+ <h5 class="modal-title" id="exampleModalLabel">Search The Plugin For Options</h5>
10
+ </div>
11
+ <div class="modal-body">
12
+ <div class="container-fluid">
13
+ <div class="row no-gutters row-cols-1">
14
+ <div class="col">
15
+ {% include '/components/search/options.twig' %}
16
+ </div>
17
+ </div>
18
+ </div>
19
+ </div>
20
+ </div>
21
+ </div>
22
+ </div>
templates/twig/components/search/options.twig ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% if vars.search_select is defined %}
2
+ <select class="selectpicker" data-live-search="true"
3
+ title="Search For Plugin Option"
4
+ data-size="10"
5
+ data-header=""
6
+ onchange="location = this.value;"
7
+ style="max-width: 100%; width: 100%"
8
+ >
9
+ {% for select_section_name,select_section_opts in vars.search_select|default([]) %}
10
+ <optgroup label="{{ select_section_name }}">
11
+ {% for select_opt_key,select_opt_data in select_section_opts %}
12
+ <option value="{{ select_opt_data.href }}"
13
+ aria-selected="false"
14
+ data-tokens="{{ select_opt_data.summary }} {{ select_opt_data.description|join(' ') }}"
15
+ >{{ select_opt_data.name }}
16
+ </option>
17
+ {% endfor %}
18
+ </optgroup>
19
+ {% endfor %}
20
+ </select>
21
+ {% endif %}
templates/twig/components/security_admin/login_box.twig ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div id="WpsfAdminAccessLogin" style="display:none;">
2
+ <div class="bootstrap-wpadmin wpsf-admin-access-login"
3
+ id="SecAdminDialog">
4
+ <div class="input-holder" id="SecAdminPinInputContainer">
5
+ <label>
6
+ {{ strings.access_message }}
7
+ <input id="SecAdminPinInput" type="password" name="sec_admin_key" />
8
+ <button type="submit">Go!</button>
9
+ </label>
10
+ </div>
11
+
12
+ </div>
13
+ </div>
14
+
15
+ <style type="text/css">
16
+ .input-holder label {
17
+ font-size: 24px;
18
+ }
19
+ .input-holder label {
20
+ font-size: inherit;
21
+ display: block;
22
+ margin: 6% 107px;
23
+ vertical-align: middle;
24
+ }
25
+ .input-holder input {
26
+ font-size: inherit;
27
+ height: 60px;
28
+ vertical-align: middle;
29
+ width: 180px;
30
+ }
31
+ </style>
32
+
33
+ <script type="text/javascript">
34
+
35
+ {# let $oThisAAL = jQuery( '#AdminInputHolder' );#}
36
+ {# let $oInput = jQuery( 'input', $oThisAAL );#}
37
+ {# jQuery( document ).ready(#}
38
+ {# function () {#}
39
+
40
+ {# jQuery( document ).on( 'click', '#SecAdminDialog button', submit_admin_access );#}
41
+ {# jQuery( 'input', $oThisAAL ).keypress( function ( e ) {#}
42
+ {# if ( e.which === 13 ) {#}
43
+ {# submit_admin_access();#}
44
+ {# }#}
45
+ {# } );#}
46
+ {# }#}
47
+ {# );#}
48
+
49
+ {# function submit_admin_access() {#}
50
+ {# $oThisAAL.html( '<div class="spinner"></div>' );#}
51
+ {# jQuery( 'input', $oThisAAL ).prop( 'disabled', true );#}
52
+
53
+ {# var requestData = {{ ajax.sec_admin_login|raw }};#}
54
+ {# requestData[ 'sec_admin_key' ] = $oInput.val();#}
55
+
56
+ {# jQuery.post( ajaxurl, requestData, function ( oResponse ) {#}
57
+ {# if ( oResponse.success ) {#}
58
+ {# location.reload();#}
59
+ {# }#}
60
+ {# if ( oResponse.data ) {#}
61
+ {# $oThisAAL.html( oResponse.data.html );#}
62
+ {# }#}
63
+ {# else {#}
64
+ {# $oThisAAL.html( 'There was an unknown error' );#}
65
+ {# }#}
66
+ {# } );#}
67
+ {# }#}
68
+ </script>
templates/twig/email/lp_2fa_email_code.twig CHANGED
@@ -16,6 +16,8 @@
16
  <li>{{ body.strings.details_ip }}</li>
17
  </ul>
18
 
 
 
19
  {% if body.flags.show_login_link %}
20
  <a href="{{ body.hrefs.login_link }}" target="_blank">{{ body.strings.login_link }}</a>
21
  {% endif %}
16
  <li>{{ body.strings.details_ip }}</li>
17
  </ul>
18
 
19
+ {# <p>{{ body.hrefs.verify_2fa }}</p>#}
20
+
21
  {% if body.flags.show_login_link %}
22
  <a href="{{ body.hrefs.login_link }}" target="_blank">{{ body.strings.login_link }}</a>
23
  {% endif %}
templates/twig/pages/block/blocklist_die.twig CHANGED
@@ -9,10 +9,10 @@
9
  <style>
10
  #UAU hr {
11
  margin: 40px 40px 30px;
12
- color: rgba(0,0,0,0.5);
13
  }
14
  #UAU h3 {
15
- margin: 20px 40px 30px ;
16
  }
17
  .uau {
18
  width: 75%;
@@ -22,19 +22,18 @@
22
  background-color: rgba(0, 0, 0, 0.02);
23
  }
24
  .uau p {
25
- margin: 10px 0 !important;
26
  }
27
  </style>
28
  {% if flags.is_autorecover %}
29
  <div id="UAU">
30
- <hr style=""/>
31
  <div class="auto-recover">
32
  <h3 style="">{{ strings.unblock.title }}</h3>
33
  {% if flags.is_uaug_permitted %}
34
  <div class="uaug uau">
35
  <p>{{ strings.unblock.you_can }}</p>
36
- <form method="post" action="#">
37
- {{ vars.gasp_element|raw }}
38
  <input type="hidden" name="email" value="" />
39
  <input type="hidden" name="ip" value="{{ vars.ip }}" />
40
  {% for key,val in vars.nonce %}
9
  <style>
10
  #UAU hr {
11
  margin: 40px 40px 30px;
12
+ color: rgba(0, 0, 0, 0.5);
13
  }
14
  #UAU h3 {
15
+ margin: 20px 40px 20px;
16
  }
17
  .uau {
18
  width: 75%;
22
  background-color: rgba(0, 0, 0, 0.02);
23
  }
24
  .uau p {
25
+ margin: 0 0 10px !important;
26
  }
27
  </style>
28
  {% if flags.is_autorecover %}
29
  <div id="UAU">
30
+ <hr style="" />
31
  <div class="auto-recover">
32
  <h3 style="">{{ strings.unblock.title }}</h3>
33
  {% if flags.is_uaug_permitted %}
34
  <div class="uaug uau">
35
  <p>{{ strings.unblock.you_can }}</p>
36
+ <form method="post" action="{{ hrefs.home }}">
 
37
  <input type="hidden" name="email" value="" />
38
  <input type="hidden" name="ip" value="{{ vars.ip }}" />
39
  {% for key,val in vars.nonce %}
templates/twig/snippets/select_search_options.twig DELETED
@@ -1,21 +0,0 @@
1
- <select class="select2picker" data-live-search="true"
2
- title="Search For Plugin Option"
3
- data-size="10"
4
- data-header=""
5
- onchange="location = this.value;"
6
- style="max-width: 100%; width: 100%"
7
- >
8
- <option value="">
9
- -- Search For Plugin Setting --
10
- </option>
11
- {% for select_section_name,select_section_opts in vars.search_select %}
12
- <optgroup label="{{ select_section_name }}">
13
- {% for select_opt_key,select_opt_data in select_section_opts %}
14
- <option value="{{ select_opt_data.href }}" aria-selected="false"
15
- data-tokens="{{ select_opt_data.summary }}"
16
- >{{ select_opt_data.name }}
17
- </option>
18
- {% endfor %}
19
- </optgroup>
20
- {% endfor %}
21
- </select>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
templates/twig/wizard/slides/common/security_admin_verify.twig CHANGED
@@ -8,7 +8,7 @@
8
  <form class="form-horizontal icwp-wizard-form">
9
  {{ icwp_macros.formInput_Hidden( 'current_index', current_index ) }}
10
  {{ icwp_macros.formInput_Hidden( 'wizard-step', 'security_admin_verify' ) }}
11
- {{ icwp_macros.formInput_Password( 'AccessKey', '', 'Security PIN' ) }}
12
  {{ icwp_macros.formInput_Submit( 'Submit Key' ) }}
13
  </form>
14
 
8
  <form class="form-horizontal icwp-wizard-form">
9
  {{ icwp_macros.formInput_Hidden( 'current_index', current_index ) }}
10
  {{ icwp_macros.formInput_Hidden( 'wizard-step', 'security_admin_verify' ) }}
11
+ {{ icwp_macros.formInput_Password( 'sec_admin_key', '', 'Security PIN' ) }}
12
  {{ icwp_macros.formInput_Submit( 'Submit Key' ) }}
13
  </form>
14
 
templates/twig/wizard/slides/welcome/admin_access_restriction.twig CHANGED
@@ -26,7 +26,7 @@
26
  <h6>Supply A New Security Access PIN</h6>
27
  <p><strong>Warning</strong>: You must remember this key to regain access to the Shield plugin.</p>
28
  <form class="form-horizontal icwp-wizard-form">
29
- {{ icwp_macros.formInput_Password( 'AccessKey', '', 'Access PIN', '', 'Do not forget this key' ) }}
30
  {{ icwp_macros.formInput_Password( 'AccessKeyConfirm', '', 'Confirm PIN', 'Confirm PIN' ) }}
31
  {{ icwp_macros.formInput_Hidden( 'wizard-step', 'admin_access_restriction' ) }}
32
  {{ icwp_macros.formInput_Submit( 'Turn On Security Admin' ) }}
26
  <h6>Supply A New Security Access PIN</h6>
27
  <p><strong>Warning</strong>: You must remember this key to regain access to the Shield plugin.</p>
28
  <form class="form-horizontal icwp-wizard-form">
29
+ {{ icwp_macros.formInput_Password( 'sec_admin_key', '', 'Access PIN', '', 'Do not forget this key' ) }}
30
  {{ icwp_macros.formInput_Password( 'AccessKeyConfirm', '', 'Confirm PIN', 'Confirm PIN' ) }}
31
  {{ icwp_macros.formInput_Hidden( 'wizard-step', 'admin_access_restriction' ) }}
32
  {{ icwp_macros.formInput_Submit( 'Turn On Security Admin' ) }}
templates/twig/wpadmin_pages/base.twig CHANGED
@@ -14,7 +14,28 @@
14
 
15
  <div class="row" id="odp-PageMain">
16
  <div class="col">
17
- {% block page_main %}Override this block for the body area{% endblock %}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  </div>
19
  </div>
20
 
@@ -29,5 +50,8 @@
29
  </div>
30
  </div>
31
 
 
 
32
  {% block inline_scripts %}
 
33
  {% endblock %}
14
 
15
  <div class="row" id="odp-PageMain">
16
  <div class="col">
17
+
18
+ <div class="row">
19
+
20
+ <div id="apto-PageMainSide"
21
+ class="col-sm-3 col-md-2 col-lg-2 col-xl-2">
22
+ {% block page_main_side %}
23
+ {% include '/wpadmin_pages/components/page/nav_sidebar.twig' %}
24
+ {% endblock %}
25
+ </div>
26
+
27
+ <div id="apto-PageMainBody"
28
+ class="col-sm-9 col-md-10 col-lg-10 col-xl-10">
29
+ {% block page_main %}
30
+ <div class="row">
31
+ <div class="col">
32
+ </div>
33
+ </div>
34
+ {% endblock %}
35
+ </div>
36
+
37
+ </div>
38
+
39
  </div>
40
  </div>
41
 
50
  </div>
51
  </div>
52
 
53
+ {% include '/components/search/dialog.twig' %}
54
+
55
  {% block inline_scripts %}
56
+ {% include '/snippets/js/freshdesk_chatbot.twig' %}
57
  {% endblock %}
templates/twig/wpadmin_pages/components/page/nav_sidebar.twig ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div id="NavSideBar" class="tour-navigation_v1">
2
+
3
+ <ul class="nav flex-column mt-4">
4
+ {% for mitem in vars.navbar_menu %}
5
+
6
+ <li class="nav-item mb-4 {{ mitem.classes|default([])|join( ' ' ) }}"
7
+ {% if mitem.id|default('') is not empty %}id="{{ mitem.id }}"{% endif %}
8
+ >
9
+
10
+ <a class="nav-link p-0 {% if mitem.active %}active{% endif %}"
11
+ href="{{ mitem.href|default('#') }}"
12
+ {% for data_key,data_val in mitem.data|default([]) %}
13
+ data-{{ data_key }}="{{ data_val }}"
14
+ {% endfor %}
15
+ {% if sub.target|default('') is not empty %}target="{{ sub.target }}"{% endif %}
16
+ {% if mitem.introjs|default('') is not empty %}data-intro="{{ mitem.introjs }}"{% endif %}
17
+ >
18
+ {% if mitem.img|default('') is not empty %}
19
+ <span class="nav-icon mr-1" style="vertical-align: text-bottom;">
20
+ <img src="{{ mitem.img }}"
21
+ class="img-fluid"
22
+ width="16px"
23
+ alt="...">
24
+ </span>
25
+ {% endif %}
26
+ <span>{{ mitem.title }}</span>
27
+ {% if mitem.badge|default([]) is not empty %}
28
+ <span class="badge badge-{{ mitem.badge.type|default('info') }}">
29
+ {{ mitem.badge.text }}
30
+ </span>
31
+ {% endif %}
32
+ </a>
33
+
34
+ {% if mitem.sub_items|default([]) is not empty %}
35
+ <div class="collapse {% if mitem.active %}show{% endif %}" id="collapse-{{ mitem.slug }}">
36
+ <ul class="nav flex-column pt-0 primary_sub_menu pl-4">
37
+ {% for sub in mitem.sub_items %}
38
+ <li class="nav-item mb-0 {{ sub.classes|default([])|join( ' ' ) }}">
39
+ <a class="pl-0 pb-0 pt-2 nav-link {% if sub.active|default(false) %}active{% endif %}"
40
+ href="{{ sub.href|default('#') }}"
41
+ {% for data_key,data_val in sub.data|default([]) %}
42
+ data-{{ data_key }}="{{ data_val }}"
43
+ {% endfor %}
44
+ {% if sub.target|default('') is not empty %}target="{{ sub.target }}"{% endif %}
45
+ >{{ sub.title }}</a>
46
+ </li>
47
+ {% endfor %}
48
+ </ul>
49
+ </div>
50
+ {% endif %}
51
+
52
+ </li>
53
+
54
+ {% endfor %}
55
+ </ul>
56
+ </div>
templates/twig/wpadmin_pages/insights/audit/audit_table.twig CHANGED
@@ -1,82 +1,68 @@
1
  <div class="row insights_widget" id="SectionAuditTable">
2
 
3
  <div class="col">
4
- {# <p>#}
5
- {# <a href="{{ hrefs.audit_trail_glossary }}" target="_blank">{{ strings.audit_trail_glossary }}</a>#}
6
- {# </p>#}
7
 
8
- <form id="AuditFilterForm" autocomplete="off" class="px-3 pt-3">
9
- <div class="form-row">
10
-
11
- <div class="col-auto mb-3">
12
- <label class="sr-only" for="_fUsername">{{ strings.username }}</label>
13
- <select id="_fUsername" name="fUsername" class="form-control">
14
- <option value="">-- {{ strings.username }} --</option>
15
- {% for uniq_user in vars.unique_users %}
16
- <option value="{{ uniq_user }}">{{ uniq_user }}</option>
17
- {% endfor %}
18
- </select>
19
- {# <small id="fUsernameHelp" class="form-text text-muted">{{ strings.username_ignores }}</small> #}
20
- </div>
21
-
22
- <div class="col-auto mb-3">
23
- <label class="sr-only" for="_fIp">{{ strings.ip_address }}</label>
24
- <select id="_fIp" name="fIp" class="form-control">
25
- <option value="">-- {{ strings.ip_address }} --</option>
26
- {% for unique_ip in vars.unique_ips %}
27
- <option value="{{ unique_ip }}">{{ unique_ip }}</option>
28
- {% endfor %}
29
- </select>
30
- </div>
31
-
32
- <div class="col-auto mb-3">
33
- <label class="sr-only" for="_fEvent">{{ strings.event }}</label>
34
- <select id="_fEvent" name="fEvent" class="form-control">
35
- <option value="">-- {{ strings.event }} --</option>
36
- {% for event_key,event_name in vars.events_for_select %}
37
- <option value="{{ event_key }}">{{ event_name }}</option>
38
- {% endfor %}
39
- </select>
40
- </div>
41
-
42
- {# <div class="col-auto"> #}
43
- {# <label for="_fLoggedIn">{{ strings.logged_in }}?</label> #}
44
- {# <select id="_fLoggedIn" name="fLoggedIn" class="form-control"> #}
45
- {# <option value="-1" selected>-- {{ strings.select }} --</option> #}
46
- {# <option value="1">{{ strings.yes }}</option> #}
47
- {# <option value="0">{{ strings.no }}</option> #}
48
- {# </select> #}
49
- {# </div> #}
50
-
51
- <div class="col-auto mb-3 input-daterange">
52
- <label class="form-label sr-only" for="_fDateFrom" title="{{ strings.show_after }}...">
53
- {{ strings.time_since }}:</label>
54
- <input type="text" class="form-control date-picker" id="_fDateFrom"
55
- name="fDateFrom" value=""
56
- placeholder="{{ strings.time_since }} {{ strings.yyyymmdd }}">
57
-
58
- </div>
59
-
60
- <div class="col-auto mb-3 input-daterange">
61
- <label class="form-label sr-only" for="_fDateTo" title="{{ strings.show_before }}...">
62
- {{ strings.time_until }}:</label>
63
- <input type="text" class="form-control date-picker" id="_fDateTo"
64
- name="fDateTo" value=""
65
- placeholder="{{ strings.time_until }} {{ strings.yyyymmdd }}">
66
- </div>
67
-
68
- <div class="col-auto mb-3 text-right">
69
- <label class="sr-only" for="SubmitForm" title="{{ strings.exclude_your_ip_tooltip }}">
70
- {{ strings.exclude_your_ip }}?</label>
71
- <input id="SubmitForm" href="#" class="btn btn-primary"
72
- type="submit" value="{{ strings.filters_apply }}" />
73
- <a id="ClearForm" href="#"
74
- class="btn btn-sm btn-link text-dark">{{ strings.filters_clear }}</a>
75
- </div>
76
- </div>
77
- </form>
78
-
79
- <div id="TableAuditTrail"></div>
80
 
81
  </div>
82
 
1
  <div class="row insights_widget" id="SectionAuditTable">
2
 
3
  <div class="col">
 
 
 
4
 
5
+ <form id="AuditFilterForm" autocomplete="off" class="px-3 pt-3">
6
+ <div class="form-row">
7
+
8
+ <div class="col-auto mb-3">
9
+ <label class="sr-only" for="_fUsername">{{ strings.username }}</label>
10
+ <select id="_fUsername" name="fUsername" class="form-control">
11
+ <option value="">-- {{ strings.username }} --</option>
12
+ {% for uniq_user in vars.unique_users %}
13
+ <option value="{{ uniq_user }}">{{ uniq_user }}</option>
14
+ {% endfor %}
15
+ </select>
16
+ </div>
17
+
18
+ <div class="col-auto mb-3">
19
+ <label class="sr-only" for="_fIp">{{ strings.ip_address }}</label>
20
+ <select id="_fIp" name="fIp" class="form-control select2picker">
21
+ <option value="">-- {{ strings.ip_address }} --</option>
22
+ {% for unique_ip in vars.unique_ips %}
23
+ <option value="{{ unique_ip }}">{{ unique_ip }}</option>
24
+ {% endfor %}
25
+ </select>
26
+ </div>
27
+
28
+ <div class="col-auto mb-3">
29
+ <label class="sr-only" for="_fEvent">{{ strings.event }}</label>
30
+ <select id="_fEvent" name="fEvent" class="form-control">
31
+ <option value="">-- {{ strings.event }} --</option>
32
+ {% for event_key,event_name in vars.events_for_select %}
33
+ <option value="{{ event_key }}">{{ event_name }}</option>
34
+ {% endfor %}
35
+ </select>
36
+ </div>
37
+
38
+ <div class="col-auto mb-3 input-daterange">
39
+ <label class="form-label sr-only" for="_fDateFrom" title="{{ strings.show_after }}...">
40
+ {{ strings.time_since }}:</label>
41
+ <input type="text" class="form-control date-picker" id="_fDateFrom"
42
+ name="fDateFrom" value=""
43
+ placeholder="{{ strings.time_since }} {{ strings.yyyymmdd }}">
44
+ </div>
45
+
46
+ <div class="col-auto mb-3 input-daterange">
47
+ <label class="form-label sr-only" for="_fDateTo" title="{{ strings.show_before }}...">
48
+ {{ strings.time_until }}:</label>
49
+ <input type="text" class="form-control date-picker" id="_fDateTo"
50
+ name="fDateTo" value=""
51
+ placeholder="{{ strings.time_until }} {{ strings.yyyymmdd }}">
52
+ </div>
53
+
54
+ <div class="col-auto mb-3 text-right">
55
+ <label class="sr-only" for="SubmitForm" title="{{ strings.exclude_your_ip_tooltip }}">
56
+ {{ strings.exclude_your_ip }}?</label>
57
+ <input id="SubmitForm" href="#" class="btn btn-primary"
58
+ type="submit" value="{{ strings.filters_apply }}" />
59
+ <a id="ClearForm" href="#"
60
+ class="btn btn-sm btn-link text-dark">{{ strings.filters_clear }}</a>
61
+ </div>
62
+ </div>
63
+ </form>
64
+
65
+ <div id="TableAuditTrail"></div>
 
 
 
 
 
 
 
 
 
 
 
66
 
67
  </div>
68
 
templates/twig/wpadmin_pages/insights/base.twig CHANGED
@@ -6,32 +6,15 @@
6
  <div class="row">
7
 
8
  <div class="col">
9
- <h5 class="mt-3">
10
  {% block page_head_titlemenu %}
11
- {% if flags.is_dashboard %}
12
- {{ strings.dashboard_shield }}
13
- {% else %}
14
- {{ strings.page_title }}
15
- <br />
16
- <p class="mb-1 mt-2 d-inline-block" style="font-size: small">
17
- <a href="{{ hrefs.back_to_dash }}">&laquo; {{ strings.dashboard }}</a>
18
- {% if vars.related_hrefs|default([]) is not empty %}
19
- {% for related_href in vars.related_hrefs %}
20
- | <a href="{{ related_href.href }}"
21
- {% if not related_href.id|default('') is empty %}id="{{ related_href.id }}"{% endif %}
22
- class="{{ related_href.classes|default([])|join(' ') }}"
23
- {% if related_href.new|default(false) %}target="_blank"{% endif %}>
24
- {{ related_href.title }}</a>
25
- {% endfor %}
26
- {% endif %}
27
- </p>
28
- {% endif %}
29
  {% endblock page_head_titlemenu %}
30
  </h5>
31
  </div>
32
 
33
  <div class="col">
34
- <a class="navbar-brand float-right mt-3"
35
  href="{{ hrefs.nav_home }}"
36
  id="navbar-bannerlogo"
37
  style="background-image: url('{{ hrefs.img_banner }}');"
@@ -44,17 +27,10 @@
44
  {% endblock %}
45
 
46
  {% block page_main %}
47
- <div class="row">
48
- <div class="col">
49
- </div>
50
- </div>
51
  {% endblock %}
52
 
53
  {% block page_foot %}
54
  {% endblock %}
55
 
56
  {% block inline_styles %}
57
- {% endblock %}
58
-
59
- {% block inline_scripts %}
60
  {% endblock %}
6
  <div class="row">
7
 
8
  <div class="col">
9
+ <h5 class="mt-3" id="PageTitle">
10
  {% block page_head_titlemenu %}
11
+ {{ strings.page_title }}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  {% endblock page_head_titlemenu %}
13
  </h5>
14
  </div>
15
 
16
  <div class="col">
17
+ <a class="navbar-brand float-right my-2"
18
  href="{{ hrefs.nav_home }}"
19
  id="navbar-bannerlogo"
20
  style="background-image: url('{{ hrefs.img_banner }}');"
27
  {% endblock %}
28
 
29
  {% block page_main %}
 
 
 
 
30
  {% endblock %}
31
 
32
  {% block page_foot %}
33
  {% endblock %}
34
 
35
  {% block inline_styles %}
 
 
 
36
  {% endblock %}
templates/twig/wpadmin_pages/insights/dashboard/card_settings.twig CHANGED
@@ -8,7 +8,7 @@
8
  </li>
9
  <li class="list-group-item" id="SearchOptionsLaunch">
10
  <div class="text-nowrap">
11
- {% include '/snippets/select_search_options.twig' %}
12
  </div>
13
  </li>
14
  </ul>
8
  </li>
9
  <li class="list-group-item" id="SearchOptionsLaunch">
10
  <div class="text-nowrap">
11
+ {% include '/components/search/options.twig' %}
12
  </div>
13
  </li>
14
  </ul>
templates/twig/wpadmin_pages/insights/docs/index.twig CHANGED
@@ -50,6 +50,7 @@
50
  {% endblock %}
51
 
52
  {% block inline_scripts %}
 
53
 
54
  <script type="text/javascript">
55
  window.announcekit = (window.announcekit || {
50
  {% endblock %}
51
 
52
  {% block inline_scripts %}
53
+ {{ parent() }}
54
 
55
  <script type="text/javascript">
56
  window.announcekit = (window.announcekit || {
templates/twig/wpadmin_pages/insights/overview/cards/shuffle.twig CHANGED
@@ -102,6 +102,13 @@ document.addEventListener( 'DOMContentLoaded', function () {
102
  }
103
  } );
104
 
 
 
 
 
 
 
 
105
  jQuery( function () {
106
  jQuery( '[data-toggle="popover"]' ).popover( {
107
  placement: 'top',
102
  }
103
  } );
104
 
105
+ if ( document.querySelector( '.state-danger' ) !== null ) {
106
+ document.querySelector('.state-danger').dispatchEvent( new MouseEvent( "click", { bubbles: true, cancellable: true } ) );
107
+ }
108
+ if ( document.querySelector( '.state-warning' ) !== null ) {
109
+ document.querySelector('.state-warning').dispatchEvent( new MouseEvent( "click", { bubbles: true, cancellable: true } ) );
110
+ }
111
+
112
  jQuery( function () {
113
  jQuery( '[data-toggle="popover"]' ).popover( {
114
  placement: 'top',
templates/twig/wpadmin_pages/insights/scans/index.twig DELETED
@@ -1,10 +0,0 @@
1
- {% extends '/wpadmin_pages/insights/base.twig' %}
2
-
3
- {% block page_main %}
4
- <div class="row">
5
- <div class="col-12 insights_section">
6
- {% include '/wpadmin_pages/insights/scans/scan_start.twig' %}
7
- </div>
8
- </div>
9
- {% include '/wpadmin_pages/insights/scans/modal/progress.twig' %}
10
- {% endblock %}
 
 
 
 
 
 
 
 
 
 
templates/twig/wpadmin_pages/insights/scans/results/index.twig ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ {% extends '/wpadmin_pages/insights/base.twig' %}
2
+
3
+ {% block page_main %}
4
+ <div class="row" id="SectionInsightsScans">
5
+ <div class="col-12 insights-sub-nav" id="ScanResultsTabs">
6
+ {% include '/wpadmin_pages/insights/scans/results/scan_results.twig' %}
7
+ </div>
8
+ </div>
9
+ {% include '/wpadmin_pages/insights/scans/modal/progress.twig' %}
10
+ {% endblock %}
templates/twig/wpadmin_pages/insights/scans/{realtime → results/realtime}/file_locker/file_diff.twig RENAMED
@@ -6,6 +6,11 @@
6
  <div class="card-body">
7
  <h5 class="card-title">{{ strings.locked_file }}</h5>
8
 
 
 
 
 
 
9
  <dl class="row">
10
  <dt class="col">{{ strings.locked }}</dt>
11
  <dd class="col">{{ vars.locked_at }}</dd>
@@ -17,8 +22,8 @@
17
  </dl>
18
 
19
  <dl class="row">
20
- <dt class="col">{{ strings.modified_timestamp }}</dt>
21
- <dd class="col">{{ vars.file_modified_at }}</dd>
22
  </dl>
23
 
24
  <dl class="row">
6
  <div class="card-body">
7
  <h5 class="card-title">{{ strings.locked_file }}</h5>
8
 
9
+ <dl class="row">
10
+ <dt class="col">{{ strings.relative_path }}</dt>
11
+ <dd class="col">{{ vars.relative_path }}</dd>
12
+ </dl>
13
+
14
  <dl class="row">
15
  <dt class="col">{{ strings.locked }}</dt>
16
  <dd class="col">{{ vars.locked_at }}</dd>
22
  </dl>
23
 
24
  <dl class="row">
25
+ <dt class="col">{{ strings.file_modified }}</dt>
26
+ <dd class="col">{{ vars.file_modified_ago }}<br/>({{ vars.file_modified_at }})</dd>
27
  </dl>
28
 
29
  <dl class="row">
templates/twig/wpadmin_pages/insights/scans/{realtime → results/realtime}/file_locker/index.twig RENAMED
@@ -10,7 +10,7 @@
10
  <div class="card-body">
11
 
12
  {% if scan.flags.is_restricted %}
13
- {% include '/wpadmin_pages/insights/scans/results/common_unavailable.twig' %}
14
  {% else %}
15
  {% if scan.flags.is_enabled %}
16
  <div class="col mt-3 mb-3">
@@ -21,12 +21,13 @@
21
  </label>
22
  </div>
23
  <select class="custom-select mw-100" id="FileLockerFileSelect">
24
- <option selected value="-">--</option>
25
  {% for lock_key, file_lock in scan.vars.file_locks.bad %}
26
  <option value="{{ lock_key }}" class="text-danger">{{ file_lock.file }}</option>
27
  {% endfor %}
28
  {% for lock_key, file_lock in scan.vars.file_locks.good %}
29
- <option value="{{ lock_key }}" class="text-success">{{ file_lock.file }}</option>
 
30
  {% endfor %}
31
  </select>
32
  </div>
@@ -40,7 +41,7 @@
40
  </div>
41
  </div>
42
  {% else %}
43
- {% include '/wpadmin_pages/insights/scans/results/common_disabled.twig' %}
44
  {% endif %}
45
  {% endif %}
46
  </div>
@@ -61,7 +62,7 @@
61
  </div>
62
 
63
  {% if not scan.flags.is_restricted %}
64
- <script type="text/javascript">
65
  jQuery( '#FileLockerFileSelect' ).on( 'change', function ( e ) {
66
  iCWP_WPSF_BodyOverlay.show();
67
  let ajax_vars ={{ scan.ajax.filelocker_showdiff|raw }};
10
  <div class="card-body">
11
 
12
  {% if scan.flags.is_restricted %}
13
+ {% include '/wpadmin_pages/insights/scans/results/results/common_unavailable.twig' %}
14
  {% else %}
15
  {% if scan.flags.is_enabled %}
16
  <div class="col mt-3 mb-3">
21
  </label>
22
  </div>
23
  <select class="custom-select mw-100" id="FileLockerFileSelect">
24
+ <option selected value="-" disabled="disabled">--</option>
25
  {% for lock_key, file_lock in scan.vars.file_locks.bad %}
26
  <option value="{{ lock_key }}" class="text-danger">{{ file_lock.file }}</option>
27
  {% endfor %}
28
  {% for lock_key, file_lock in scan.vars.file_locks.good %}
29
+ <option value="{{ lock_key }}"
30
+ class="text-success">{{ file_lock.file }}</option>
31
  {% endfor %}
32
  </select>
33
  </div>
41
  </div>
42
  </div>
43
  {% else %}
44
+ {% include '/wpadmin_pages/insights/scans/results/results/common_disabled.twig' %}
45
  {% endif %}
46
  {% endif %}
47
  </div>
62
  </div>
63
 
64
  {% if not scan.flags.is_restricted %}
65
+ <script type="text/javascript">
66
  jQuery( '#FileLockerFileSelect' ).on( 'change', function ( e ) {
67
  iCWP_WPSF_BodyOverlay.show();
68
  let ajax_vars ={{ scan.ajax.filelocker_showdiff|raw }};
templates/twig/wpadmin_pages/insights/scans/results/{aggregate.twig → results/aggregate.twig} RENAMED
File without changes
templates/twig/wpadmin_pages/insights/scans/results/{apc.twig → results/apc.twig} RENAMED
@@ -20,11 +20,11 @@
20
  {% endif %}
21
 
22
  {% else %}
23
- {% include '/wpadmin_pages/insights/scans/results/common_disabled.twig' %}
24
  {% endif %}
25
 
26
  {% else %}
27
- {% include '/wpadmin_pages/insights/scans/results/common_unavailable.twig' %}
28
  {% endif %}
29
 
30
  </div>
20
  {% endif %}
21
 
22
  {% else %}
23
+ {% include '/wpadmin_pages/insights/scans/results/results/common_disabled.twig' %}
24
  {% endif %}
25
 
26
  {% else %}
27
+ {% include '/wpadmin_pages/insights/scans/results/results/common_unavailable.twig' %}
28
  {% endif %}
29
 
30
  </div>
templates/twig/wpadmin_pages/insights/scans/results/{common_disabled.twig → results/common_disabled.twig} RENAMED
File without changes
templates/twig/wpadmin_pages/insights/scans/results/{common_unavailable.twig → results/common_unavailable.twig} RENAMED
File without changes
templates/twig/wpadmin_pages/insights/scans/results/{mal.twig → results/mal.twig} RENAMED
@@ -10,7 +10,7 @@
10
  <div class="card-body">
11
 
12
  {% if scan.flags.is_restricted %}
13
- {% include '/wpadmin_pages/insights/scans/results/common_unavailable.twig' %}
14
  {% else %}
15
  {% if scan.flags.is_available %}
16
 
@@ -21,7 +21,7 @@
21
  {% endif %}
22
 
23
  {% else %}
24
- {% include '/wpadmin_pages/insights/scans/results/common_disabled.twig' %}
25
  {% endif %}
26
  {% endif %}
27
 
10
  <div class="card-body">
11
 
12
  {% if scan.flags.is_restricted %}
13
+ {% include '/wpadmin_pages/insights/scans/results/results/common_unavailable.twig' %}
14
  {% else %}
15
  {% if scan.flags.is_available %}
16
 
21
  {% endif %}
22
 
23
  {% else %}
24
+ {% include '/wpadmin_pages/insights/scans/results/results/common_disabled.twig' %}
25
  {% endif %}
26
  {% endif %}
27
 
templates/twig/wpadmin_pages/insights/scans/results/{ptg.twig → results/ptg.twig} RENAMED
@@ -9,17 +9,17 @@
9
 
10
  <div class="card-body">
11
  {% if scan.flags.is_restricted %}
12
- {% include '/wpadmin_pages/insights/scans/results/common_unavailable.twig' %}
13
  {% else %}
14
  {% if scan.flags.is_available %}
15
  {% if not scan.flags.has_items %}
16
  <div class="alert alert-success m-0">{{ strings.no_entries_to_display }}</div>
17
  {% else %}
18
- {% include '/wpadmin_pages/insights/scans/results/'~scankey~'_table.twig' %}
19
  {% endif %}
20
 
21
  {% else %}
22
- {% include '/wpadmin_pages/insights/scans/results/common_disabled.twig' %}
23
  {% endif %}
24
  {% endif %}
25
  </div>
9
 
10
  <div class="card-body">
11
  {% if scan.flags.is_restricted %}
12
+ {% include '/wpadmin_pages/insights/scans/results/results/common_unavailable.twig' %}
13
  {% else %}
14
  {% if scan.flags.is_available %}
15
  {% if not scan.flags.has_items %}
16
  <div class="alert alert-success m-0">{{ strings.no_entries_to_display }}</div>
17
  {% else %}
18
+ {% include '/wpadmin_pages/insights/scans/results/results/'~scankey~'_table.twig' %}
19
  {% endif %}
20
 
21
  {% else %}
22
+ {% include '/wpadmin_pages/insights/scans/results/results/common_disabled.twig' %}
23
  {% endif %}
24
  {% endif %}
25
  </div>
templates/twig/wpadmin_pages/insights/scans/results/{ptg_table.twig → results/ptg_table.twig} RENAMED
File without changes
templates/twig/wpadmin_pages/insights/scans/results/{ufc.twig → results/ufc.twig} RENAMED
File without changes
templates/twig/wpadmin_pages/insights/scans/results/{wcf.twig → results/wcf.twig} RENAMED
@@ -3,8 +3,22 @@
3
  <div class="card card-scan_results">
4
 
5
  <div class="card-header">
6
- <h5 class="card-title">{{ scan.strings.title }}</h5>
7
- <h6 class="card-subtitle text-muted">{{ scan.strings.subtitle }}</h6>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  </div>
9
 
10
  <div class="card-body">
3
  <div class="card card-scan_results">
4
 
5
  <div class="card-header">
6
+ <h5 class="card-title">
7
+ {{ scan.strings.title }}
8
+ <a data-toggle="collapse"
9
+ data-target="#MoreInfo-{{ scan.vars.slug }}"
10
+ ><span class="dashicons dashicons-info"></span></a>
11
+ </h5>
12
+ <h6 class="card-subtitle text-muted">
13
+ {{ scan.strings.subtitle }}
14
+ </h6>
15
+ <div class="collapse mt-3" id="MoreInfo-{{ scan.vars.slug }}">
16
+ <div class="alert alert-dark">
17
+ {% for line in scan.strings.explanation %}
18
+ <p class="mb-2">{{ line }}</p>
19
+ {% endfor %}
20
+ </div>
21
+ </div>
22
  </div>
23
 
24
  <div class="card-body">
templates/twig/wpadmin_pages/insights/scans/results/{wpv.twig → results/wpv.twig} RENAMED
@@ -10,7 +10,7 @@
10
  <div class="card-body">
11
 
12
  {% if scan.flags.is_restricted %}
13
- {% include '/wpadmin_pages/insights/scans/results/common_unavailable.twig' %}
14
  {% else %}
15
  {% if scan.flags.is_available %}
16
 
@@ -21,7 +21,7 @@
21
  {% endif %}
22
 
23
  {% else %}
24
- {% include '/wpadmin_pages/insights/scans/results/common_disabled.twig' %}
25
  {% endif %}
26
  {% endif %}
27
 
10
  <div class="card-body">
11
 
12
  {% if scan.flags.is_restricted %}
13
+ {% include '/wpadmin_pages/insights/scans/results/results/common_unavailable.twig' %}
14
  {% else %}
15
  {% if scan.flags.is_available %}
16
 
21
  {% endif %}
22
 
23
  {% else %}
24
+ {% include '/wpadmin_pages/insights/scans/results/results/common_disabled.twig' %}
25
  {% endif %}
26
  {% endif %}
27
 
templates/twig/wpadmin_pages/insights/scans/{scan_results.twig → results/scan_results.twig} RENAMED
@@ -12,8 +12,13 @@
12
  {% for scankey,scanvars in scans %}
13
  {% if scanvars.flags.show_table %}
14
  <li class="nav-item">
15
- <a class="nav-link" id="h-tabs-home-tab" data-toggle="tab" href="#h-tabs-{{ scankey }}"
16
- role="tab" aria-controls="h-tabs-{{ scankey }}">
 
 
 
 
 
17
  <span class="badge badge-{% if scanvars.count > 0 %}danger{% endif %}"
18
  >{% if scanvars.count > 0 %}&#33;{% endif %}</span>
19
  {{ scanvars.strings.title }}
@@ -31,12 +36,13 @@
31
  </a>
32
  </li>
33
  </ul>
 
34
  <div class="tab-content mb-5" id="ScanResultsTabsContent">
35
 
36
  {% set scan = aggregate %}
37
  <div class="tab-pane show active" id="h-tabs-aggregate" role="tabpanel"
38
  aria-labelledby="h-tabs-aggregate-tab">
39
- {% include '/wpadmin_pages/insights/scans/results/aggregate.twig' %}
40
  </div>
41
 
42
  {% for scankey,scanvars in scans %}
@@ -44,7 +50,7 @@
44
  <div class="tab-pane" id="h-tabs-{{ scankey }}" role="tabpanel"
45
  aria-labelledby="h-tabs-{{ scankey }}-tab">
46
  {% set scan = attribute(scans, scankey) %}
47
- {% include '/wpadmin_pages/insights/scans/results/'~scankey~'.twig' %}
48
  </div>
49
  {% endif %}
50
  {% endfor %}
@@ -52,6 +58,6 @@
52
  <div class="tab-pane show" id="h-tabs-file_locker" role="tabpanel"
53
  aria-labelledby="h-tabs-aggregate-tab">
54
  {% set scan = file_locker %}
55
- {% include '/wpadmin_pages/insights/scans/realtime/file_locker/index.twig' %}
56
  </div>
57
  </div>
12
  {% for scankey,scanvars in scans %}
13
  {% if scanvars.flags.show_table %}
14
  <li class="nav-item">
15
+ <a class="nav-link"
16
+ id="h-tabs-home-tab"
17
+ data-toggle="tab"
18
+ href="#h-tabs-{{ scankey }}"
19
+ role="tab"
20
+ aria-controls="h-tabs-{{ scankey }}"
21
+ >
22
  <span class="badge badge-{% if scanvars.count > 0 %}danger{% endif %}"
23
  >{% if scanvars.count > 0 %}&#33;{% endif %}</span>
24
  {{ scanvars.strings.title }}
36
  </a>
37
  </li>
38
  </ul>
39
+
40
  <div class="tab-content mb-5" id="ScanResultsTabsContent">
41
 
42
  {% set scan = aggregate %}
43
  <div class="tab-pane show active" id="h-tabs-aggregate" role="tabpanel"
44
  aria-labelledby="h-tabs-aggregate-tab">
45
+ {% include '/wpadmin_pages/insights/scans/results/results/aggregate.twig' %}
46
  </div>
47
 
48
  {% for scankey,scanvars in scans %}
50
  <div class="tab-pane" id="h-tabs-{{ scankey }}" role="tabpanel"
51
  aria-labelledby="h-tabs-{{ scankey }}-tab">
52
  {% set scan = attribute(scans, scankey) %}
53
+ {% include '/wpadmin_pages/insights/scans/results/results/'~scankey~'.twig' %}
54
  </div>
55
  {% endif %}
56
  {% endfor %}
58
  <div class="tab-pane show" id="h-tabs-file_locker" role="tabpanel"
59
  aria-labelledby="h-tabs-aggregate-tab">
60
  {% set scan = file_locker %}
61
+ {% include '/wpadmin_pages/insights/scans/results/realtime/file_locker/index.twig' %}
62
  </div>
63
  </div>
templates/twig/wpadmin_pages/insights/scans/run/index.twig ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends '/wpadmin_pages/insights/base.twig' %}
2
+
3
+ {% block page_main %}
4
+
5
+ <div class="row" id="SectionInsightsScans">
6
+ <div class="col-12">
7
+ {% include '/wpadmin_pages/insights/scans/run/scan_areas.twig' %}
8
+ </div>
9
+ </div>
10
+ {% include '/wpadmin_pages/insights/scans/modal/progress.twig' %}
11
+ {% endblock %}
templates/twig/wpadmin_pages/insights/scans/{scan_areas.twig → run/scan_areas.twig} RENAMED
@@ -163,16 +163,18 @@
163
  <script>
164
  jQuery( 'form#StartScans' ).icwpWpsfScansStart(
165
  {
166
- 'ajax_scans_start':{{ ajax.scans_start|raw }},
167
- 'ajax_scans_check':{{ ajax.scans_check|raw }}
 
168
  }
169
  );
170
  {% if vars.initial_check %}
171
- jQuery( document ).icwpWpsfScansCheck(
172
- {
173
- 'ajax_scans_check':{{ ajax.scans_check|raw }}
174
- }
175
- );
 
176
  {% endif %}
177
 
178
  </script>
163
  <script>
164
  jQuery( 'form#StartScans' ).icwpWpsfScansStart(
165
  {
166
+ 'ajax_scans_start': {{ ajax.scans_start|raw }},
167
+ 'ajax_scans_check': {{ ajax.scans_check|raw }},
168
+ 'href_scans_results': "{{ hrefs.scans_results|raw }}"
169
  }
170
  );
171
  {% if vars.initial_check %}
172
+ jQuery( document ).icwpWpsfScansCheck(
173
+ {
174
+ 'ajax_scans_check': {{ ajax.scans_check|raw }},
175
+ 'href_scans_results': "{{ hrefs.scans_results|raw }}"
176
+ }
177
+ );
178
  {% endif %}
179
 
180
  </script>
templates/twig/wpadmin_pages/insights/scans/scan_start.twig DELETED
@@ -1,46 +0,0 @@
1
- <div class="tab-content" id="ScanResultsTabsContent">
2
-
3
- <div class="tab-pane show active fade" id="ScanPagePaneResults" role="tabpanel"
4
- aria-labelledby="h-tabs-scanpage-tab">
5
- <div class="row" id="SectionInsightsScans">
6
- <div class="col-12 insights-sub-nav" id="ScanResultsTabs">
7
- {% include '/wpadmin_pages/insights/scans/scan_results.twig' %}
8
- </div>
9
- </div>
10
- </div>
11
-
12
- <div class="tab-pane fade" id="ScanPagePaneScanNow" role="tabpanel"
13
- aria-labelledby="h-tabs-scanpage-tab">
14
- <div class="row" id="SectionInsightsScans">
15
- <div class="col-12">
16
- {% include '/wpadmin_pages/insights/scans/scan_areas.twig' %}
17
- </div>
18
- </div>
19
- </div>
20
- </div>
21
- <ul class="nav nav-tabs d-block" id="ScanPageTabsNav" role="tablist" style="border-bottom: 0 none;">
22
-
23
- <li id="ScanPageTabsNavResults" class="nav-item hidden footer-form-actions">
24
- <a class="nav-link active btn btn-primary btn-lg" data-toggle="tab" href="#ScanPagePaneResults"
25
- role="tab" aria-controls="h-tabs-scanpage" aria-selected="true">
26
- &larr; {{ strings.select_view_results }}
27
- </a>
28
- </li>
29
- <li id="ScanPageTabsNavScan" class="nav-item footer-form-actions">
30
- <a class="nav-link btn btn-primary btn-lg" data-toggle="tab" href="#ScanPagePaneScanNow"
31
- role="tab" aria-controls="h-tabs-scanpage" aria-selected="true">
32
- {{ strings.run_scans_now }} &rarr;
33
- </a>
34
- </li>
35
- </ul>
36
-
37
- <script type="text/javascript">
38
- jQuery( '#ScanPageTabsNavResults a[data-toggle="tab"]' ).on( 'shown.bs.tab', function ( e ) {
39
- jQuery( '#ScanPageTabsNavScan' ).removeClass( 'hidden' );
40
- jQuery( '#ScanPageTabsNavResults' ).addClass( 'hidden' );
41
- } );
42
- jQuery( '#ScanPageTabsNavScan a[data-toggle="tab"]' ).on( 'shown.bs.tab', function ( e ) {
43
- jQuery( '#ScanPageTabsNavResults' ).removeClass( 'hidden' );
44
- jQuery( '#ScanPageTabsNavScan' ).addClass( 'hidden' );
45
- } );
46
- </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
templates/twig/wpadmin_pages/insights/settings/index.twig CHANGED
@@ -2,46 +2,10 @@
2
 
3
  {% block page_head_titlemenu %}
4
  {{ parent() }}
5
- <p class="d-inline">|</p>
6
- <div class="d-inline-block" id="ModuleSettingsJump">
7
- {% include '/snippets/select_module_settings.twig' %}
8
- </div>
9
  {% endblock page_head_titlemenu %}
10
 
11
  {% block page_main %}
12
  <div class="row" id="ModulePageTopRow">
13
- {# <div class="modules smoothwidth" id="ColumnModules">#}
14
- {# <div class="nav flex-column">#}
15
- {# <div>#}
16
- {# <a id="ModeToggle" href="#" class="btn btn-block btn-outline-primary text-nowrap"#}
17
- {# data-txthoverin="{{ strings.mode_switchto }}" data-txthoverout="{{ strings.mode_switchfrom }}"#}
18
- {# >#}
19
- {# {{ strings.mode }}: <span class="font-weight-bold">#}
20
- {# {{ attribute(strings,flags.is_advanced ? 'mode_advanced':'mode_simple') }}#}
21
- {# </span>#}
22
- {# </a>#}
23
- {# </div>#}
24
-
25
- {# <h5 class="mt-3 border-bottom"#}
26
- {# style="font-variant: small-caps;font-weight: normal">Shield Modules</h5>#}
27
- {# {% for mod_summary in aSummaryData %}#}
28
- {# <a class="nav-link module#}
29
- {# {% if mod_summary.active %}active{% endif %}#}
30
- {# {% if mod_summary.enabled %}enabled{% else %}notenabled{% endif %}"#}
31
- {# id="tab-{{ mod_summary.slug }}"#}
32
- {# href="{{ mod_summary.href }}" role="tab">#}
33
- {# <div>#}
34
- {# <span class="module-icon module-icon-{{ mod_summary.slug }}"#}
35
- {# id="module-{{ mod_summary.slug }}"></span>#}
36
- {# <span class="module-name">#}
37
- {# {{ mod_summary.tooltip }}#}
38
- {# </span>#}
39
- {# </div>#}
40
- {# </a>#}
41
- {# {% endfor %}#}
42
- {# </div>#}
43
- {# </div>#}
44
-
45
  <div class="col" id="ColumnOptions">
46
  <div class="content-options"> {{ strings.loading }} ... </div>
47
  </div>
@@ -49,28 +13,5 @@
49
  <script>
50
  iCWP_WPSF_OptsPageRender.renderForm( {{ ajax.mod_opts_form_render|raw }} );
51
  iCWP_WPSF_OptionsFormSubmit.updateAjaxReqParams( {{ ajax.mod_options|raw }} );
52
- jQuery( 'a.nav-link.module' ).tooltip( {
53
- placement: 'right',
54
- trigger: 'hover'
55
- } );
56
- jQuery( 'a.section-help-video' ).tooltip( {
57
- placement: 'right',
58
- trigger: 'hover'
59
- } );
60
-
61
- jQuery( 'a#ModeToggle' ).hover(
62
- function ( evt ) {
63
- let $this = jQuery( this );
64
- $this.text( $this.data( 'txthoverin' ) );
65
- $this.addClass( 'btn-warning' )
66
- .removeClass( 'btn-outline-primary' );
67
- },
68
- function ( evt ) {
69
- let $this = jQuery( this );
70
- $this.text( $this.data( 'txthoverout' ) );
71
- $this.addClass( 'btn-outline-primary' )
72
- .removeClass( 'btn-warning' );
73
- }
74
- );
75
  </script>
76
  {% endblock %}
2
 
3
  {% block page_head_titlemenu %}
4
  {{ parent() }}
 
 
 
 
5
  {% endblock page_head_titlemenu %}
6
 
7
  {% block page_main %}
8
  <div class="row" id="ModulePageTopRow">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  <div class="col" id="ColumnOptions">
10
  <div class="content-options"> {{ strings.loading }} ... </div>
11
  </div>
13
  <script>
14
  iCWP_WPSF_OptsPageRender.renderForm( {{ ajax.mod_opts_form_render|raw }} );
15
  iCWP_WPSF_OptionsFormSubmit.updateAjaxReqParams( {{ ajax.mod_options|raw }} );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  </script>
17
  {% endblock %}
templates/twig/wpadmin_pages/insights/stats/index.twig ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends '/wpadmin_pages/insights/base.twig' %}
2
+
3
+ {% block page_main %}
4
+
5
+ {% if flags.has_stats %}
6
+
7
+ <div id="StatsNav">
8
+ <ul class="nav nav-pills">
9
+ {% for stat_interval_key, stat_interval_name in vars.stat_intervals %}
10
+ <li class="nav-item">
11
+ <a class="nav-link {% if stat_interval_key == 'days_1' %}active{% endif %}"
12
+ data-toggle="pill"
13
+ href="#statsTab-{{ stat_interval_key }}">
14
+ {{ stat_interval_name }}</a>
15
+ </li>
16
+ {% endfor %}
17
+ </ul>
18
+ </div>
19
+
20
+ <div class="tab-content mt-3" id="statsTabs">
21
+ {% for stat_interval_key, stat_interval_name in vars.stat_intervals %}
22
+ <div class="tab-pane {% if stat_interval_key == 'days_1' %}active{% endif %}" id="statsTab-{{ stat_interval_key }}" role="tabpanel" aria-labelledby="home-tab">
23
+ {% set stat_to_show = stat_interval_key %}
24
+ {% include '/components/events/stats/stats_collection.twig' %}
25
+ </div>
26
+ {% endfor %}
27
+ </div>
28
+
29
+ {% else %}
30
+ <div class="alert alert-info">{{ strings.no_stats }}</div>
31
+ {% endif %}
32
+
33
+ {% endblock %}
templates/twig/wpadmin_pages/insights/traffic/traffic_table.twig CHANGED
@@ -13,7 +13,7 @@
13
 
14
  <div class="col-auto mb-3">
15
  <label class="sr-only" for="_fIp">{{ strings.ip_address }}</label>
16
- <select id="_fIp" name="fIp" class="form-control">
17
  <option value="">-- {{ strings.ip_address }} --</option>
18
  {% for unique_ip in vars.unique_ips %}
19
  <option value="{{ unique_ip }}">{{ unique_ip }}</option>
13
 
14
  <div class="col-auto mb-3">
15
  <label class="sr-only" for="_fIp">{{ strings.ip_address }}</label>
16
+ <select id="_fIp" name="fIp" class="form-control select2picker">
17
  <option value="">-- {{ strings.ip_address }} --</option>
18
  {% for unique_ip in vars.unique_ips %}
19
  <option value="{{ unique_ip }}">{{ unique_ip }}</option>
templates/twig/wpadmin_pages/security_admin/index.twig CHANGED
@@ -2,7 +2,7 @@
2
 
3
  {% block h1heading %}<h1 style="display: none;">&nbsp;</h1>{% endblock %}
4
  {% block page_head %}{% endblock %}
5
- {% block page_main %}
6
  <div class="row justify-content-center">
7
  <div class="col-xl-6 col-lg-7 col-md-8 col-sm-12">
8
  <div class="options-body" id="IcwpWpsfSecurityAdmin">
@@ -86,8 +86,4 @@
86
  background-color: transparent;
87
  }
88
  </style>
89
- {% endblock %}
90
-
91
- {% block inline_scripts %}
92
- {% include '/snippets/js/freshdesk_chatbot.twig' %}
93
  {% endblock %}
2
 
3
  {% block h1heading %}<h1 style="display: none;">&nbsp;</h1>{% endblock %}
4
  {% block page_head %}{% endblock %}
5
+ {% block body %}
6
  <div class="row justify-content-center">
7
  <div class="col-xl-6 col-lg-7 col-md-8 col-sm-12">
8
  <div class="options-body" id="IcwpWpsfSecurityAdmin">
86
  background-color: transparent;
87
  }
88
  </style>
 
 
 
 
89
  {% endblock %}
unsupported.php CHANGED
@@ -5,10 +5,10 @@ add_action( 'network_admin_notices', 'icwp_wpsf_unsupported_php' );
5
 
6
  function icwp_wpsf_unsupported_php() {
7
  global $sIcwpWpsfPluginFile;
8
- $aText = array(
9
- 'Sorry, your website runs an incredibly old version of PHP that Shield Security no longer supports, as of Shield v7.0',
10
  "Your PHP no longer gets upgrades and it's difficult to maintain code for.",
11
- 'We recommend that you contact your website hosting provider on how to upgrade to at least PHP v5.4'
12
  );
13
  echo sprintf(
14
  '<div class="error"><h4>%s</h4><p>%s</p>' .
@@ -16,7 +16,7 @@ function icwp_wpsf_unsupported_php() {
16
  '/ <a href="%s">%s</a></p></div>',
17
 
18
  sprintf( 'Shield Security Plugin - Unsupported PHP Version: %s', PHP_VERSION ),
19
- implode( '<br/>', $aText ),
20
  'https://shsec.io/dl',
21
  sprintf( 'Click here for more info' ),
22
  add_query_arg(
5
 
6
  function icwp_wpsf_unsupported_php() {
7
  global $sIcwpWpsfPluginFile;
8
+ $text = array(
9
+ 'Sorry, your website runs an incredibly old version of PHP that Shield Security no longer supports, as of Shield v9.0',
10
  "Your PHP no longer gets upgrades and it's difficult to maintain code for.",
11
+ 'We recommend that you contact your website hosting provider on how to upgrade to at least PHP 7.0'
12
  );
13
  echo sprintf(
14
  '<div class="error"><h4>%s</h4><p>%s</p>' .
16
  '/ <a href="%s">%s</a></p></div>',
17
 
18
  sprintf( 'Shield Security Plugin - Unsupported PHP Version: %s', PHP_VERSION ),
19
+ implode( '<br/>', $text ),
20
  'https://shsec.io/dl',
21
  sprintf( 'Click here for more info' ),
22
  add_query_arg(