Shield Security for WordPress - Version 11.2.0

Version Description

Download this release

Release Info

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

Code changes from version 11.1.1 to 11.2.0

Files changed (315) hide show
  1. cl.json +59 -5
  2. icwp-wpsf.php +1 -1
  3. plugin-spec.php +91 -63
  4. readme.txt +2 -2
  5. resources/css/featherlight.css +0 -141
  6. resources/css/global-plugin.css +5 -3
  7. resources/css/jquery.fancybox.min.css +0 -1
  8. resources/css/jquery.steps.css +0 -383
  9. resources/css/jquery/fancybox.min.css +1 -0
  10. resources/css/plugin.css +58 -2
  11. resources/css/shield/dialog.css +7 -0
  12. resources/css/{pages.css → shield/pages.css} +0 -0
  13. resources/css/shield/wizard.css +542 -0
  14. resources/css/wizard.css +0 -163
  15. resources/images/bootstrap/envelope-fill.svg +3 -0
  16. resources/images/bootstrap/facebook.svg +3 -0
  17. resources/images/bootstrap/file-earmark-play.svg +4 -0
  18. resources/images/bootstrap/play-btn-fill.svg +3 -0
  19. resources/images/bootstrap/play-btn.svg +4 -0
  20. resources/images/bootstrap/play-circle.svg +4 -0
  21. resources/images/bootstrap/play-fill.svg +3 -0
  22. resources/images/bootstrap/shield-fill-check.svg +3 -0
  23. resources/images/bootstrap/shield-fill-exclamation.svg +3 -0
  24. resources/images/bootstrap/shield-fill-plus.svg +3 -0
  25. resources/images/bootstrap/twitter.svg +3 -0
  26. resources/js/featherlight.js +0 -641
  27. resources/js/global-plugin.js +1 -45
  28. resources/js/jquery.fancybox.min.js +0 -12
  29. resources/js/jquery.steps.min.js +0 -6
  30. resources/js/jquery/fancybox.min.js +13 -0
  31. resources/js/{jquery.fileDownload.js → jquery/fileDownload.js} +0 -0
  32. resources/js/{u2f-frontend.js → login/u2f.js} +0 -0
  33. resources/js/plugin.js +1 -1
  34. resources/js/shield/antibot.js +15 -1
  35. resources/js/shield/dialog.js +10 -0
  36. resources/js/shield/navigation.js +1 -1
  37. resources/js/shield/tours.js +20 -3
  38. resources/js/shield/u2f-admin.js +0 -64
  39. resources/js/shield/userprofile.js +182 -17
  40. resources/js/shield/wizard.js +0 -0
  41. src/config/feature-autoupdates.php +2 -2
  42. src/config/feature-comments_filter.php +1 -1
  43. src/config/feature-integrations.php +81 -14
  44. src/config/feature-ips.php +4 -3
  45. src/config/feature-login_protect.php +12 -12
  46. src/config/feature-plugin.php +32 -21
  47. src/lib/src/Controller/Admin/MainAdminMenu.php +1 -17
  48. src/lib/src/Controller/Ajax/Response.php +1 -1
  49. src/lib/src/Controller/Assets/Enqueue.php +33 -2
  50. src/lib/src/Controller/Assets/Svgs.php +19 -0
  51. src/lib/src/Controller/Controller.php +18 -4
  52. src/lib/src/Databases/AuditTrail/Handler.php +0 -8
  53. src/lib/src/Databases/Base/BaseQuery.php +89 -61
  54. src/lib/src/Databases/Base/Delete.php +41 -5
  55. src/lib/src/Databases/Base/EntryVO.php +1 -1
  56. src/lib/src/Databases/Base/Handler.php +2 -18
  57. src/lib/src/Databases/Base/Update.php +2 -5
  58. src/lib/src/Databases/BotSignals/EntryVO.php +1 -0
  59. src/lib/src/Databases/Events/Handler.php +0 -8
  60. src/lib/src/Databases/Events/Select.php +6 -7
  61. src/lib/src/Databases/FileLocker/Handler.php +0 -7
  62. src/lib/src/Databases/IPs/Handler.php +0 -8
  63. src/lib/src/Databases/ScanQueue/Common.php +3 -3
  64. src/lib/src/Databases/Scanner/Update.php +13 -17
  65. src/lib/src/Databases/Session/Handler.php +6 -8
  66. src/lib/src/Databases/Traffic/Handler.php +0 -8
  67. src/lib/src/License/EddLicenseVO.php +1 -1
  68. src/lib/src/Modules/AuditTrail/Insights/OverviewCards.php +7 -13
  69. src/lib/src/Modules/AuditTrail/Lib/AuditWriter.php +1 -1
  70. src/lib/src/Modules/Autoupdates/Insights/OverviewCards.php +23 -27
  71. src/lib/src/Modules/Base/AdminPage.php +120 -0
  72. src/lib/src/Modules/Base/Common/ExecOnceModConsumer.php +12 -0
  73. src/lib/src/Modules/Base/Insights/OverviewCards.php +41 -6
  74. src/lib/src/Modules/Base/Lib/Rest/Request/Process.php +144 -0
  75. src/lib/src/Modules/Base/Lib/Rest/Request/RequestVO.php +18 -0
  76. src/lib/src/Modules/Base/Lib/Rest/RequestVoConsumer.php +29 -0
  77. src/lib/src/Modules/Base/Lib/Rest/Route/RestRouteConsumer.php +27 -0
  78. src/lib/src/Modules/Base/Lib/Rest/Route/RouteBase.php +256 -0
  79. src/lib/src/Modules/Base/Lib/Rest/Route/RouteCache.php +47 -0
  80. src/lib/src/Modules/Base/Lib/Rest/Utility/PreChecks.php +33 -0
  81. src/lib/src/Modules/Base/Lib/Rest/Utility/RestLocker.php +65 -0
  82. src/lib/src/Modules/Base/ModCon.php +68 -29
  83. src/lib/src/Modules/Base/Options.php +7 -3
  84. src/lib/src/Modules/Base/RestHandler.php +66 -0
  85. src/lib/src/Modules/Base/Strings.php +2 -2
  86. src/lib/src/Modules/Base/UI.php +1 -1
  87. src/lib/src/Modules/Base/Upgrade.php +3 -7
  88. src/lib/src/Modules/Base/WpCli.php +12 -11
  89. src/lib/src/Modules/BaseShield/AdminPage.php +18 -0
  90. src/lib/src/Modules/BaseShield/ModCon.php +12 -28
  91. src/lib/src/Modules/BaseShield/UI.php +13 -5
  92. src/lib/src/Modules/CommentsFilter/Forms/Gasp.php +2 -6
  93. src/lib/src/Modules/CommentsFilter/Forms/GoogleRecaptcha.php +2 -6
  94. src/lib/src/Modules/CommentsFilter/Insights/OverviewCards.php +11 -13
  95. src/lib/src/Modules/CommentsFilter/ModCon.php +2 -2
  96. src/lib/src/Modules/CommentsFilter/Scan/CommentAdditiveCleaner.php +2 -6
  97. src/lib/src/Modules/CommentsFilter/Scan/Scanner.php +2 -6
  98. src/lib/src/Modules/CommentsFilter/Strings.php +10 -4
  99. src/lib/src/Modules/Email/Processor.php +2 -3
  100. src/lib/src/Modules/Events/Lib/EventsListener.php +2 -3
  101. src/lib/src/Modules/Events/Lib/StatsWriter.php +1 -1
  102. src/lib/src/Modules/Firewall/Insights/OverviewCards.php +29 -26
  103. src/lib/src/Modules/Firewall/Lib/Scan/PerformScan.php +2 -4
  104. src/lib/src/Modules/HackGuard/AjaxHandler.php +1 -1
  105. src/lib/src/Modules/HackGuard/Insights/OverviewCards.php +14 -16
  106. src/lib/src/Modules/HackGuard/Lib/Reports/ScanAlerts.php +3 -3
  107. src/lib/src/Modules/HackGuard/Scan/Controller/Base.php +13 -7
  108. src/lib/src/Modules/HackGuard/Scan/Controller/Ptg.php +2 -2
  109. src/lib/src/Modules/HackGuard/Scan/Queue/CompleteQueue.php +1 -2
  110. src/lib/src/Modules/HackGuard/Scan/ScansController.php +3 -6
  111. src/lib/src/Modules/HackGuard/UI.php +13 -9
  112. src/lib/src/Modules/Headers/Insights/OverviewCards.php +11 -13
  113. src/lib/src/Modules/IPs/AjaxHandler.php +4 -0
  114. src/lib/src/Modules/IPs/Components/IpAddressConsumer.php +11 -4
  115. src/lib/src/Modules/IPs/Lib/AutoUnblock.php +10 -26
  116. src/lib/src/Modules/IPs/Lib/BlockRequest.php +2 -6
  117. src/lib/src/Modules/IPs/Lib/Bots/BotEventListener.php +3 -7
  118. src/lib/src/Modules/IPs/Lib/Bots/BotSignalsController.php +2 -6
  119. src/lib/src/Modules/IPs/Lib/Bots/BotSignalsRecord.php +14 -0
  120. src/lib/src/Modules/IPs/Lib/Bots/Calculator/BuildScores.php +21 -14
  121. src/lib/src/Modules/IPs/Lib/Bots/NotBot/InsertNotBotJs.php +19 -6
  122. src/lib/src/Modules/IPs/Lib/Bots/NotBot/NotBotHandler.php +32 -15
  123. src/lib/src/Modules/IPs/Lib/IpAnalyse/BuildDisplay.php +2 -2
  124. src/lib/src/Modules/IPs/Lib/OffenseTracker.php +2 -4
  125. src/lib/src/Modules/IPs/Lib/Ops/LookupIpOnList.php +0 -18
  126. src/lib/src/Modules/IPs/Lib/ProcessOffenses.php +2 -6
  127. src/lib/src/Modules/IPs/Options.php +10 -23
  128. src/lib/src/Modules/IPs/Strings.php +3 -1
  129. src/lib/src/Modules/IPs/UI.php +5 -5
  130. src/lib/src/Modules/Insights/AdminPage.php +12 -0
  131. src/lib/src/Modules/Insights/Lib/Requests/DynamicPageLoader.php +18 -6
  132. src/lib/src/Modules/Insights/Lib/SideMenuBuilder.php +86 -49
  133. src/lib/src/Modules/Insights/Lib/SummaryCards.php +184 -0
  134. src/lib/src/Modules/Insights/ModCon.php +17 -8
  135. src/lib/src/Modules/Insights/UI.php +31 -17
  136. src/lib/src/Modules/Integrations/Lib/Bots/Common/BaseBotDetectionController.php +50 -0
  137. src/lib/src/Modules/Integrations/Lib/Bots/Common/BaseHandler.php +49 -0
  138. src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/Base.php +32 -0
  139. src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/ContactForm7.php +20 -0
  140. src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/ElementorPro.php +26 -0
  141. src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/FluentForms.php +28 -0
  142. src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/FormidableForms.php +29 -0
  143. src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/Forminator.php +20 -0
  144. src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/GravityForms.php +22 -0
  145. src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/Groundhogg.php +21 -0
  146. src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/Helpers/NinjaForms_ShieldSpamAction.php +47 -0
  147. src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/KaliForms.php +27 -0
  148. src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/NinjaForms.php +48 -0
  149. src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/WPForms.php +37 -0
  150. src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/WpForo.php +40 -0
  151. src/lib/src/Modules/Integrations/Lib/Bots/Spam/SpamController.php +30 -0
  152. src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/Base.php +101 -0
  153. src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/Buddypress.php +28 -0
  154. src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/EasyDigitalDownloads.php +28 -0
  155. src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/LearnPress.php +48 -0
  156. src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/LifterLMS.php +50 -0
  157. src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/MemberPress.php +71 -0
  158. src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/PaidMemberSubscriptions.php +28 -0
  159. src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/ProfileBuilder.php +35 -0
  160. src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/UltimateMember.php +50 -0
  161. src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/WPMembers.php +52 -0
  162. src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/WooCommerce.php +66 -0
  163. src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/WordPress.php +92 -0
  164. src/lib/src/Modules/Integrations/Lib/Bots/UserForms/UserFormsController.php +43 -0
  165. src/lib/src/Modules/Integrations/Lib/MainWP/Controller.php +2 -6
  166. src/lib/src/Modules/Integrations/Lib/MainWP/Server/Data/SyncHandler.php +2 -6
  167. src/lib/src/Modules/Integrations/Lib/MainWP/Server/UI/ExtensionSettingsPage.php +2 -6
  168. src/lib/src/Modules/Integrations/Lib/Spam/Handlers/Base.php +2 -6
  169. src/lib/src/Modules/Integrations/Lib/Spam/SpamController.php +5 -0
  170. src/lib/src/Modules/Integrations/ModCon.php +13 -0
  171. src/lib/src/Modules/Integrations/Options.php +12 -0
  172. src/lib/src/Modules/Integrations/Processor.php +11 -4
  173. src/lib/src/Modules/Integrations/Strings.php +40 -2
  174. src/lib/src/Modules/Integrations/UI.php +71 -0
  175. src/lib/src/Modules/Integrations/Upgrade.php +25 -0
  176. src/lib/src/Modules/License/Lib/LookupRequest.php +15 -29
  177. src/lib/src/Modules/License/Lib/PluginNameSuffix.php +2 -4
  178. src/lib/src/Modules/License/Lib/Verify.php +25 -26
  179. src/lib/src/Modules/Lockdown/Insights/OverviewCards.php +11 -13
  180. src/lib/src/Modules/Lockdown/Lib/CleanRubbish.php +2 -6
  181. src/lib/src/Modules/LoginGuard/AjaxHandler.php +135 -35
  182. src/lib/src/Modules/LoginGuard/Insights/OverviewCards.php +12 -13
  183. src/lib/src/Modules/LoginGuard/Lib/AntiBot/AntibotSetup.php +4 -13
  184. src/lib/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/BaseFormProvider.php +12 -12
  185. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/LoginIntentPage.php +8 -8
  186. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/MfaController.php +57 -24
  187. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/MfaProfilesController.php +93 -0
  188. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Profiles/CustomForms.php +0 -67
  189. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Profiles/RenderCustomForms.php +55 -0
  190. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/{Backup.php → BackupCodes.php} +35 -35
  191. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/BaseProvider.php +52 -18
  192. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/BaseProviderV2.php +0 -279
  193. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Email.php +25 -20
  194. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/GoogleAuth.php +67 -35
  195. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/ProviderInterface.php +0 -13
  196. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/U2F.php +109 -106
  197. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Yubikey.php +91 -71
  198. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/UserProfile.php +62 -62
  199. src/lib/src/Modules/LoginGuard/Lib/TwoFactor/ValidateLoginIntentRequest.php +4 -4
  200. src/lib/src/Modules/LoginGuard/ModCon.php +6 -4
  201. src/lib/src/Modules/LoginGuard/Options.php +4 -0
  202. src/lib/src/Modules/LoginGuard/Strings.php +28 -12
  203. src/lib/src/Modules/LoginGuard/UI.php +26 -24
  204. src/lib/src/Modules/Plugin/AdminNotices.php +13 -6
  205. src/lib/src/Modules/Plugin/AjaxHandler.php +15 -0
  206. src/lib/src/Modules/Plugin/Components/PluginBadge.php +10 -5
  207. src/lib/src/Modules/Plugin/Insights/OverviewCards.php +12 -16
  208. src/lib/src/Modules/Plugin/Lib/PluginTelemetry.php +3 -6
  209. src/lib/src/Modules/Plugin/Strings.php +1 -1
  210. src/lib/src/Modules/Plugin/UI.php +27 -0
  211. src/lib/src/Modules/Reporting/Lib/ReportingController.php +2 -0
  212. src/lib/src/Modules/Reporting/Lib/Reports/CreateReportVO.php +34 -29
  213. src/lib/src/Modules/SecurityAdmin/Insights/OverviewCards.php +11 -10
  214. src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/Base.php +2 -5
  215. src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/WpOptions.php +0 -1
  216. src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/SecurityAdminController.php +19 -21
  217. src/lib/src/Modules/SecurityAdmin/Lib/WhiteLabel/BuildOptions.php +1 -1
  218. src/lib/src/Modules/SecurityAdmin/Lib/WhiteLabel/{ApplyLabels.php → WhitelabelController.php} +35 -20
  219. src/lib/src/Modules/SecurityAdmin/ModCon.php +6 -165
  220. src/lib/src/Modules/SecurityAdmin/Options.php +16 -4
  221. src/lib/src/Modules/SecurityAdmin/Processor.php +2 -159
  222. src/lib/src/Modules/Sessions/Lib/Ops/Retrieve.php +38 -0
  223. src/lib/src/Modules/Sessions/Lib/Ops/Terminate.php +9 -5
  224. src/lib/src/Modules/Sessions/Lib/SessionController.php +59 -3
  225. src/lib/src/Modules/Sessions/Processor.php +19 -7
  226. src/lib/src/Modules/Traffic/Strings.php +5 -2
  227. src/lib/src/Modules/UserManagement/AjaxHandler.php +19 -19
  228. src/lib/src/Modules/UserManagement/Insights/OverviewCards.php +11 -13
  229. src/lib/src/Modules/UserManagement/Lib/Password/UserPasswordHandler.php +2 -5
  230. src/lib/src/Modules/UserManagement/Lib/Session/UserSessionHandler.php +2 -8
  231. src/lib/src/Modules/UserManagement/Lib/Suspend/UserSuspendController.php +3 -5
  232. src/lib/src/Modules/UserManagement/ModCon.php +15 -15
  233. src/lib/src/Modules/UserManagement/Processor.php +19 -19
  234. src/lib/src/Tables/Build/Traffic.php +2 -2
  235. src/lib/src/Tables/Render/Common/BaseTable.php +151 -0
  236. src/lib/src/Tables/Render/DataTable/Base.php +10 -0
  237. src/lib/src/Tables/Render/DataTable/ScanBase.php +9 -0
  238. src/lib/src/Tables/Render/DataTable/ScanWcf.php +9 -0
  239. src/lib/src/Tables/Render/WpListTable/ScanBase.php +3 -3
  240. src/lib/src/Users/ShieldUserMeta.php +22 -22
  241. src/lib/src/Utilities/Consumer/WpLoginCapture.php +24 -1
  242. src/lib/src/Utilities/Consumer/WpUserConsumer.php +6 -6
  243. src/lib/vendor/bacon/bacon-qr-code/Module.php +37 -0
  244. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/AbstractEnum.php +115 -0
  245. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitArray.php +435 -0
  246. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitMatrix.php +350 -0
  247. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitUtils.php +51 -0
  248. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/CharacterSetEci.php +134 -0
  249. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/EcBlock.php +65 -0
  250. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/EcBlocks.php +101 -0
  251. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/ErrorCorrectionLevel.php +62 -0
  252. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/FormatInformation.php +236 -0
  253. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/Mode.php +70 -0
  254. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/ReedSolomonCodec.php +476 -0
  255. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/Version.php +687 -0
  256. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/BlockPair.php +64 -0
  257. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/ByteMatrix.php +158 -0
  258. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/Encoder.php +687 -0
  259. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/MaskUtil.php +291 -0
  260. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/MatrixUtil.php +580 -0
  261. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/QrCode.php +201 -0
  262. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/ExceptionInterface.php +14 -0
  263. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/InvalidArgumentException.php +14 -0
  264. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/OutOfBoundsException.php +14 -0
  265. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/RuntimeException.php +14 -0
  266. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/UnexpectedValueException.php +14 -0
  267. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/WriterException.php +14 -0
  268. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/Cmyk.php +160 -0
  269. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/ColorInterface.php +37 -0
  270. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/Gray.php +84 -0
  271. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/Rgb.php +148 -0
  272. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/AbstractRenderer.php +338 -0
  273. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Decorator/DecoratorInterface.php +63 -0
  274. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Decorator/FinderPattern.php +210 -0
  275. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Eps.php +152 -0
  276. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Png.php +115 -0
  277. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/RendererInterface.php +61 -0
  278. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Svg.php +146 -0
  279. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/RendererInterface.php +26 -0
  280. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Text/Html.php +91 -0
  281. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Text/Plain.php +150 -0
  282. src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Writer.php +105 -0
  283. src/lib/vendor/composer/autoload_classmap.php +213 -5
  284. src/lib/vendor/composer/autoload_files.php +2 -1
  285. src/lib/vendor/composer/autoload_namespaces.php +1 -0
  286. src/lib/vendor/composer/autoload_psr4.php +4 -0
  287. src/lib/vendor/composer/autoload_static.php +248 -6
  288. src/lib/vendor/dolondro/google-authenticator/src/GoogleAuthenticator.php +2 -1
  289. src/lib/vendor/dolondro/google-authenticator/src/QrImageGenerator/EndroidQrImageGenerator.php +4 -2
  290. src/lib/vendor/endroid/qr-code/src/Bundle/QrCodeBundle/Controller/QrCodeController.php +64 -0
  291. src/lib/vendor/endroid/qr-code/src/Bundle/QrCodeBundle/DependencyInjection/Compiler/WriterRegistryCompilerPass.php +36 -0
  292. src/lib/vendor/endroid/qr-code/src/Bundle/QrCodeBundle/DependencyInjection/Configuration.php +77 -0
  293. src/lib/vendor/endroid/qr-code/src/Bundle/QrCodeBundle/DependencyInjection/EndroidQrCodeExtension.php +34 -0
  294. src/lib/vendor/endroid/qr-code/src/Bundle/QrCodeBundle/EndroidQrCodeBundle.php +27 -0
  295. src/lib/vendor/endroid/qr-code/src/Bundle/QrCodeBundle/Resources/config/routing.yml +11 -0
  296. src/lib/vendor/endroid/qr-code/src/Bundle/QrCodeBundle/Resources/config/services.yml +31 -0
  297. src/lib/vendor/endroid/qr-code/src/Bundle/QrCodeBundle/Resources/views/QrCode/twigFunctions.html.twig +3 -0
  298. src/lib/vendor/endroid/qr-code/src/ErrorCorrectionLevel.php +20 -0
  299. src/lib/vendor/endroid/qr-code/src/Exception/InvalidPathException.php +14 -0
  300. src/lib/vendor/endroid/qr-code/src/Exception/InvalidWriterException.php +14 -0
  301. src/lib/vendor/endroid/qr-code/src/Exception/MissingFunctionException.php +14 -0
  302. src/lib/vendor/endroid/qr-code/src/Exception/QrCodeException.php +16 -0
  303. src/lib/vendor/endroid/qr-code/src/Exception/UnsupportedExtensionException.php +14 -0
  304. src/lib/vendor/endroid/qr-code/src/Exception/ValidationException.php +14 -0
  305. src/lib/vendor/endroid/qr-code/src/Factory/QrCodeFactory.php +120 -0
  306. src/lib/vendor/endroid/qr-code/src/LabelAlignment.php +19 -0
  307. src/lib/vendor/endroid/qr-code/src/QrCode.php +591 -0
  308. src/lib/vendor/endroid/qr-code/src/QrCodeInterface.php +95 -0
  309. src/lib/vendor/endroid/qr-code/src/StaticWriterRegistry.php +42 -0
  310. src/lib/vendor/endroid/qr-code/src/Twig/Extension/QrCodeExtension.php +117 -0
  311. src/lib/vendor/endroid/qr-code/src/Writer/AbstractBaconWriter.php +40 -0
  312. src/lib/vendor/endroid/qr-code/src/Writer/AbstractWriter.php +63 -0
  313. src/lib/vendor/endroid/qr-code/src/Writer/BinaryWriter.php +52 -0
  314. src/lib/vendor/endroid/qr-code/src/Writer/DebugWriter.php +58 -0
  315. src/lib/vendor/endroid/qr-code/src/Writer/EpsWriter.php +19 -0
cl.json CHANGED
@@ -1,4 +1,63 @@
1
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  "11.1": {
3
  "version": "11.1",
4
  "released_at": 1616666000,
@@ -6,7 +65,6 @@
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.",
@@ -114,7 +172,6 @@
114
  "release": "https://shsec.io/shieldrelease110",
115
  "upgrade": "https://shsec.io/shieldupgradeguide110"
116
  },
117
- "href": "https://shsec.io/",
118
  "title": "All-New Shield AntiBot Detection Engine",
119
  "description": [
120
  "WordPress security nearly always starts with bots - detecting bad bots and blocking them.",
@@ -224,7 +281,6 @@
224
  "release": "https://shsec.io/shieldrelease102",
225
  "upgrade": "https://shsec.io/shieldupgradeguide102"
226
  },
227
- "href": "https://shsec.io/",
228
  "title": "Removal of simple Content Security Policy settings and bugfixes",
229
  "description": [
230
  "We've decided to remove our simple Content Security Policy options as this feature is too complex.",
@@ -353,7 +409,6 @@
353
  "release": "https://shsec.io/shieldrelease101",
354
  "upgrade": "https://shsec.io/shieldupgradeguide101"
355
  },
356
- "href": "https://shsec.io/",
357
  "title": "Enhanced Dashboard + MainWP Integration",
358
  "description": [
359
  "We're continuing our improvements to the Shield UI with a brand new Dashboard.",
@@ -490,7 +545,6 @@
490
  "release": "https://shsec.io/shieldrelease100",
491
  "upgrade": "https://shsec.io/shieldupgradeguide100"
492
  },
493
- "href": "https://shsec.io/",
494
  "title": "All-New PHP-7 Optimised Shield Security",
495
  "description": [
496
  "We've massively enhanced the Dashboard UI, making it much easier to secure your WordPress site by quickly identifying areas of improvement.",
1
  {
2
+ "11.2": {
3
+ "version": "11.2",
4
+ "released_at": 1621844125,
5
+ "hrefs": {
6
+ "release": "https://shsec.io/shieldrelease112",
7
+ "upgrade": "https://shsec.io/shieldupgradeguide112"
8
+ },
9
+ "title": "AntiBot Scoring Improvements",
10
+ "description": [
11
+ "Shield 11.0 brought the new AntiBot Detection Engine, designed to detect bad bots and block them.",
12
+ "With feedback from customers and ongoing research, we've made some major improvements and adjustments to the system."
13
+ ],
14
+ "items": [
15
+ {
16
+ "type": "new",
17
+ "pro_only": false,
18
+ "title": "New And Improved Welcome Wizard",
19
+ "description": [
20
+ "All-New Welcome Wizard designed to get you up and running with Shield quickly and effortlessly."
21
+ ]
22
+ },
23
+ {
24
+ "type": "new",
25
+ "title": "Add Shield's Two-Factor Authentication User Settings Anywhere",
26
+ "description": [
27
+ "With the use of a WP Shortcode, you can add user configuration pages for 2FA into any page.",
28
+ "This is useful if you want to offer 2FA options to your customers."
29
+ ]
30
+ },
31
+ {
32
+ "type": "improved",
33
+ "title": "AntiBot Detection Engine Improvements.",
34
+ "description": [
35
+ "We've adjusted some of the bot scoring and improved the ability to detect legitimate users based on earlier logins.",
36
+ "We've also removed the need for the small cookie that was needed to help track the NotBot status."
37
+ ]
38
+ },
39
+ {
40
+ "type": "new",
41
+ "title": "Support For Groundhogg",
42
+ "description": [
43
+ "Added support for protecting Groundhogg forms from bots."
44
+ ],
45
+ "href": "https://shsec.io/groundhogg"
46
+ },
47
+ {
48
+ "type": "new",
49
+ "title": "Support For LifterLMS.",
50
+ "description": [
51
+ "Added support for protecting LifterLMS login & registration forms from bots."
52
+ ]
53
+ },
54
+ {
55
+ "type": "fixed",
56
+ "title": "The tour system would run multiple times.",
57
+ "description": []
58
+ }
59
+ ]
60
+ },
61
  "11.1": {
62
  "version": "11.1",
63
  "released_at": 1616666000,
65
  "release": "https://shsec.io/shieldrelease111",
66
  "upgrade": "https://shsec.io/shieldupgradeguide111"
67
  },
 
68
  "title": "UI Cleanup and Enhancement",
69
  "description": [
70
  "With Shield being such a large plugin, it's been a challenge to get a UI that everyone is happy with.",
172
  "release": "https://shsec.io/shieldrelease110",
173
  "upgrade": "https://shsec.io/shieldupgradeguide110"
174
  },
 
175
  "title": "All-New Shield AntiBot Detection Engine",
176
  "description": [
177
  "WordPress security nearly always starts with bots - detecting bad bots and blocking them.",
281
  "release": "https://shsec.io/shieldrelease102",
282
  "upgrade": "https://shsec.io/shieldupgradeguide102"
283
  },
 
284
  "title": "Removal of simple Content Security Policy settings and bugfixes",
285
  "description": [
286
  "We've decided to remove our simple Content Security Policy options as this feature is too complex.",
409
  "release": "https://shsec.io/shieldrelease101",
410
  "upgrade": "https://shsec.io/shieldupgradeguide101"
411
  },
 
412
  "title": "Enhanced Dashboard + MainWP Integration",
413
  "description": [
414
  "We're continuing our improvements to the Shield UI with a brand new Dashboard.",
545
  "release": "https://shsec.io/shieldrelease100",
546
  "upgrade": "https://shsec.io/shieldupgradeguide100"
547
  },
 
548
  "title": "All-New PHP-7 Optimised Shield Security",
549
  "description": [
550
  "We've massively enhanced the Dashboard UI, making it much easier to secure your WordPress site by quickly identifying areas of improvement.",
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.1.1
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.2.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.1.1",
4
- "release_timestamp": 1618305000,
5
- "build": "202104.1301",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
  "human_name": "Shield Security",
@@ -51,15 +51,15 @@
51
  "css": [
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
  ]
@@ -73,38 +73,47 @@
73
  "bootstrap": {
74
  "url": "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.0/css/bootstrap.min.css"
75
  },
76
- "select2": {
77
- "url": "https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/css/select2.min.css",
78
- "deps": [
79
- "plugin"
80
- ]
81
- },
82
  "bootstrap-datepicker": {
83
  "url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.8.0/css/bootstrap-datepicker.min.css",
84
  "deps": [
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": [
 
97
  "bootstrap",
98
  "global-plugin"
99
  ]
100
  },
101
- "wizard": {
102
  "deps": [
103
  "bootstrap",
104
  "global-plugin"
105
  ]
106
  },
107
- "featherlight": {},
 
 
108
  "chartist": {
109
  "url": "https://cdnjs.cloudflare.com/ajax/libs/chartist/0.11.4/chartist.min.css"
110
  },
@@ -121,159 +130,177 @@
121
  "plugin"
122
  ]
123
  },
124
- "shield/mainwp": {}
 
 
 
 
 
 
125
  },
126
  "js": {
127
- "bootstrap": {
128
  "url": "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.0/js/bootstrap.bundle.min.js",
129
  "deps": [
130
  "wp-jquery"
131
  ]
132
  },
133
- "select2": {
134
  "url": "https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/js/select2.min.js",
135
  "deps": [
136
  "plugin"
137
  ]
138
  },
139
- "bootstrap-datepicker": {
140
  "url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.8.0/js/bootstrap-datepicker.min.js",
141
  "deps": [
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"
154
  ]
155
  },
156
- "plugin": {
 
 
 
 
 
157
  "deps": [
158
  "bootstrap",
 
159
  "global-plugin",
160
  "shield/navigation",
161
  "base64.min",
162
  "lz-string.min"
163
  ]
164
  },
165
- "base64.min": {
166
  "url": "https://cdn.jsdelivr.net/npm/js-base64@2.6.4/base64.min.js"
167
  },
168
- "lz-string.min": {},
169
- "jquery.fileDownload": {
170
- "deps": [
171
- "wp-jquery"
172
- ]
173
  },
174
- "featherlight": {
175
- "deps": [
176
- "wp-jquery"
177
- ]
178
  },
179
- "chartist": {
180
  "url": "https://cdnjs.cloudflare.com/ajax/libs/chartist/0.11.4/chartist.min.js"
181
  },
182
- "chartist-plugin-legend": {
183
  "deps": [
184
  "chartist"
185
  ]
186
  },
187
- "introjs": {
188
  "url": "https://cdnjs.cloudflare.com/ajax/libs/intro.js/3.3.1/intro.min.js"
189
  },
190
- "shield/charts": {
191
  "deps": [
192
  "chartist",
193
  "chartist-plugin-legend",
194
  "plugin"
195
  ]
196
  },
197
- "shuffle": {
198
  "url": "https://cdnjs.cloudflare.com/ajax/libs/Shuffle/5.3.0/shuffle.min.js"
199
  },
200
- "shield/shuffle": {
201
  "deps": [
202
  "shuffle"
203
  ]
204
  },
205
- "shield/comments": {
 
 
 
 
 
206
  "deps": [
207
  "wp-jquery"
208
  ],
209
  "footer": true
210
  },
211
- "shield/loginbot": {
212
  "deps": [
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"
225
  ]
226
  },
227
- "shield/tours": {
228
  "deps": [
229
  "plugin",
230
  "introjs"
231
  ]
232
  },
233
- "shield/antibot": {
234
- "footer": true
235
  },
236
- "shield/scans": {
237
  "deps": [
238
  "shield/tables"
239
  ]
240
  },
241
- "shield/import": {
242
  "deps": [
243
  "plugin"
244
  ]
245
  },
246
- "shield/ipanalyse": {
247
  "deps": [
248
  "plugin"
249
  ]
250
  },
251
- "shield/mainwp": {
252
  "deps": [
253
  "wp-jquery"
254
  ]
255
  },
256
- "shield/userprofile": {
257
- "deps": [
258
- "global-plugin"
259
- ]
 
 
260
  },
261
- "u2f-bundle": {},
262
- "shield/u2f-admin": {
263
  "deps": [
264
- "u2f-bundle",
265
- "wp-jquery"
 
266
  ]
267
  },
268
- "tp/grecaptcha": {
269
- "url": "https://www.google.com/recaptcha/api.js",
 
270
  "attributes": {
271
  "async": "async",
272
  "defer": "defer"
273
  }
274
  },
275
- "tp/hcaptcha": {
276
- "url": "https://hcaptcha.com/1/api.js",
277
  "attributes": {
278
  "async": "async",
279
  "defer": "defer"
@@ -318,7 +345,8 @@
318
  "9.2.0",
319
  "9.2.2",
320
  "10.1.0",
321
- "10.2.1"
 
322
  ],
323
  "action_links": {
324
  "remove": null,
1
  {
2
  "properties": {
3
+ "version": "11.2.0",
4
+ "release_timestamp": 1622017666,
5
+ "build": "202105.2601",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
  "human_name": "Shield Security",
51
  "css": [
52
  "select2",
53
  "plugin",
54
+ "jquery/featherlight",
55
  "introjs",
56
  "bootstrap-select"
57
  ],
58
  "js": [
59
  "select2",
60
  "plugin",
61
+ "jquery/featherlight",
62
+ "jquery/fileDownload",
63
  "shield/tours",
64
  "bootstrap-select"
65
  ]
73
  "bootstrap": {
74
  "url": "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.0/css/bootstrap.min.css"
75
  },
 
 
 
 
 
 
76
  "bootstrap-datepicker": {
77
  "url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.8.0/css/bootstrap-datepicker.min.css",
78
  "deps": [
79
  "bootstrap"
80
  ]
81
  },
82
+ "bootstrap-select": {
83
  "url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.18/css/bootstrap-select.min.css",
84
  "deps": [
85
  "bootstrap"
86
  ]
87
  },
88
+ "select2": {
89
+ "url": "https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/css/select2.min.css",
90
+ "deps": [
91
+ "plugin"
92
+ ]
93
+ },
94
+ "datatables": {
95
+ "url": "https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.21/css/dataTables.bootstrap4.min.css",
96
+ "deps": [
97
+ "bootstrap"
98
+ ]
99
+ },
100
  "global-plugin": {},
101
  "plugin": {
102
  "deps": [
103
+ "datatables",
104
  "bootstrap",
105
  "global-plugin"
106
  ]
107
  },
108
+ "shield/wizard": {
109
  "deps": [
110
  "bootstrap",
111
  "global-plugin"
112
  ]
113
  },
114
+ "jquery/featherlight": {
115
+ "url": "https://cdnjs.cloudflare.com/ajax/libs/featherlight/1.7.13/featherlight.min.css"
116
+ },
117
  "chartist": {
118
  "url": "https://cdnjs.cloudflare.com/ajax/libs/chartist/0.11.4/chartist.min.css"
119
  },
130
  "plugin"
131
  ]
132
  },
133
+ "shield/dialog": {
134
+ "deps": [
135
+ "wp-wp-jquery-ui-dialog"
136
+ ],
137
+ "footer": true
138
+ },
139
+ "shield/mainwp": {}
140
  },
141
  "js": {
142
+ "bootstrap": {
143
  "url": "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.0/js/bootstrap.bundle.min.js",
144
  "deps": [
145
  "wp-jquery"
146
  ]
147
  },
148
+ "select2": {
149
  "url": "https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/js/select2.min.js",
150
  "deps": [
151
  "plugin"
152
  ]
153
  },
154
+ "bootstrap-datepicker": {
155
  "url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.8.0/js/bootstrap-datepicker.min.js",
156
  "deps": [
157
  "bootstrap"
158
  ]
159
  },
160
+ "bootstrap-select": {
161
  "url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.18/js/bootstrap-select.min.js",
162
  "deps": [
163
  "bootstrap"
164
  ]
165
  },
166
+ "datatables": {
167
+ "url": "https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.21/js/jquery.dataTables.min.js",
168
  "deps": [
169
+ "bootstrap",
170
  "wp-jquery"
171
  ]
172
  },
173
+ "global-plugin": {
174
+ "deps": [
175
+ "wp-jquery"
176
+ ]
177
+ },
178
+ "plugin": {
179
  "deps": [
180
  "bootstrap",
181
+ "datatables",
182
  "global-plugin",
183
  "shield/navigation",
184
  "base64.min",
185
  "lz-string.min"
186
  ]
187
  },
188
+ "base64.min": {
189
  "url": "https://cdn.jsdelivr.net/npm/js-base64@2.6.4/base64.min.js"
190
  },
191
+ "lz-string.min": {},
192
+ "jquery/fileDownload": {},
193
+ "jquery/steps": {
194
+ "url": "https://cdnjs.cloudflare.com/ajax/libs/jquery-steps/1.1.0/jquery.steps.min.js"
 
195
  },
196
+ "jquery/featherlight": {
197
+ "url": "https://cdnjs.cloudflare.com/ajax/libs/featherlight/1.7.13/featherlight.min.js"
 
 
198
  },
199
+ "chartist": {
200
  "url": "https://cdnjs.cloudflare.com/ajax/libs/chartist/0.11.4/chartist.min.js"
201
  },
202
+ "chartist-plugin-legend": {
203
  "deps": [
204
  "chartist"
205
  ]
206
  },
207
+ "introjs": {
208
  "url": "https://cdnjs.cloudflare.com/ajax/libs/intro.js/3.3.1/intro.min.js"
209
  },
210
+ "shield/charts": {
211
  "deps": [
212
  "chartist",
213
  "chartist-plugin-legend",
214
  "plugin"
215
  ]
216
  },
217
+ "shuffle": {
218
  "url": "https://cdnjs.cloudflare.com/ajax/libs/Shuffle/5.3.0/shuffle.min.js"
219
  },
220
+ "shield/shuffle": {
221
  "deps": [
222
  "shuffle"
223
  ]
224
  },
225
+ "shield/dialog": {
226
+ "deps": [
227
+ "wp-jquery-ui-dialog"
228
+ ]
229
+ },
230
+ "shield/comments": {
231
  "deps": [
232
  "wp-jquery"
233
  ],
234
  "footer": true
235
  },
236
+ "shield/loginbot": {
237
  "deps": [
238
  "wp-jquery"
239
  ]
240
  },
241
+ "shield/navigation": {},
242
+ "shield/secadmin": {
243
  "deps": [
244
  "wp-jquery"
245
  ]
246
  },
247
+ "shield/tables": {
248
  "deps": [
249
  "plugin"
250
  ]
251
  },
252
+ "shield/tours": {
253
  "deps": [
254
  "plugin",
255
  "introjs"
256
  ]
257
  },
258
+ "shield/antibot": {
 
259
  },
260
+ "shield/scans": {
261
  "deps": [
262
  "shield/tables"
263
  ]
264
  },
265
+ "shield/import": {
266
  "deps": [
267
  "plugin"
268
  ]
269
  },
270
+ "shield/ipanalyse": {
271
  "deps": [
272
  "plugin"
273
  ]
274
  },
275
+ "shield/mainwp": {
276
  "deps": [
277
  "wp-jquery"
278
  ]
279
  },
280
+ "shield/userprofile": {
281
+ "deps": [
282
+ "u2f-bundle",
283
+ "shield/dialog"
284
+ ],
285
+ "footer": true
286
  },
287
+ "shield/wizard": {
 
288
  "deps": [
289
+ "bootstrap",
290
+ "global-plugin",
291
+ "jquery/steps"
292
  ]
293
  },
294
+ "u2f-bundle": {},
295
+ "tp/grecaptcha": {
296
+ "url": "https://www.google.com/recaptcha/api.js",
297
  "attributes": {
298
  "async": "async",
299
  "defer": "defer"
300
  }
301
  },
302
+ "tp/hcaptcha": {
303
+ "url": "https://hcaptcha.com/1/api.js",
304
  "attributes": {
305
  "async": "async",
306
  "defer": "defer"
345
  "9.2.0",
346
  "9.2.2",
347
  "10.1.0",
348
+ "10.2.1",
349
+ "11.2.0"
350
  ],
351
  "action_links": {
352
  "remove": null,
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.1.1
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 ==
@@ -268,7 +268,7 @@ Login Cooldown prevents more than 1 login attempt to your site every "so-many" s
268
 
269
  This system completely blocks any level of brute-force login attacks and a cooldown of just 1 second goes a long way.
270
 
271
- More Info: https://shsec.io/2t
272
 
273
  = How does the GASP Login Guard work? =
274
 
8
  Requires PHP: 7.0
9
  Recommended PHP: 7.4
10
  Tested up to: 5.7
11
+ Stable tag: 11.2.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 ==
268
 
269
  This system completely blocks any level of brute-force login attacks and a cooldown of just 1 second goes a long way.
270
 
271
+ [More Info](https://shsec.io/2t)
272
 
273
  = How does the GASP Login Guard work? =
274
 
resources/css/featherlight.css DELETED
@@ -1,141 +0,0 @@
1
- /**
2
- * Featherlight – ultra slim jQuery lightbox
3
- * Version 1.7.1 - http://noelboss.github.io/featherlight/
4
- *
5
- * Copyright 2017, Noël Raoul Bossart (http://www.noelboss.com)
6
- * MIT Licensed.
7
- **/
8
- @media all {
9
- .featherlight {
10
- display: none;
11
-
12
- /* dimensions: spanning the background from edge to edge */
13
- position:fixed;
14
- top: 0; right: 0; bottom: 0; left: 0;
15
- z-index: 2147483647; /* z-index needs to be >= elements on the site. */
16
-
17
- /* position: centering content */
18
- text-align: center;
19
-
20
- /* insures that the ::before pseudo element doesn't force wrap with fixed width content; */
21
- white-space: nowrap;
22
-
23
- /* styling */
24
- cursor: pointer;
25
- background: #333;
26
- /* IE8 "hack" for nested featherlights */
27
- background: rgba(0, 0, 0, 0);
28
- }
29
-
30
- /* support for nested featherlights. Does not work in IE8 (use JS to fix) */
31
- .featherlight:last-of-type {
32
- background: rgba(0, 0, 0, 0.8);
33
- }
34
-
35
- .featherlight:before {
36
- /* position: trick to center content vertically */
37
- content: '';
38
- display: inline-block;
39
- height: 100%;
40
- vertical-align: middle;
41
- }
42
-
43
- .featherlight .featherlight-content {
44
- /* make content container for positioned elements (close button) */
45
- position: relative;
46
-
47
- /* position: centering vertical and horizontal */
48
- text-align: left;
49
- vertical-align: middle;
50
- display: inline-block;
51
-
52
- /* dimensions: cut off images */
53
- overflow: auto;
54
- padding: 25px 25px 0;
55
- border-bottom: 25px solid transparent;
56
-
57
- /* dimensions: handling large content */
58
- margin-left: 5%;
59
- margin-right: 5%;
60
- max-height: 95%;
61
-
62
- /* styling */
63
- background: #fff;
64
- cursor: auto;
65
-
66
- /* reset white-space wrapping */
67
- white-space: normal;
68
- }
69
-
70
- /* contains the content */
71
- .featherlight .featherlight-inner {
72
- /* make sure its visible */
73
- display: block;
74
- }
75
-
76
- .featherlight .featherlight-close-icon {
77
- /* position: centering vertical and horizontal */
78
- position: absolute;
79
- z-index: 9999;
80
- top: 0;
81
- right: 0;
82
-
83
- /* dimensions: 25px x 25px */
84
- line-height: 25px;
85
- width: 25px;
86
-
87
- /* styling */
88
- cursor: pointer;
89
- text-align: center;
90
- font-family: Arial, sans-serif;
91
- background: #fff; /* Set the background in case it overlaps the content */
92
- background: rgba(255, 255, 255, 0.3);
93
- color: #000;
94
- border: none;
95
- padding: 0;
96
- }
97
-
98
- /* See http://stackoverflow.com/questions/16077341/how-to-reset-all-default-styles-of-the-html5-button-element */
99
- .featherlight .featherlight-close-icon::-moz-focus-inner {
100
- border: 0;
101
- padding: 0;
102
- }
103
-
104
- .featherlight .featherlight-image {
105
- /* styling */
106
- width: 100%;
107
- }
108
-
109
-
110
- .featherlight-iframe .featherlight-content {
111
- /* removed the border for image croping since iframe is edge to edge */
112
- border-bottom: 0;
113
- padding: 0;
114
- -webkit-overflow-scrolling: touch;
115
- overflow-y: scroll;
116
- }
117
-
118
- .featherlight iframe {
119
- /* styling */
120
- border: none;
121
- }
122
-
123
- .featherlight * { /* See https://github.com/noelboss/featherlight/issues/42 */
124
- -webkit-box-sizing: border-box;
125
- -moz-box-sizing: border-box;
126
- box-sizing: border-box;
127
- }
128
- }
129
-
130
- /* handling phones and small screens */
131
- @media only screen and (max-width: 1024px) {
132
- .featherlight .featherlight-content {
133
- /* dimensions: maximize lightbox with for small screens */
134
- margin-left: 0;
135
- margin-right: 0;
136
- max-height: 98%;
137
-
138
- padding: 10px 10px 0;
139
- border-bottom: 10px solid transparent;
140
- }
141
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
resources/css/global-plugin.css CHANGED
@@ -167,8 +167,8 @@ tr.icwp-plugin-vulnerability dd {
167
  padding: 0 7px;
168
  background-color: whitesmoke;
169
  }
170
- .wp-submenu-wrap a .icwp_highlighted {
171
- color: #008000;
172
  }
173
  #icwp-wpsf-dashboard_widget {
174
  }
@@ -351,4 +351,6 @@ tr.icwp-plugin-vulnerability dd {
351
  border-radius: 50%;
352
  margin-left: 6px;
353
  /*background-color: rgb(0, 128, 0);*/
354
- }
 
 
167
  padding: 0 7px;
168
  background-color: whitesmoke;
169
  }
170
+ .wp-submenu-wrap a .shield_highlighted_menu {
171
+ color: #00ff00;
172
  }
173
  #icwp-wpsf-dashboard_widget {
174
  }
351
  border-radius: 50%;
352
  margin-left: 6px;
353
  /*background-color: rgb(0, 128, 0);*/
354
+ }
355
+
356
+ /* override boostrap */
resources/css/jquery.fancybox.min.css DELETED
@@ -1 +0,0 @@
1
- @charset "UTF-8";body.fancybox-active{overflow:hidden}body.fancybox-iosfix{position:fixed;left:0;right:0}.fancybox-is-hidden{position:absolute;top:-9999px;left:-9999px;visibility:hidden}.fancybox-container{position:fixed;top:0;left:0;width:100%;height:100%;z-index:99992;-webkit-tap-highlight-color:transparent;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform:translateZ(0);transform:translateZ(0);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.fancybox-bg,.fancybox-inner,.fancybox-outer,.fancybox-stage{position:absolute;top:0;right:0;bottom:0;left:0}.fancybox-outer{overflow-y:auto;-webkit-overflow-scrolling:touch}.fancybox-bg{background:#1e1e1e;opacity:0;transition-duration:inherit;transition-property:opacity;transition-timing-function:cubic-bezier(.47,0,.74,.71)}.fancybox-is-open .fancybox-bg{opacity:.87;transition-timing-function:cubic-bezier(.22,.61,.36,1)}.fancybox-caption-wrap,.fancybox-infobar,.fancybox-toolbar{position:absolute;direction:ltr;z-index:99997;opacity:0;visibility:hidden;transition:opacity .25s,visibility 0s linear .25s;box-sizing:border-box}.fancybox-show-caption .fancybox-caption-wrap,.fancybox-show-infobar .fancybox-infobar,.fancybox-show-toolbar .fancybox-toolbar{opacity:1;visibility:visible;transition:opacity .25s,visibility 0s}.fancybox-infobar{top:0;left:0;font-size:13px;padding:0 10px;height:44px;min-width:44px;line-height:44px;color:#ccc;text-align:center;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-touch-callout:none;-webkit-tap-highlight-color:transparent;-webkit-font-smoothing:subpixel-antialiased;mix-blend-mode:exclusion}.fancybox-toolbar{top:0;right:0;margin:0;padding:0}.fancybox-stage{overflow:hidden;direction:ltr;z-index:99994;-webkit-transform:translateZ(0)}.fancybox-is-closing .fancybox-stage{overflow:visible}.fancybox-slide{position:absolute;top:0;left:0;width:100%;height:100%;margin:0;padding:0;overflow:auto;outline:none;white-space:normal;box-sizing:border-box;text-align:center;z-index:99994;-webkit-overflow-scrolling:touch;display:none;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition-property:opacity,-webkit-transform;transition-property:transform,opacity;transition-property:transform,opacity,-webkit-transform}.fancybox-slide:before{content:"";display:inline-block;vertical-align:middle;height:100%;width:0}.fancybox-is-sliding .fancybox-slide,.fancybox-slide--current,.fancybox-slide--next,.fancybox-slide--previous{display:block}.fancybox-slide--image{overflow:visible}.fancybox-slide--image:before{display:none}.fancybox-slide--video .fancybox-content,.fancybox-slide--video iframe{background:#000}.fancybox-slide--map .fancybox-content,.fancybox-slide--map iframe{background:#e5e3df}.fancybox-slide--next{z-index:99995}.fancybox-slide>*{display:inline-block;position:relative;padding:24px;margin:44px 0;border-width:0;vertical-align:middle;text-align:left;background-color:#fff;overflow:auto;box-sizing:border-box}.fancybox-slide>base,.fancybox-slide>link,.fancybox-slide>meta,.fancybox-slide>script,.fancybox-slide>style,.fancybox-slide>title{display:none}.fancybox-slide .fancybox-image-wrap{position:absolute;top:0;left:0;margin:0;padding:0;border:0;z-index:99995;background:transparent;cursor:default;overflow:visible;-webkit-transform-origin:top left;transform-origin:top left;background-size:100% 100%;background-repeat:no-repeat;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;transition-property:opacity,-webkit-transform;transition-property:transform,opacity;transition-property:transform,opacity,-webkit-transform}.fancybox-can-zoomOut .fancybox-image-wrap{cursor:zoom-out}.fancybox-can-zoomIn .fancybox-image-wrap{cursor:zoom-in}.fancybox-can-drag .fancybox-image-wrap{cursor:-webkit-grab;cursor:grab}.fancybox-is-dragging .fancybox-image-wrap{cursor:-webkit-grabbing;cursor:grabbing}.fancybox-image,.fancybox-spaceball{position:absolute;top:0;left:0;width:100%;height:100%;margin:0;padding:0;border:0;max-width:none;max-height:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.fancybox-spaceball{z-index:1}.fancybox-slide--iframe .fancybox-content{padding:0;width:80%;height:80%;max-width:calc(100% - 100px);max-height:calc(100% - 88px);overflow:visible;background:#fff}.fancybox-iframe{display:block;padding:0;border:0;height:100%}.fancybox-error,.fancybox-iframe{margin:0;width:100%;background:#fff}.fancybox-error{padding:40px;max-width:380px;cursor:default}.fancybox-error p{margin:0;padding:0;color:#444;font-size:16px;line-height:20px}.fancybox-button{box-sizing:border-box;display:inline-block;vertical-align:top;width:44px;height:44px;margin:0;padding:10px;border:0;border-radius:0;background:rgba(30,30,30,.6);transition:color .3s ease;cursor:pointer;outline:none}.fancybox-button,.fancybox-button:link,.fancybox-button:visited{color:#ccc}.fancybox-button:focus,.fancybox-button:hover{color:#fff}.fancybox-button[disabled]{color:#ccc;cursor:default;opacity:.6}.fancybox-button svg{display:block;position:relative;overflow:visible;shape-rendering:geometricPrecision}.fancybox-button svg path{fill:currentColor;stroke:currentColor;stroke-linejoin:round;stroke-width:3}.fancybox-button--share svg path{stroke-width:1}.fancybox-button--pause svg path:nth-child(1),.fancybox-button--play svg path:nth-child(2){display:none}.fancybox-button--zoom svg path{fill:transparent}.fancybox-navigation{display:none}.fancybox-show-nav .fancybox-navigation{display:block}.fancybox-navigation button{position:absolute;top:50%;margin:-50px 0 0;z-index:99997;background:transparent;width:60px;height:100px;padding:17px}.fancybox-navigation button:before{content:"";position:absolute;top:30px;right:10px;width:40px;height:40px;background:rgba(30,30,30,.6)}.fancybox-navigation .fancybox-button--arrow_left{left:0}.fancybox-navigation .fancybox-button--arrow_right{right:0}.fancybox-close-small{position:absolute;top:0;right:0;width:40px;height:40px;padding:0;margin:0;border:0;border-radius:0;background:transparent;z-index:10;cursor:pointer}.fancybox-close-small:after{content:"×";position:absolute;top:5px;right:5px;width:30px;height:30px;font:22px/30px Arial,Helvetica Neue,Helvetica,sans-serif;color:#888;font-weight:300;text-align:center;border-radius:50%;border-width:0;background-color:transparent;transition:background-color .25s;box-sizing:border-box;z-index:2}.fancybox-close-small:focus{outline:none}.fancybox-close-small:focus:after{outline:1px dotted #888}.fancybox-close-small:hover:after{color:#555;background:#eee}.fancybox-slide--iframe .fancybox-close-small,.fancybox-slide--image .fancybox-close-small{top:0;right:-40px}.fancybox-slide--iframe .fancybox-close-small:after,.fancybox-slide--image .fancybox-close-small:after{font-size:35px;color:#aaa}.fancybox-slide--iframe .fancybox-close-small:hover:after,.fancybox-slide--image .fancybox-close-small:hover:after{color:#fff;background:transparent}.fancybox-is-scaling .fancybox-close-small,.fancybox-is-zoomable.fancybox-can-drag .fancybox-close-small{display:none}.fancybox-caption-wrap{bottom:0;left:0;right:0;padding:60px 2vw 0;background:linear-gradient(180deg,transparent 0,rgba(0,0,0,.1) 20%,rgba(0,0,0,.2) 40%,rgba(0,0,0,.6) 80%,rgba(0,0,0,.8));pointer-events:none}.fancybox-caption{padding:30px 0;border-top:1px solid hsla(0,0%,100%,.4);font-size:14px;color:#fff;line-height:20px;-webkit-text-size-adjust:none}.fancybox-caption a,.fancybox-caption button,.fancybox-caption select{pointer-events:all;position:relative}.fancybox-caption a{color:#fff;text-decoration:underline}.fancybox-slide>.fancybox-loading{border:6px solid hsla(0,0%,39%,.4);border-top:6px solid hsla(0,0%,100%,.6);border-radius:100%;height:50px;width:50px;-webkit-animation:a .8s infinite linear;animation:a .8s infinite linear;background:transparent;position:absolute;top:50%;left:50%;margin-top:-30px;margin-left:-30px;z-index:99999}@-webkit-keyframes a{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes a{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fancybox-animated{transition-timing-function:cubic-bezier(0,0,.25,1)}.fancybox-fx-slide.fancybox-slide--previous{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);opacity:0}.fancybox-fx-slide.fancybox-slide--next{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);opacity:0}.fancybox-fx-slide.fancybox-slide--current{-webkit-transform:translateZ(0);transform:translateZ(0);opacity:1}.fancybox-fx-fade.fancybox-slide--next,.fancybox-fx-fade.fancybox-slide--previous{opacity:0;transition-timing-function:cubic-bezier(.19,1,.22,1)}.fancybox-fx-fade.fancybox-slide--current{opacity:1}.fancybox-fx-zoom-in-out.fancybox-slide--previous{-webkit-transform:scale3d(1.5,1.5,1.5);transform:scale3d(1.5,1.5,1.5);opacity:0}.fancybox-fx-zoom-in-out.fancybox-slide--next{-webkit-transform:scale3d(.5,.5,.5);transform:scale3d(.5,.5,.5);opacity:0}.fancybox-fx-zoom-in-out.fancybox-slide--current{-webkit-transform:scaleX(1);transform:scaleX(1);opacity:1}.fancybox-fx-rotate.fancybox-slide--previous{-webkit-transform:rotate(-1turn);transform:rotate(-1turn);opacity:0}.fancybox-fx-rotate.fancybox-slide--next{-webkit-transform:rotate(1turn);transform:rotate(1turn);opacity:0}.fancybox-fx-rotate.fancybox-slide--current{-webkit-transform:rotate(0deg);transform:rotate(0deg);opacity:1}.fancybox-fx-circular.fancybox-slide--previous{-webkit-transform:scale3d(0,0,0) translate3d(-100%,0,0);transform:scale3d(0,0,0) translate3d(-100%,0,0);opacity:0}.fancybox-fx-circular.fancybox-slide--next{-webkit-transform:scale3d(0,0,0) translate3d(100%,0,0);transform:scale3d(0,0,0) translate3d(100%,0,0);opacity:0}.fancybox-fx-circular.fancybox-slide--current{-webkit-transform:scaleX(1) translateZ(0);transform:scaleX(1) translateZ(0);opacity:1}.fancybox-fx-tube.fancybox-slide--previous{-webkit-transform:translate3d(-100%,0,0) scale(.1) skew(-10deg);transform:translate3d(-100%,0,0) scale(.1) skew(-10deg)}.fancybox-fx-tube.fancybox-slide--next{-webkit-transform:translate3d(100%,0,0) scale(.1) skew(10deg);transform:translate3d(100%,0,0) scale(.1) skew(10deg)}.fancybox-fx-tube.fancybox-slide--current{-webkit-transform:translateZ(0) scale(1);transform:translateZ(0) scale(1)}.fancybox-share{padding:30px;border-radius:3px;background:#f4f4f4;max-width:90%;text-align:center}.fancybox-share h1{color:#222;margin:0 0 20px;font-size:35px;font-weight:700}.fancybox-share p{margin:0;padding:0}p.fancybox-share__links{margin-right:-10px}.fancybox-share__button{display:inline-block;text-decoration:none;margin:0 10px 10px 0;padding:0 15px;min-width:130px;border:0;border-radius:3px;background:#fff;white-space:nowrap;font-size:14px;font-weight:700;line-height:40px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;color:#fff;transition:all .2s}.fancybox-share__button:hover{text-decoration:none}.fancybox-share__button--fb{background:#3b5998}.fancybox-share__button--fb:hover{background:#344e86}.fancybox-share__button--pt{background:#bd081d}.fancybox-share__button--pt:hover{background:#aa0719}.fancybox-share__button--tw{background:#1da1f2}.fancybox-share__button--tw:hover{background:#0d95e8}.fancybox-share__button svg{position:relative;top:-1px;width:25px;height:25px;margin-right:7px;vertical-align:middle}.fancybox-share__button svg path{fill:#fff}.fancybox-share__input{box-sizing:border-box;width:100%;margin:10px 0 0;padding:10px 15px;background:transparent;color:#5d5b5b;font-size:14px;outline:none;border:0;border-bottom:2px solid #d7d7d7}.fancybox-thumbs{display:none;position:absolute;top:0;bottom:0;right:0;width:212px;margin:0;padding:2px 2px 4px;background:#fff;-webkit-tap-highlight-color:transparent;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar;box-sizing:border-box;z-index:99995}.fancybox-thumbs-x{overflow-y:hidden;overflow-x:auto}.fancybox-show-thumbs .fancybox-thumbs{display:block}.fancybox-show-thumbs .fancybox-inner{right:212px}.fancybox-thumbs>ul{list-style:none;position:absolute;position:relative;width:100%;height:100%;margin:0;padding:0;overflow-x:hidden;overflow-y:auto;font-size:0;white-space:nowrap}.fancybox-thumbs-x>ul{overflow:hidden}.fancybox-thumbs-y>ul::-webkit-scrollbar{width:7px}.fancybox-thumbs-y>ul::-webkit-scrollbar-track{background:#fff;border-radius:10px;box-shadow:inset 0 0 6px rgba(0,0,0,.3)}.fancybox-thumbs-y>ul::-webkit-scrollbar-thumb{background:#2a2a2a;border-radius:10px}.fancybox-thumbs>ul>li{float:left;overflow:hidden;padding:0;margin:2px;width:100px;height:75px;max-width:calc(50% - 4px);max-height:calc(100% - 8px);position:relative;cursor:pointer;outline:none;-webkit-tap-highlight-color:transparent;-webkit-backface-visibility:hidden;backface-visibility:hidden;box-sizing:border-box}li.fancybox-thumbs-loading{background:rgba(0,0,0,.1)}.fancybox-thumbs>ul>li>img{position:absolute;top:0;left:0;max-width:none;max-height:none;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.fancybox-thumbs>ul>li:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;border:4px solid #4ea7f9;z-index:99991;opacity:0;transition:all .2s cubic-bezier(.25,.46,.45,.94)}.fancybox-thumbs>ul>li.fancybox-thumbs-active:before{opacity:1}@media (max-width:800px){.fancybox-thumbs{width:110px}.fancybox-show-thumbs .fancybox-inner{right:110px}.fancybox-thumbs>ul>li{max-width:calc(100% - 10px)}}
 
resources/css/jquery.steps.css DELETED
@@ -1,383 +0,0 @@
1
- /*
2
- Common
3
- */
4
-
5
- .wizard,
6
- .tabcontrol
7
- {
8
- display: block;
9
- width: 100%;
10
- overflow: hidden;
11
- }
12
-
13
- .wizard a,
14
- .tabcontrol a
15
- {
16
- outline: 0;
17
- }
18
-
19
- .wizard ul,
20
- .tabcontrol ul
21
- {
22
- list-style: none;
23
- padding: 0;
24
- margin: 0;
25
- }
26
-
27
- .wizard ul > li,
28
- .tabcontrol ul > li
29
- {
30
- display: block;
31
- padding: 0;
32
- }
33
-
34
- /* Accessibility */
35
- .wizard > .steps .current-info,
36
- .tabcontrol > .steps .current-info
37
- {
38
- position: absolute;
39
- left: -999em;
40
- }
41
-
42
- .wizard > .content > .title,
43
- .tabcontrol > .content > .title
44
- {
45
- position: absolute;
46
- left: -999em;
47
- }
48
-
49
-
50
-
51
- /*
52
- Wizard
53
- */
54
-
55
- .wizard > .steps
56
- {
57
- position: relative;
58
- display: block;
59
- width: 100%;
60
- }
61
-
62
- .wizard.vertical > .steps
63
- {
64
- display: inline;
65
- float: left;
66
- width: 30%;
67
- }
68
-
69
- .wizard > .steps .number
70
- {
71
- font-size: 1.429em;
72
- }
73
-
74
- .wizard > .steps > ul > li
75
- {
76
- width: 25%;
77
- }
78
-
79
- .wizard > .steps > ul > li,
80
- .wizard > .actions > ul > li
81
- {
82
- float: left;
83
- }
84
-
85
- .wizard.vertical > .steps > ul > li
86
- {
87
- float: none;
88
- width: 100%;
89
- }
90
-
91
- .wizard > .steps a,
92
- .wizard > .steps a:hover,
93
- .wizard > .steps a:active
94
- {
95
- display: block;
96
- width: auto;
97
- margin: 0 0.5em 0.5em;
98
- padding: 1em 1em;
99
- text-decoration: none;
100
-
101
- -webkit-border-radius: 5px;
102
- -moz-border-radius: 5px;
103
- border-radius: 5px;
104
- }
105
-
106
- .wizard > .steps .disabled a,
107
- .wizard > .steps .disabled a:hover,
108
- .wizard > .steps .disabled a:active
109
- {
110
- background: #eee;
111
- color: #aaa;
112
- cursor: default;
113
- }
114
-
115
- .wizard > .steps .current a,
116
- .wizard > .steps .current a:hover,
117
- .wizard > .steps .current a:active
118
- {
119
- background: rgba(69, 119, 0, 1);
120
- color: #fff;
121
- cursor: default;
122
- }
123
-
124
- .wizard > .steps .done a,
125
- .wizard > .steps .done a:hover,
126
- .wizard > .steps .done a:active
127
- {
128
- background: rgba(69, 119, 0, 0.5);
129
- color: #fff;
130
- }
131
-
132
- .wizard > .steps .error a,
133
- .wizard > .steps .error a:hover,
134
- .wizard > .steps .error a:active
135
- {
136
- background: #ff3111;
137
- color: #fff;
138
- }
139
-
140
- .wizard > .content
141
- {
142
- background: transparent;
143
- display: block;
144
- margin: 0.5em;
145
- min-height: 35em;
146
- overflow: hidden;
147
- position: relative;
148
- width: auto;
149
-
150
- -webkit-border-radius: 5px;
151
- -moz-border-radius: 5px;
152
- border-radius: 5px;
153
- border: 1px solid transparent;
154
- }
155
-
156
- .wizard.vertical > .content
157
- {
158
- display: inline;
159
- float: left;
160
- margin: 0 2.5% 0.5em 2.5%;
161
- width: 65%;
162
- }
163
-
164
- .wizard > .content > .body
165
- {
166
- float: left;
167
- position: absolute;
168
- width: 95%;
169
- height: 95%;
170
- padding: 2.5%;
171
- }
172
-
173
- .wizard > .content > .body ul
174
- {
175
- list-style: disc ;
176
- }
177
-
178
- .wizard > .content > .body ul > li
179
- {
180
- display: list-item;
181
- }
182
-
183
- .wizard > .content > .body > iframe
184
- {
185
- border: 0 none;
186
- width: 100%;
187
- height: 100%;
188
- }
189
-
190
- .wizard > .content > .body input
191
- {
192
- /*display: block;*/
193
- /*border: 1px solid #ccc;*/
194
- }
195
-
196
- .wizard > .content > .body input[type="checkbox"]
197
- {
198
- display: inline-block;
199
- }
200
-
201
- .wizard > .content > .body input.error
202
- {
203
- background: rgb(251, 227, 228);
204
- border: 1px solid #fbc2c4;
205
- color: #8a1f11;
206
- }
207
-
208
- .wizard > .content > .body label
209
- {
210
- /*display: inline-block;*/
211
- /*margin-bottom: 0.5em;*/
212
- }
213
-
214
- .wizard > .content > .body label.error
215
- {
216
- color: #8a1f11;
217
- display: inline-block;
218
- margin-left: 1.5em;
219
- }
220
-
221
- .wizard > .actions
222
- {
223
- position: relative;
224
- display: block;
225
- text-align: right;
226
- width: 100%;
227
- }
228
-
229
- .wizard.vertical > .actions
230
- {
231
- display: inline;
232
- float: right;
233
- margin: 0 2.5%;
234
- width: 95%;
235
- }
236
-
237
- .wizard > .actions > ul
238
- {
239
- display: inline-block;
240
- text-align: right;
241
- }
242
-
243
- .wizard > .actions > ul > li
244
- {
245
- margin: 0 0.5em;
246
- }
247
-
248
- .wizard.vertical > .actions > ul > li
249
- {
250
- margin: 0 0 0 1em;
251
- }
252
-
253
- .wizard > .actions a,
254
- .wizard > .actions a:hover,
255
- .wizard > .actions a:active
256
- {
257
- background: rgba(69, 119, 0, 1);
258
- color: #fff;
259
- display: block;
260
- padding: 0.5em 1em;
261
- text-decoration: none;
262
-
263
- -webkit-border-radius: 5px;
264
- -moz-border-radius: 5px;
265
- border-radius: 5px;
266
- }
267
-
268
- .wizard > .actions .disabled a,
269
- .wizard > .actions .disabled a:hover,
270
- .wizard > .actions .disabled a:active
271
- {
272
- background: #eee;
273
- color: #aaa;
274
- }
275
-
276
- .wizard > .loading
277
- {
278
- }
279
-
280
- .wizard > .loading .spinner
281
- {
282
- }
283
-
284
-
285
-
286
- /*
287
- Tabcontrol
288
- */
289
-
290
- .tabcontrol > .steps
291
- {
292
- position: relative;
293
- display: block;
294
- width: 100%;
295
- }
296
-
297
- .tabcontrol > .steps > ul
298
- {
299
- position: relative;
300
- margin: 6px 0 0 0;
301
- top: 1px;
302
- z-index: 1;
303
- }
304
-
305
- .tabcontrol > .steps > ul > li
306
- {
307
- float: left;
308
- margin: 5px 2px 0 0;
309
- padding: 1px;
310
-
311
- -webkit-border-top-left-radius: 5px;
312
- -webkit-border-top-right-radius: 5px;
313
- -moz-border-radius-topleft: 5px;
314
- -moz-border-radius-topright: 5px;
315
- border-top-left-radius: 5px;
316
- border-top-right-radius: 5px;
317
- }
318
-
319
- .tabcontrol > .steps > ul > li:hover
320
- {
321
- background: #edecec;
322
- border: 1px solid #bbb;
323
- padding: 0;
324
- }
325
-
326
- .tabcontrol > .steps > ul > li.current
327
- {
328
- background: #fff;
329
- border: 1px solid #bbb;
330
- border-bottom: 0 none;
331
- padding: 0 0 1px 0;
332
- margin-top: 0;
333
- }
334
-
335
- .tabcontrol > .steps > ul > li > a
336
- {
337
- color: #5f5f5f;
338
- display: inline-block;
339
- border: 0 none;
340
- margin: 0;
341
- padding: 10px 30px;
342
- text-decoration: none;
343
- }
344
-
345
- .tabcontrol > .steps > ul > li > a:hover
346
- {
347
- text-decoration: none;
348
- }
349
-
350
- .tabcontrol > .steps > ul > li.current > a
351
- {
352
- padding: 15px 30px 10px 30px;
353
- }
354
-
355
- .tabcontrol > .content
356
- {
357
- position: relative;
358
- display: inline-block;
359
- width: 100%;
360
- height: 35em;
361
- overflow: hidden;
362
- border-top: 1px solid #bbb;
363
- padding-top: 20px;
364
- }
365
-
366
- .tabcontrol > .content > .body
367
- {
368
- float: left;
369
- position: absolute;
370
- width: 95%;
371
- height: 95%;
372
- padding: 2.5%;
373
- }
374
-
375
- .tabcontrol > .content > .body ul
376
- {
377
- list-style: disc !important;
378
- }
379
-
380
- .tabcontrol > .content > .body ul > li
381
- {
382
- display: list-item;
383
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
resources/css/jquery/fancybox.min.css ADDED
@@ -0,0 +1 @@
 
1
+ body.compensate-for-scrollbar{overflow:hidden}.fancybox-active{height:auto}.fancybox-is-hidden{left:-9999px;margin:0;position:absolute!important;top:-9999px;visibility:hidden}.fancybox-container{-webkit-backface-visibility:hidden;height:100%;left:0;outline:none;position:fixed;-webkit-tap-highlight-color:transparent;top:0;-ms-touch-action:manipulation;touch-action:manipulation;transform:translateZ(0);width:100%;z-index:99992}.fancybox-container *{box-sizing:border-box}.fancybox-bg,.fancybox-inner,.fancybox-outer,.fancybox-stage{bottom:0;left:0;position:absolute;right:0;top:0}.fancybox-outer{-webkit-overflow-scrolling:touch;overflow-y:auto}.fancybox-bg{background:#1e1e1e;opacity:0;transition-duration:inherit;transition-property:opacity;transition-timing-function:cubic-bezier(.47,0,.74,.71)}.fancybox-is-open .fancybox-bg{opacity:.9;transition-timing-function:cubic-bezier(.22,.61,.36,1)}.fancybox-caption,.fancybox-infobar,.fancybox-navigation .fancybox-button,.fancybox-toolbar{direction:ltr;opacity:0;position:absolute;transition:opacity .25s ease,visibility 0s ease .25s;visibility:hidden;z-index:99997}.fancybox-show-caption .fancybox-caption,.fancybox-show-infobar .fancybox-infobar,.fancybox-show-nav .fancybox-navigation .fancybox-button,.fancybox-show-toolbar .fancybox-toolbar{opacity:1;transition:opacity .25s ease 0s,visibility 0s ease 0s;visibility:visible}.fancybox-infobar{color:#ccc;font-size:13px;-webkit-font-smoothing:subpixel-antialiased;height:44px;left:0;line-height:44px;min-width:44px;mix-blend-mode:difference;padding:0 10px;pointer-events:none;top:0;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.fancybox-toolbar{right:0;top:0}.fancybox-stage{direction:ltr;overflow:visible;transform:translateZ(0);z-index:99994}.fancybox-is-open .fancybox-stage{overflow:hidden}.fancybox-slide{-webkit-backface-visibility:hidden;display:none;height:100%;left:0;outline:none;overflow:auto;-webkit-overflow-scrolling:touch;padding:44px;position:absolute;text-align:center;top:0;transition-property:transform,opacity;white-space:normal;width:100%;z-index:99994}.fancybox-slide:before{content:"";display:inline-block;font-size:0;height:100%;vertical-align:middle;width:0}.fancybox-is-sliding .fancybox-slide,.fancybox-slide--current,.fancybox-slide--next,.fancybox-slide--previous{display:block}.fancybox-slide--image{overflow:hidden;padding:44px 0}.fancybox-slide--image:before{display:none}.fancybox-slide--html{padding:6px}.fancybox-content{background:#fff;display:inline-block;margin:0;max-width:100%;overflow:auto;-webkit-overflow-scrolling:touch;padding:44px;position:relative;text-align:left;vertical-align:middle}.fancybox-slide--image .fancybox-content{animation-timing-function:cubic-bezier(.5,0,.14,1);-webkit-backface-visibility:hidden;background:transparent;background-repeat:no-repeat;background-size:100% 100%;left:0;max-width:none;overflow:visible;padding:0;position:absolute;top:0;transform-origin:top left;transition-property:transform,opacity;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:99995}.fancybox-can-zoomOut .fancybox-content{cursor:zoom-out}.fancybox-can-zoomIn .fancybox-content{cursor:zoom-in}.fancybox-can-pan .fancybox-content,.fancybox-can-swipe .fancybox-content{cursor:grab}.fancybox-is-grabbing .fancybox-content{cursor:grabbing}.fancybox-container [data-selectable=true]{cursor:text}.fancybox-image,.fancybox-spaceball{background:transparent;border:0;height:100%;left:0;margin:0;max-height:none;max-width:none;padding:0;position:absolute;top:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:100%}.fancybox-spaceball{z-index:1}.fancybox-slide--iframe .fancybox-content,.fancybox-slide--map .fancybox-content,.fancybox-slide--pdf .fancybox-content,.fancybox-slide--video .fancybox-content{height:100%;overflow:visible;padding:0;width:100%}.fancybox-slide--video .fancybox-content{background:#000}.fancybox-slide--map .fancybox-content{background:#e5e3df}.fancybox-slide--iframe .fancybox-content{background:#fff}.fancybox-iframe,.fancybox-video{background:transparent;border:0;display:block;height:100%;margin:0;overflow:hidden;padding:0;width:100%}.fancybox-iframe{left:0;position:absolute;top:0}.fancybox-error{background:#fff;cursor:default;max-width:400px;padding:40px;width:100%}.fancybox-error p{color:#444;font-size:16px;line-height:20px;margin:0;padding:0}.fancybox-button{background:rgba(30,30,30,.6);border:0;border-radius:0;box-shadow:none;cursor:pointer;display:inline-block;height:44px;margin:0;padding:10px;position:relative;transition:color .2s;vertical-align:top;visibility:inherit;width:44px}.fancybox-button,.fancybox-button:link,.fancybox-button:visited{color:#ccc}.fancybox-button:hover{color:#fff}.fancybox-button:focus{outline:none}.fancybox-button.fancybox-focus{outline:1px dotted}.fancybox-button[disabled],.fancybox-button[disabled]:hover{color:#888;cursor:default;outline:none}.fancybox-button div{height:100%}.fancybox-button svg{display:block;height:100%;overflow:visible;position:relative;width:100%}.fancybox-button svg path{fill:currentColor;stroke-width:0}.fancybox-button--fsenter svg:nth-child(2),.fancybox-button--fsexit svg:first-child,.fancybox-button--pause svg:first-child,.fancybox-button--play svg:nth-child(2){display:none}.fancybox-progress{background:#ff5268;height:2px;left:0;position:absolute;right:0;top:0;transform:scaleX(0);transform-origin:0;transition-property:transform;transition-timing-function:linear;z-index:99998}.fancybox-close-small{background:transparent;border:0;border-radius:0;color:#ccc;cursor:pointer;opacity:.8;padding:8px;position:absolute;right:-12px;top:-44px;z-index:401}.fancybox-close-small:hover{color:#fff;opacity:1}.fancybox-slide--html .fancybox-close-small{color:currentColor;padding:10px;right:0;top:0}.fancybox-slide--image.fancybox-is-scaling .fancybox-content{overflow:hidden}.fancybox-is-scaling .fancybox-close-small,.fancybox-is-zoomable.fancybox-can-pan .fancybox-close-small{display:none}.fancybox-navigation .fancybox-button{background-clip:content-box;height:100px;opacity:0;position:absolute;top:calc(50% - 50px);width:70px}.fancybox-navigation .fancybox-button div{padding:7px}.fancybox-navigation .fancybox-button--arrow_left{left:0;left:env(safe-area-inset-left);padding:31px 26px 31px 6px}.fancybox-navigation .fancybox-button--arrow_right{padding:31px 6px 31px 26px;right:0;right:env(safe-area-inset-right)}.fancybox-caption{background:linear-gradient(0deg,rgba(0,0,0,.85) 0,rgba(0,0,0,.3) 50%,rgba(0,0,0,.15) 65%,rgba(0,0,0,.075) 75.5%,rgba(0,0,0,.037) 82.85%,rgba(0,0,0,.019) 88%,transparent);bottom:0;color:#eee;font-size:14px;font-weight:400;left:0;line-height:1.5;padding:75px 44px 25px;pointer-events:none;right:0;text-align:center;z-index:99996}@supports (padding:max(0px)){.fancybox-caption{padding:75px max(44px,env(safe-area-inset-right)) max(25px,env(safe-area-inset-bottom)) max(44px,env(safe-area-inset-left))}}.fancybox-caption--separate{margin-top:-50px}.fancybox-caption__body{max-height:50vh;overflow:auto;pointer-events:all}.fancybox-caption a,.fancybox-caption a:link,.fancybox-caption a:visited{color:#ccc;text-decoration:none}.fancybox-caption a:hover{color:#fff;text-decoration:underline}.fancybox-loading{animation:a 1s linear infinite;background:transparent;border:4px solid #888;border-bottom-color:#fff;border-radius:50%;height:50px;left:50%;margin:-25px 0 0 -25px;opacity:.7;padding:0;position:absolute;top:50%;width:50px;z-index:99999}@keyframes a{to{transform:rotate(1turn)}}.fancybox-animated{transition-timing-function:cubic-bezier(0,0,.25,1)}.fancybox-fx-slide.fancybox-slide--previous{opacity:0;transform:translate3d(-100%,0,0)}.fancybox-fx-slide.fancybox-slide--next{opacity:0;transform:translate3d(100%,0,0)}.fancybox-fx-slide.fancybox-slide--current{opacity:1;transform:translateZ(0)}.fancybox-fx-fade.fancybox-slide--next,.fancybox-fx-fade.fancybox-slide--previous{opacity:0;transition-timing-function:cubic-bezier(.19,1,.22,1)}.fancybox-fx-fade.fancybox-slide--current{opacity:1}.fancybox-fx-zoom-in-out.fancybox-slide--previous{opacity:0;transform:scale3d(1.5,1.5,1.5)}.fancybox-fx-zoom-in-out.fancybox-slide--next{opacity:0;transform:scale3d(.5,.5,.5)}.fancybox-fx-zoom-in-out.fancybox-slide--current{opacity:1;transform:scaleX(1)}.fancybox-fx-rotate.fancybox-slide--previous{opacity:0;transform:rotate(-1turn)}.fancybox-fx-rotate.fancybox-slide--next{opacity:0;transform:rotate(1turn)}.fancybox-fx-rotate.fancybox-slide--current{opacity:1;transform:rotate(0deg)}.fancybox-fx-circular.fancybox-slide--previous{opacity:0;transform:scale3d(0,0,0) translate3d(-100%,0,0)}.fancybox-fx-circular.fancybox-slide--next{opacity:0;transform:scale3d(0,0,0) translate3d(100%,0,0)}.fancybox-fx-circular.fancybox-slide--current{opacity:1;transform:scaleX(1) translateZ(0)}.fancybox-fx-tube.fancybox-slide--previous{transform:translate3d(-100%,0,0) scale(.1) skew(-10deg)}.fancybox-fx-tube.fancybox-slide--next{transform:translate3d(100%,0,0) scale(.1) skew(10deg)}.fancybox-fx-tube.fancybox-slide--current{transform:translateZ(0) scale(1)}@media (max-height:576px){.fancybox-slide{padding-left:6px;padding-right:6px}.fancybox-slide--image{padding:6px 0}.fancybox-close-small{right:-6px}.fancybox-slide--image .fancybox-close-small{background:#4e4e4e;color:#f2f4f6;height:36px;opacity:1;padding:6px;right:0;top:0;width:36px}.fancybox-caption{padding-left:12px;padding-right:12px}@supports (padding:max(0px)){.fancybox-caption{padding-left:max(12px,env(safe-area-inset-left));padding-right:max(12px,env(safe-area-inset-right))}}}.fancybox-share{background:#f4f4f4;border-radius:3px;max-width:90%;padding:30px;text-align:center}.fancybox-share h1{color:#222;font-size:35px;font-weight:700;margin:0 0 20px}.fancybox-share p{margin:0;padding:0}.fancybox-share__button{border:0;border-radius:3px;display:inline-block;font-size:14px;font-weight:700;line-height:40px;margin:0 5px 10px;min-width:130px;padding:0 15px;text-decoration:none;transition:all .2s;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;white-space:nowrap}.fancybox-share__button:link,.fancybox-share__button:visited{color:#fff}.fancybox-share__button:hover{text-decoration:none}.fancybox-share__button--fb{background:#3b5998}.fancybox-share__button--fb:hover{background:#344e86}.fancybox-share__button--pt{background:#bd081d}.fancybox-share__button--pt:hover{background:#aa0719}.fancybox-share__button--tw{background:#1da1f2}.fancybox-share__button--tw:hover{background:#0d95e8}.fancybox-share__button svg{height:25px;margin-right:7px;position:relative;top:-1px;vertical-align:middle;width:25px}.fancybox-share__button svg path{fill:#fff}.fancybox-share__input{background:transparent;border:0;border-bottom:1px solid #d7d7d7;border-radius:0;color:#5d5b5b;font-size:14px;margin:10px 0 0;outline:none;padding:10px 15px;width:100%}.fancybox-thumbs{background:#ddd;bottom:0;display:none;margin:0;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar;padding:2px 2px 4px;position:absolute;right:0;-webkit-tap-highlight-color:rgba(0,0,0,0);top:0;width:212px;z-index:99995}.fancybox-thumbs-x{overflow-x:auto;overflow-y:hidden}.fancybox-show-thumbs .fancybox-thumbs{display:block}.fancybox-show-thumbs .fancybox-inner{right:212px}.fancybox-thumbs__list{font-size:0;height:100%;list-style:none;margin:0;overflow-x:hidden;overflow-y:auto;padding:0;position:absolute;position:relative;white-space:nowrap;width:100%}.fancybox-thumbs-x .fancybox-thumbs__list{overflow:hidden}.fancybox-thumbs-y .fancybox-thumbs__list::-webkit-scrollbar{width:7px}.fancybox-thumbs-y .fancybox-thumbs__list::-webkit-scrollbar-track{background:#fff;border-radius:10px;box-shadow:inset 0 0 6px rgba(0,0,0,.3)}.fancybox-thumbs-y .fancybox-thumbs__list::-webkit-scrollbar-thumb{background:#2a2a2a;border-radius:10px}.fancybox-thumbs__list a{-webkit-backface-visibility:hidden;backface-visibility:hidden;background-color:rgba(0,0,0,.1);background-position:50%;background-repeat:no-repeat;background-size:cover;cursor:pointer;float:left;height:75px;margin:2px;max-height:calc(100% - 8px);max-width:calc(50% - 4px);outline:none;overflow:hidden;padding:0;position:relative;-webkit-tap-highlight-color:transparent;width:100px}.fancybox-thumbs__list a:before{border:6px solid #ff5268;bottom:0;content:"";left:0;opacity:0;position:absolute;right:0;top:0;transition:all .2s cubic-bezier(.25,.46,.45,.94);z-index:99991}.fancybox-thumbs__list a:focus:before{opacity:.5}.fancybox-thumbs__list a.fancybox-thumbs-active:before{opacity:1}@media (max-width:576px){.fancybox-thumbs{width:110px}.fancybox-show-thumbs .fancybox-inner{right:110px}.fancybox-thumbs__list a{max-width:calc(100% - 10px)}}
resources/css/plugin.css CHANGED
@@ -1558,10 +1558,14 @@ body.folded #FooterBannerGoPro {
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
  }
@@ -1571,7 +1575,6 @@ body.folded #FooterBannerGoPro {
1571
  #SearchDialog .bootstrap-select > .dropdown-toggle.bs-placeholder {
1572
  color: #333333;
1573
  }
1574
-
1575
  #StatsNav {
1576
  background-color: #f1f1f1;
1577
  display: inline-block;
@@ -1588,4 +1591,57 @@ body.folded #FooterBannerGoPro {
1588
  .stat_box .stat_count {
1589
  font-size: 3rem;
1590
  line-height: 3.5rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1591
  }
1558
  }
1559
  #NavSideBar a.nav-link.active {
1560
  font-weight: bolder;
1561
+ font-size: 1rem;
1562
  }
1563
  .primary_sub_menu {
1564
  }
1565
+ .primary_sub_menu a.active {
1566
+ border-left: 3px solid rgba(0, 128, 0, 0.4);
1567
+ padding-left: 6px !important;
1568
+ }
1569
  #SearchDialog .modal-body {
1570
  min-height: 450px;
1571
  }
1575
  #SearchDialog .bootstrap-select > .dropdown-toggle.bs-placeholder {
1576
  color: #333333;
1577
  }
 
1578
  #StatsNav {
1579
  background-color: #f1f1f1;
1580
  display: inline-block;
1591
  .stat_box .stat_count {
1592
  font-size: 3rem;
1593
  line-height: 3.5rem;
1594
+ }
1595
+ #odp-PageContainer .summary-card.card {
1596
+ border-color: transparent;
1597
+ }
1598
+ .summary-card.card,
1599
+ .summary-card .card-body {
1600
+ background-color: transparent;
1601
+ }
1602
+ .summary-card .card-body {
1603
+ padding: 0.1rem;
1604
+ }
1605
+ .summary-card .card-footer {
1606
+ border: 1px solid transparent;
1607
+ background-color: transparent;
1608
+ }
1609
+ .summary-card .card-footer h6 {
1610
+ font-size: 0.8rem;
1611
+ margin: 0;
1612
+ text-align: center;
1613
+ }
1614
+ .summary-card.enabled .icon,
1615
+ .summary-card.enabled .card-footer a {
1616
+ color: #008000;
1617
+ }
1618
+ .summary-card.disabled .icon,
1619
+ .summary-card.disabled .card-footer a {
1620
+ color: #c23e0c;
1621
+ }
1622
+ .summary-card a[target="_blank"]::after {
1623
+ content: '' !important;
1624
+ margin: 0 !important;
1625
+ }
1626
+ .summary-card .icon > svg {
1627
+ width: 64px;
1628
+ height: 64px;
1629
+ padding: 12px;
1630
+ border: 1px solid #008000;
1631
+ border-radius: 32px;
1632
+ /* Permalink - use to edit and share this gradient: https://colorzilla.com/gradient-editor/#f8ffe8+0,e3f5ab+33,b7df2d+100;Green+3D+%234 */
1633
+ background: #f8ffe8; /* Old browsers */
1634
+ background: -moz-linear-gradient(top, #f8ffe8 0%, #e3f5ab 33%, #b7df2d 100%); /* FF3.6-15 */
1635
+ background: -webkit-linear-gradient(top, #f8ffe8 0%, #e3f5ab 33%, #b7df2d 100%); /* Chrome10-25,Safari5.1-6 */
1636
+ background: linear-gradient(to bottom, #f8ffe8 0%, #e3f5ab 33%, #b7df2d 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
1637
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f8ffe8', endColorstr='#b7df2d', GradientType=0); /* IE6-9 */
1638
+ }
1639
+ .summary-card.disabled .icon > svg {
1640
+ border-color: #c23e0c;
1641
+ /* Permalink - use to edit and share this gradient: https://colorzilla.com/gradient-editor/#ffeded+0,fcd6d6+12,f9acac+88 */
1642
+ background: #ffeded; /* Old browsers */
1643
+ background: -moz-linear-gradient(top, #ffeded 0%, #fcd6d6 12%, #f9acac 88%); /* FF3.6-15 */
1644
+ background: -webkit-linear-gradient(top, #ffeded 0%, #fcd6d6 12%, #f9acac 88%); /* Chrome10-25,Safari5.1-6 */
1645
+ background: linear-gradient(to bottom, #ffeded 0%, #fcd6d6 12%, #f9acac 88%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
1646
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffeded', endColorstr='#f9acac', GradientType=0); /* IE6-9 */
1647
  }
resources/css/shield/dialog.css ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ .shield_dialog {
2
+ color: black;
3
+ }
4
+ .shield_dialog .dialog-content,
5
+ .shield_dialog .ui-dialog-title {
6
+ color: black;
7
+ }
resources/css/{pages.css → shield/pages.css} RENAMED
File without changes
resources/css/shield/wizard.css ADDED
@@ -0,0 +1,542 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ html {
2
+ overflow-y: scroll;
3
+ }
4
+ body {
5
+ padding-bottom: 200px;
6
+ overflow-y: visible;
7
+ }
8
+ body.wait {
9
+ cursor: wait !important;
10
+ }
11
+ .wizard > .content {
12
+ background: #ffffff;
13
+ box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.2);
14
+ }
15
+ .wizard > .steps .current a {
16
+ text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.1);
17
+ }
18
+ .wizard.vertical > .steps {
19
+ width: 20%; /** from 30 **/
20
+ }
21
+ /*
22
+ Common
23
+ */
24
+ .wizard,
25
+ .tabcontrol {
26
+ display: block;
27
+ width: 100%;
28
+ overflow: hidden;
29
+ }
30
+ .wizard a,
31
+ .tabcontrol a {
32
+ outline: 0;
33
+ }
34
+ .wizard ul,
35
+ .tabcontrol ul {
36
+ list-style: none;
37
+ padding: 0;
38
+ margin: 0;
39
+ }
40
+ .wizard ul > li,
41
+ .tabcontrol ul > li {
42
+ display: block;
43
+ padding: 0;
44
+ }
45
+ /* Accessibility */
46
+ .wizard > .steps .current-info,
47
+ .tabcontrol > .steps .current-info {
48
+ position: absolute;
49
+ left: -999em;
50
+ }
51
+ .wizard > .content > .title,
52
+ .tabcontrol > .content > .title {
53
+ position: absolute;
54
+ left: -999em;
55
+ }
56
+ /*
57
+ Wizard
58
+ */
59
+ .wizard > .steps {
60
+ position: relative;
61
+ display: block;
62
+ width: 100%;
63
+ }
64
+ .wizard.vertical > .steps {
65
+ display: inline;
66
+ float: left;
67
+ width: 30%;
68
+ }
69
+ .wizard > .steps .number {
70
+ font-size: 1.429em;
71
+ }
72
+ .wizard > .steps > ul > li {
73
+ width: 25%;
74
+ }
75
+ .wizard > .steps > ul > li,
76
+ .wizard > .actions > ul > li {
77
+ float: left;
78
+ }
79
+ .wizard.vertical > .steps > ul > li {
80
+ float: none;
81
+ width: 100%;
82
+ }
83
+ .wizard > .steps a,
84
+ .wizard > .steps a:hover,
85
+ .wizard > .steps a:active {
86
+ display: block;
87
+ width: auto;
88
+ margin: 0 0.5em 0.5em;
89
+ padding: 1em 1em;
90
+ text-decoration: none;
91
+ -webkit-border-radius: 5px;
92
+ -moz-border-radius: 5px;
93
+ border-radius: 5px;
94
+ }
95
+ .wizard > .steps .disabled a,
96
+ .wizard > .steps .disabled a:hover,
97
+ .wizard > .steps .disabled a:active {
98
+ background: #eeeeee;
99
+ color: #aaaaaa;
100
+ cursor: default;
101
+ }
102
+ .wizard > .steps .current a,
103
+ .wizard > .steps .current a:hover,
104
+ .wizard > .steps .current a:active {
105
+ background: rgba(69, 119, 0, 1);
106
+ color: #ffffff;
107
+ cursor: default;
108
+ }
109
+ .wizard > .steps .done a,
110
+ .wizard > .steps .done a:hover,
111
+ .wizard > .steps .done a:active {
112
+ background: rgba(69, 119, 0, 0.5);
113
+ color: #ffffff;
114
+ }
115
+ .wizard > .steps .error a,
116
+ .wizard > .steps .error a:hover,
117
+ .wizard > .steps .error a:active {
118
+ background: #ff3111;
119
+ color: #ffffff;
120
+ }
121
+ .wizard > .content {
122
+ background: transparent;
123
+ display: block;
124
+ margin: 0.5em;
125
+ min-height: 35em;
126
+ overflow: hidden;
127
+ position: relative;
128
+ width: auto;
129
+ -webkit-border-radius: 5px;
130
+ -moz-border-radius: 5px;
131
+ border-radius: 5px;
132
+ border: 1px solid transparent;
133
+ }
134
+ .wizard.vertical > .content {
135
+ display: inline;
136
+ float: left;
137
+ margin: 0 2.5% 0.5em 2.5%;
138
+ width: 65%;
139
+ }
140
+ .wizard > .content > .body {
141
+ float: left;
142
+ position: absolute;
143
+ width: 95%;
144
+ height: 95%;
145
+ padding: 2.5%;
146
+ }
147
+ .wizard > .content > .body ul {
148
+ list-style: disc;
149
+ }
150
+ .wizard > .content > .body ul > li {
151
+ display: list-item;
152
+ }
153
+ .wizard > .content > .body > iframe {
154
+ border: 0 none;
155
+ width: 100%;
156
+ height: 100%;
157
+ }
158
+ .wizard > .content > .body input {
159
+ /*display: block;*/
160
+ /*border: 1px solid #ccc;*/
161
+ }
162
+ .wizard > .content > .body input[type="checkbox"] {
163
+ display: inline-block;
164
+ }
165
+ .wizard > .content > .body input.error {
166
+ background: rgb(251, 227, 228);
167
+ border: 1px solid #fbc2c4;
168
+ color: #8a1f11;
169
+ }
170
+ .wizard > .content > .body label {
171
+ /*display: inline-block;*/
172
+ /*margin-bottom: 0.5em;*/
173
+ }
174
+ .wizard > .content > .body label.error {
175
+ color: #8a1f11;
176
+ display: inline-block;
177
+ margin-left: 1.5em;
178
+ }
179
+ .wizard > .actions {
180
+ position: relative;
181
+ display: block;
182
+ text-align: right;
183
+ width: 100%;
184
+ }
185
+ .wizard.vertical > .actions {
186
+ display: inline;
187
+ float: right;
188
+ margin: 0 2.5%;
189
+ width: 95%;
190
+ }
191
+ .wizard > .actions > ul {
192
+ display: inline-block;
193
+ text-align: right;
194
+ }
195
+ .wizard > .actions > ul > li {
196
+ margin: 0 0.5em;
197
+ }
198
+ .wizard.vertical > .actions > ul > li {
199
+ margin: 0 0 0 1em;
200
+ }
201
+ .wizard > .actions a,
202
+ .wizard > .actions a:hover,
203
+ .wizard > .actions a:active {
204
+ background: rgba(69, 119, 0, 1);
205
+ color: #ffffff;
206
+ display: block;
207
+ padding: 0.5em 1em;
208
+ text-decoration: none;
209
+ -webkit-border-radius: 5px;
210
+ -moz-border-radius: 5px;
211
+ border-radius: 5px;
212
+ }
213
+ .wizard > .actions .disabled a,
214
+ .wizard > .actions .disabled a:hover,
215
+ .wizard > .actions .disabled a:active {
216
+ background: #eeeeee;
217
+ color: #aaaaaa;
218
+ }
219
+ .wizard > .loading {
220
+ }
221
+ .wizard > .loading .spinner {
222
+ }
223
+ /*
224
+ Tabcontrol
225
+ */
226
+ .tabcontrol > .steps {
227
+ position: relative;
228
+ display: block;
229
+ width: 100%;
230
+ }
231
+ .tabcontrol > .steps > ul {
232
+ position: relative;
233
+ margin: 6px 0 0 0;
234
+ top: 1px;
235
+ z-index: 1;
236
+ }
237
+ .tabcontrol > .steps > ul > li {
238
+ float: left;
239
+ margin: 5px 2px 0 0;
240
+ padding: 1px;
241
+ -webkit-border-top-left-radius: 5px;
242
+ -webkit-border-top-right-radius: 5px;
243
+ -moz-border-radius-topleft: 5px;
244
+ -moz-border-radius-topright: 5px;
245
+ border-top-left-radius: 5px;
246
+ border-top-right-radius: 5px;
247
+ }
248
+ .tabcontrol > .steps > ul > li:hover {
249
+ background: #edecec;
250
+ border: 1px solid #bbbbbb;
251
+ padding: 0;
252
+ }
253
+ .tabcontrol > .steps > ul > li.current {
254
+ background: #ffffff;
255
+ border: 1px solid #bbbbbb;
256
+ border-bottom: 0 none;
257
+ padding: 0 0 1px 0;
258
+ margin-top: 0;
259
+ }
260
+ .tabcontrol > .steps > ul > li > a {
261
+ color: #5f5f5f;
262
+ display: inline-block;
263
+ border: 0 none;
264
+ margin: 0;
265
+ padding: 10px 30px;
266
+ text-decoration: none;
267
+ }
268
+ .tabcontrol > .steps > ul > li > a:hover {
269
+ text-decoration: none;
270
+ }
271
+ .tabcontrol > .steps > ul > li.current > a {
272
+ padding: 15px 30px 10px 30px;
273
+ }
274
+ .tabcontrol > .content {
275
+ position: relative;
276
+ display: inline-block;
277
+ width: 100%;
278
+ height: 35em;
279
+ overflow: hidden;
280
+ border-top: 1px solid #bbbbbb;
281
+ padding-top: 20px;
282
+ }
283
+ .tabcontrol > .content > .body {
284
+ float: left;
285
+ position: absolute;
286
+ width: 95%;
287
+ height: 95%;
288
+ padding: 2.5%;
289
+ }
290
+ .tabcontrol > .content > .body ul {
291
+ list-style: disc !important;
292
+ }
293
+ .tabcontrol > .content > .body ul > li {
294
+ display: list-item;
295
+ }
296
+ .wizard.vertical > .content {
297
+ width: 75%; /** from 65 **/
298
+ }
299
+ .wizard > .content > .body {
300
+ height: auto;
301
+ position: relative;
302
+ padding: 0;
303
+ width: 100%
304
+ }
305
+ .wizard > .content > .body .slide-header {
306
+ padding: 3% 3% 0 3%;
307
+ }
308
+ .wizard > .content > .body .slide-header .btn-block {
309
+ margin-bottom: -1px;
310
+ }
311
+ .wizard > .content > .body .slide-header hr {
312
+ margin: 15px 0;
313
+ }
314
+ .wizard > .content > .body .slide-body {
315
+ padding: 0 6% 0 6%;
316
+ }
317
+ .wizard > .content > .body .slide-footer {
318
+ padding: 0 6% 3% 6%;
319
+ }
320
+ .wizard.vertical > .actions {
321
+ margin-bottom: 20px;
322
+ }
323
+ .wizard h3 {
324
+ margin-bottom: 20px;
325
+ }
326
+ .wizard h4 {
327
+ font-size: 2rem;
328
+ margin: 2rem 0;
329
+ }
330
+ .wizard li,
331
+ .wizard p {
332
+ font-size: 16px;
333
+ margin-bottom: 1.2rem;
334
+ }
335
+ .wizard .body ol,
336
+ .wizard .body ul {
337
+ margin-bottom: 20px;
338
+ padding-left: 20px;
339
+ }
340
+ .wizard .body ul {
341
+ list-style: square inside none;
342
+ }
343
+ .wizard p.wizard-response {
344
+ /*padding: 10px 15px;*/
345
+ }
346
+ .wizard .slide-body img {
347
+ }
348
+ .wizard .slide-body .media {
349
+ margin-top: 25px
350
+ }
351
+ .wizard .slide-body .media-object {
352
+ border: 1px solid #888888;
353
+ height: 64px;
354
+ width: 64px;
355
+ }
356
+ .wizard .indent_slight {
357
+ margin-left: 26px;
358
+ }
359
+ .wizard_slot {
360
+ border: 1px solid #dddddd;
361
+ border-radius: 3px;
362
+ margin-top: 30px;
363
+ padding: 0 20px 20px;
364
+ }
365
+ .wizard_slot:hover {
366
+ background-color: #ffffff;
367
+ }
368
+ .wizard form label {
369
+ }
370
+ .wizard form input[type="radio"]:checked + span {
371
+ font-weight: bolder;
372
+ letter-spacing: -0.4px;
373
+ }
374
+ .wizard form .form-check-label {
375
+ margin-bottom: 10px;
376
+ }
377
+ .wizard form .form-check-inline .form-check-label {
378
+ margin-bottom: 0;
379
+ }
380
+ .shield-go-pro {
381
+ min-width: 200px;
382
+ display: block;
383
+ margin: 5px auto 20px;
384
+ background-color: #1e7e34;
385
+ border-color: #1c7430;
386
+ }
387
+ #GoProBtn {
388
+ width: 128px;
389
+ display: block;
390
+ margin: 5px auto 20px;
391
+ }
392
+ #FooterWizardBanner {
393
+ position: fixed;
394
+ bottom: -50px;
395
+ height: 100px;
396
+ width: 100%;
397
+ }
398
+ #WizardTop {
399
+ height: 40px;
400
+ background-color: #fafafa;
401
+ background: linear-gradient(to top, rgba(250, 250, 250, 0.95), rgba(250, 250, 250, 0.7));
402
+ }
403
+ #WizardBanner {
404
+ height: 100px;
405
+ background-color: #eaffea;
406
+ border-top: 1px solid #bbbbbb;
407
+ padding-top: 10px;
408
+ text-align: center;
409
+ word-break: keep-all;
410
+ white-space: nowrap;
411
+ }
412
+ #WizardBanner p {
413
+ margin: 0;
414
+ line-height: 20px;
415
+ text-align: left;
416
+ }
417
+ #MoreDetails {
418
+ margin-top: 12px;
419
+ }
420
+ .more_details {
421
+ margin-bottom: 12px;
422
+ }
423
+ .more_details:hover {
424
+ cursor: pointer;
425
+ }
426
+ .more_details_body {
427
+ margin-bottom: 12px;
428
+ }
429
+ .scan-results-accordian {
430
+ }
431
+ .scan-results-accordian .card {
432
+ margin-bottom: 24px;
433
+ }
434
+ .scan-results-accordian .card-header {
435
+ padding: .5rem 1.25rem;
436
+ }
437
+ .scan-results-accordian .card-header button:hover,
438
+ .scan-results-accordian .card-header button {
439
+ color: #f1f1f1
440
+ }
441
+ .embed-vimeo {
442
+ margin-bottom: 20px;
443
+ border-radius: 3px;
444
+ box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.3);
445
+ }
446
+ span.shield-progress-bar {
447
+ position: relative;
448
+ top: 8px;
449
+ width: 130%;
450
+ background-color: #2271b1;
451
+ height: 2px;
452
+ left: 75%;
453
+ }
454
+ /* override jquery.steps.css */
455
+ .wizard > .actions a,
456
+ .wizard > .actions a:hover,
457
+ .wizard > .actions a:active,
458
+ .wizard > .steps .current a,
459
+ .wizard > .steps .current a:hover,
460
+ .wizard > .steps .current a:active,
461
+ .wizard > .steps .disabled a, .wizard > .steps .disabled a:hover, .wizard > .steps .disabled a:active,
462
+ .wizard > .steps .done a, .wizard > .steps .done a:hover, .wizard > .steps .done a:active {
463
+ background: none !important;
464
+ }
465
+ .wizard > .steps > ul > li {
466
+ }
467
+ div.steps ul {
468
+ display: flex;
469
+ flex-direction: row;
470
+ flex-wrap: nowrap;
471
+ justify-content: space-evenly;
472
+ }
473
+ div.step {
474
+ display: flex;
475
+ align-content: center;
476
+ justify-content: space-between;
477
+ flex-direction: column;
478
+ flex-wrap: nowrap;
479
+ align-items: center;
480
+ }
481
+ div.step-number {
482
+ width: 15px;
483
+ height: 15px;
484
+ border-radius: 100%;
485
+ }
486
+ li div.step-number {
487
+ background-color: rgba(34, 113, 177, 1);
488
+ z-index: 5;
489
+ }
490
+ li div.step-title {
491
+ color: rgba(34, 113, 177, 1);
492
+ text-align: center;
493
+ }
494
+ li.done div.step-number {
495
+ background-color: #95c125;
496
+ }
497
+ li.done div.step-title {
498
+ color: #95c125;
499
+ }
500
+ li.disabled div.step-number {
501
+ background-color: #aaaaaa;
502
+ }
503
+ li.disabled div.step-title {
504
+ color: #aaaaaa;
505
+ }
506
+ .wizard > .content {
507
+ -webkit-border-radius: 0;
508
+ border-radius: 0;
509
+ margin: 0;
510
+ }
511
+ li.disabled span.shield-progress-bar {
512
+ background-color: #aaaaaa;
513
+ }
514
+ div.steps ul li:last-child span.shield-progress-bar {
515
+ display: none;
516
+ }
517
+ /* override bootstrap */
518
+ a, a:not([href]):not([class]) {
519
+ color: #2271b1;
520
+ text-decoration: underline;
521
+ }
522
+ a:hover, a:visited {
523
+ color: #135e96;
524
+ }
525
+ .vimeo-feather img {
526
+ padding: 3px;
527
+ border: 1px solid #008000;
528
+ background: white;
529
+ }
530
+ .vimeo-feather img {
531
+ width: 400px;
532
+ }
533
+ .button > svg {
534
+ width: 24px;
535
+ height: 24px;
536
+ margin-right: 3px;
537
+ }
538
+
539
+ .wp-core-ui button.wizard-button-go-back {
540
+ border: 0 none;
541
+ background: transparent;
542
+ }
resources/css/wizard.css DELETED
@@ -1,163 +0,0 @@
1
- html {
2
- overflow-y: scroll;
3
- }
4
- body {
5
- padding-bottom: 200px;
6
- }
7
- body.wait {
8
- cursor: wait !important;
9
- }
10
- .wizard > .content {
11
- background: #ffffff;
12
- box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.2);
13
- }
14
- .wizard > .steps .current a {
15
- text-shadow: 1px 1px 0 rgba(0,0,0,0.1);
16
- }
17
- .wizard.vertical > .steps {
18
- width: 20%; /** from 30 **/
19
- }
20
- .wizard.vertical > .content {
21
- width: 75%; /** from 65 **/
22
- }
23
- .wizard > .content > .body {
24
- height: auto;
25
- position: relative;
26
- padding: 0;
27
- width: 100%
28
- }
29
- .wizard > .content > .body .slide-header {
30
- padding: 3% 3% 0 3%;
31
- }
32
- .wizard > .content > .body .slide-header .btn-block {
33
- margin-bottom: -1px;
34
- }
35
- .wizard > .content > .body .slide-header hr {
36
- margin: 15px 0;
37
- }
38
- .wizard > .content > .body .slide-body {
39
- padding: 0 6% 0 6%;
40
- }
41
- .wizard > .content > .body .slide-footer {
42
- padding: 0 6% 3% 6%;
43
- }
44
- .wizard.vertical > .actions {
45
- margin-bottom: 20px;
46
- }
47
- .wizard h3 {
48
- margin-bottom: 20px;
49
- }
50
- .wizard p {
51
- }
52
- .wizard .body ol,
53
- .wizard .body ul {
54
- margin-bottom: 20px;
55
- padding-left: 20px;
56
- }
57
- .wizard .body ul {
58
- list-style: square inside none;
59
- }
60
- .wizard p.wizard-response {
61
- /*padding: 10px 15px;*/
62
- }
63
-
64
- .wizard .slide-body img {
65
- float: left;
66
- width: 40%;
67
- margin-right: 20px;
68
- }
69
- .wizard .slide-body .media {
70
- margin-top: 25px
71
- }
72
- .wizard .slide-body .media-object {
73
- border: 1px solid #888;
74
- height: 64px;
75
- width: 64px;
76
- }
77
- .wizard .indent_slight {
78
- margin-left: 26px;
79
- }
80
-
81
- .wizard_slot {
82
- border: 1px solid #dddddd;
83
- border-radius: 3px;
84
- margin-top: 30px;
85
- padding: 0 20px 20px;
86
- }
87
- .wizard_slot:hover {
88
- background-color: #ffffff;
89
- }
90
-
91
- .wizard form label {
92
- }
93
- .wizard form input[type="radio"]:checked + span {
94
- font-weight: bolder;
95
- letter-spacing: -0.4px;
96
- }
97
- .wizard form .form-check-label {
98
- margin-bottom: 10px;
99
- }
100
- .wizard form .form-check-inline .form-check-label {
101
- margin-bottom: 0;
102
- }
103
-
104
- #GoProBtn {
105
- width: 128px;
106
- display: block;
107
- margin: 5px auto 20px;
108
- }
109
-
110
- #FooterWizardBanner {
111
- position: fixed;
112
- bottom: 0;
113
- height: 100px;
114
- width: 100%;
115
- }
116
- #WizardTop {
117
- height: 40px;
118
- background-color: #fafafa;
119
- background: linear-gradient(to top, rgba(250,250,250,0.95), rgba(250,250,250,0.7));
120
- }
121
- #WizardBanner {
122
- height: 100px;
123
- background-color: #eaffea;
124
- border-top: 1px solid #bbbbbb;
125
- padding-top: 10px;
126
- text-align: center;
127
- word-break: keep-all;
128
- white-space: nowrap;
129
- }
130
- #WizardBanner p {
131
- margin: 0;
132
- line-height: 20px;
133
- text-align: left;
134
- }
135
-
136
- .more_details {
137
- margin-bottom: 12px;
138
- }
139
- .more_details:hover {
140
- cursor: pointer;
141
- }
142
- .more_details_body {
143
- margin-bottom: 12px;
144
- }
145
-
146
- .scan-results-accordian {
147
- }
148
- .scan-results-accordian .card {
149
- margin-bottom: 24px;
150
- }
151
- .scan-results-accordian .card-header {
152
- padding: .5rem 1.25rem;
153
- }
154
- .scan-results-accordian .card-header button:hover,
155
- .scan-results-accordian .card-header button {
156
- color: #f1f1f1
157
- }
158
-
159
- .embed-vimeo {
160
- margin-bottom: 20px;
161
- border-radius: 3px;
162
- box-shadow: 1px 1px 3px rgba(0,0,0,0.3);
163
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
resources/images/bootstrap/envelope-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-envelope-fill" viewBox="0 0 16 16">
2
+ <path d="M.05 3.555A2 2 0 0 1 2 2h12a2 2 0 0 1 1.95 1.555L8 8.414.05 3.555zM0 4.697v7.104l5.803-3.558L0 4.697zM6.761 8.83l-6.57 4.027A2 2 0 0 0 2 14h12a2 2 0 0 0 1.808-1.144l-6.57-4.027L8 9.586l-1.239-.757zm3.436-.586L16 11.801V4.697l-5.803 3.546z"/>
3
+ </svg>
resources/images/bootstrap/facebook.svg ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-facebook" viewBox="0 0 16 16">
2
+ <path d="M16 8.049c0-4.446-3.582-8.05-8-8.05C3.58 0-.002 3.603-.002 8.05c0 4.017 2.926 7.347 6.75 7.951v-5.625h-2.03V8.05H6.75V6.275c0-2.017 1.195-3.131 3.022-3.131.876 0 1.791.157 1.791.157v1.98h-1.009c-.993 0-1.303.621-1.303 1.258v1.51h2.218l-.354 2.326H9.25V16c3.824-.604 6.75-3.934 6.75-7.951z"/>
3
+ </svg>
resources/images/bootstrap/file-earmark-play.svg ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-file-earmark-play" viewBox="0 0 16 16">
2
+ <path d="M6 6.883v4.234a.5.5 0 0 0 .757.429l3.528-2.117a.5.5 0 0 0 0-.858L6.757 6.454a.5.5 0 0 0-.757.43z"/>
3
+ <path d="M14 14V4.5L9.5 0H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2zM9.5 3A1.5 1.5 0 0 0 11 4.5h2V14a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h5.5v2z"/>
4
+ </svg>
resources/images/bootstrap/play-btn-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-play-btn-fill" viewBox="0 0 16 16">
2
+ <path d="M0 12V4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm6.79-6.907A.5.5 0 0 0 6 5.5v5a.5.5 0 0 0 .79.407l3.5-2.5a.5.5 0 0 0 0-.814l-3.5-2.5z"/>
3
+ </svg>
resources/images/bootstrap/play-btn.svg ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-play-btn" viewBox="0 0 16 16">
2
+ <path d="M6.79 5.093A.5.5 0 0 0 6 5.5v5a.5.5 0 0 0 .79.407l3.5-2.5a.5.5 0 0 0 0-.814l-3.5-2.5z"/>
3
+ <path d="M0 4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V4zm15 0a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4z"/>
4
+ </svg>
resources/images/bootstrap/play-circle.svg ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-play-circle" 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="M6.271 5.055a.5.5 0 0 1 .52.038l3.5 2.5a.5.5 0 0 1 0 .814l-3.5 2.5A.5.5 0 0 1 6 10.5v-5a.5.5 0 0 1 .271-.445z"/>
4
+ </svg>
resources/images/bootstrap/play-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-play-fill" viewBox="0 0 16 16">
2
+ <path d="m11.596 8.697-6.363 3.692c-.54.313-1.233-.066-1.233-.697V4.308c0-.63.692-1.01 1.233-.696l6.363 3.692a.802.802 0 0 1 0 1.393z"/>
3
+ </svg>
resources/images/bootstrap/shield-fill-check.svg ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-shield-fill-check" viewBox="0 0 16 16">
2
+ <path fill-rule="evenodd" d="M8 0c-.69 0-1.843.265-2.928.56-1.11.3-2.229.655-2.887.87a1.54 1.54 0 0 0-1.044 1.262c-.596 4.477.787 7.795 2.465 9.99a11.777 11.777 0 0 0 2.517 2.453c.386.273.744.482 1.048.625.28.132.581.24.829.24s.548-.108.829-.24a7.159 7.159 0 0 0 1.048-.625 11.775 11.775 0 0 0 2.517-2.453c1.678-2.195 3.061-5.513 2.465-9.99a1.541 1.541 0 0 0-1.044-1.263 62.467 62.467 0 0 0-2.887-.87C9.843.266 8.69 0 8 0zm2.146 5.146a.5.5 0 0 1 .708.708l-3 3a.5.5 0 0 1-.708 0l-1.5-1.5a.5.5 0 1 1 .708-.708L7.5 7.793l2.646-2.647z"/>
3
+ </svg>
resources/images/bootstrap/shield-fill-exclamation.svg ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-shield-fill-exclamation" viewBox="0 0 16 16">
2
+ <path fill-rule="evenodd" d="M8 0c-.69 0-1.843.265-2.928.56-1.11.3-2.229.655-2.887.87a1.54 1.54 0 0 0-1.044 1.262c-.596 4.477.787 7.795 2.465 9.99a11.777 11.777 0 0 0 2.517 2.453c.386.273.744.482 1.048.625.28.132.581.24.829.24s.548-.108.829-.24a7.159 7.159 0 0 0 1.048-.625 11.775 11.775 0 0 0 2.517-2.453c1.678-2.195 3.061-5.513 2.465-9.99a1.541 1.541 0 0 0-1.044-1.263 62.467 62.467 0 0 0-2.887-.87C9.843.266 8.69 0 8 0zm-.55 8.502L7.1 4.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0zM8.002 12a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/>
3
+ </svg>
resources/images/bootstrap/shield-fill-plus.svg ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-shield-fill-plus" viewBox="0 0 16 16">
2
+ <path fill-rule="evenodd" d="M8 0c-.69 0-1.843.265-2.928.56-1.11.3-2.229.655-2.887.87a1.54 1.54 0 0 0-1.044 1.262c-.596 4.477.787 7.795 2.465 9.99a11.777 11.777 0 0 0 2.517 2.453c.386.273.744.482 1.048.625.28.132.581.24.829.24s.548-.108.829-.24a7.159 7.159 0 0 0 1.048-.625 11.775 11.775 0 0 0 2.517-2.453c1.678-2.195 3.061-5.513 2.465-9.99a1.541 1.541 0 0 0-1.044-1.263 62.467 62.467 0 0 0-2.887-.87C9.843.266 8.69 0 8 0zm-.5 5a.5.5 0 0 1 1 0v1.5H10a.5.5 0 0 1 0 1H8.5V9a.5.5 0 0 1-1 0V7.5H6a.5.5 0 0 1 0-1h1.5V5z"/>
3
+ </svg>
resources/images/bootstrap/twitter.svg ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-twitter" viewBox="0 0 16 16">
2
+ <path d="M5.026 15c6.038 0 9.341-5.003 9.341-9.334 0-.14 0-.282-.006-.422A6.685 6.685 0 0 0 16 3.542a6.658 6.658 0 0 1-1.889.518 3.301 3.301 0 0 0 1.447-1.817 6.533 6.533 0 0 1-2.087.793A3.286 3.286 0 0 0 7.875 6.03a9.325 9.325 0 0 1-6.767-3.429 3.289 3.289 0 0 0 1.018 4.382A3.323 3.323 0 0 1 .64 6.575v.045a3.288 3.288 0 0 0 2.632 3.218 3.203 3.203 0 0 1-.865.115 3.23 3.23 0 0 1-.614-.057 3.283 3.283 0 0 0 3.067 2.277A6.588 6.588 0 0 1 .78 13.58a6.32 6.32 0 0 1-.78-.045A9.344 9.344 0 0 0 5.026 15z"/>
3
+ </svg>
resources/js/featherlight.js DELETED
@@ -1,641 +0,0 @@
1
- /**
2
- * Featherlight - ultra slim jQuery lightbox
3
- * Version 1.7.13 - http://noelboss.github.io/featherlight/
4
- *
5
- * Copyright 2018, Noël Raoul Bossart (http://www.noelboss.com)
6
- * MIT Licensed.
7
- **/
8
- (function($) {
9
- "use strict";
10
-
11
- if('undefined' === typeof $) {
12
- if('console' in window){ window.console.info('Too much lightness, Featherlight needs jQuery.'); }
13
- return;
14
- }
15
- if($.fn.jquery.match(/-ajax/)) {
16
- if('console' in window){ window.console.info('Featherlight needs regular jQuery, not the slim version.'); }
17
- return;
18
- }
19
- /* Featherlight is exported as $.featherlight.
20
- It is a function used to open a featherlight lightbox.
21
-
22
- [tech]
23
- Featherlight uses prototype inheritance.
24
- Each opened lightbox will have a corresponding object.
25
- That object may have some attributes that override the
26
- prototype's.
27
- Extensions created with Featherlight.extend will have their
28
- own prototype that inherits from Featherlight's prototype,
29
- thus attributes can be overriden either at the object level,
30
- or at the extension level.
31
- To create callbacks that chain themselves instead of overriding,
32
- use chainCallbacks.
33
- For those familiar with CoffeeScript, this correspond to
34
- Featherlight being a class and the Gallery being a class
35
- extending Featherlight.
36
- The chainCallbacks is used since we don't have access to
37
- CoffeeScript's `super`.
38
- */
39
-
40
- function Featherlight($content, config) {
41
- if(this instanceof Featherlight) { /* called with new */
42
- this.id = Featherlight.id++;
43
- this.setup($content, config);
44
- this.chainCallbacks(Featherlight._callbackChain);
45
- } else {
46
- var fl = new Featherlight($content, config);
47
- fl.open();
48
- return fl;
49
- }
50
- }
51
-
52
- var opened = [],
53
- pruneOpened = function(remove) {
54
- opened = $.grep(opened, function(fl) {
55
- return fl !== remove && fl.$instance.closest('body').length > 0;
56
- } );
57
- return opened;
58
- };
59
-
60
- // Removes keys of `set` from `obj` and returns the removed key/values.
61
- function slice(obj, set) {
62
- var r = {};
63
- for (var key in obj) {
64
- if (key in set) {
65
- r[key] = obj[key];
66
- delete obj[key];
67
- }
68
- }
69
- return r;
70
- }
71
-
72
- // NOTE: List of available [iframe attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe).
73
- var iFrameAttributeSet = {
74
- allow: 1, allowfullscreen: 1, frameborder: 1, height: 1, longdesc: 1, marginheight: 1, marginwidth: 1,
75
- mozallowfullscreen: 1, name: 1, referrerpolicy: 1, sandbox: 1, scrolling: 1, src: 1, srcdoc: 1, style: 1,
76
- webkitallowfullscreen: 1, width: 1
77
- };
78
-
79
- // Converts camelCased attributes to dasherized versions for given prefix:
80
- // parseAttrs({hello: 1, hellFrozeOver: 2}, 'hell') => {froze-over: 2}
81
- function parseAttrs(obj, prefix) {
82
- var attrs = {},
83
- regex = new RegExp('^' + prefix + '([A-Z])(.*)');
84
- for (var key in obj) {
85
- var match = key.match(regex);
86
- if (match) {
87
- var dasherized = (match[1] + match[2].replace(/([A-Z])/g, '-$1')).toLowerCase();
88
- attrs[dasherized] = obj[key];
89
- }
90
- }
91
- return attrs;
92
- }
93
-
94
- /* document wide key handler */
95
- var eventMap = { keyup: 'onKeyUp', resize: 'onResize' };
96
-
97
- var globalEventHandler = function(event) {
98
- $.each(Featherlight.opened().reverse(), function() {
99
- if (!event.isDefaultPrevented()) {
100
- if (false === this[eventMap[event.type]](event)) {
101
- event.preventDefault(); event.stopPropagation(); return false;
102
- }
103
- }
104
- });
105
- };
106
-
107
- var toggleGlobalEvents = function(set) {
108
- if(set !== Featherlight._globalHandlerInstalled) {
109
- Featherlight._globalHandlerInstalled = set;
110
- var events = $.map(eventMap, function(_, name) { return name+'.'+Featherlight.prototype.namespace; } ).join(' ');
111
- $(window)[set ? 'on' : 'off'](events, globalEventHandler);
112
- }
113
- };
114
-
115
- Featherlight.prototype = {
116
- constructor: Featherlight,
117
- /*** defaults ***/
118
- /* extend featherlight with defaults and methods */
119
- namespace: 'featherlight', /* Name of the events and css class prefix */
120
- targetAttr: 'data-featherlight', /* Attribute of the triggered element that contains the selector to the lightbox content */
121
- variant: null, /* Class that will be added to change look of the lightbox */
122
- resetCss: false, /* Reset all css */
123
- background: null, /* Custom DOM for the background, wrapper and the closebutton */
124
- openTrigger: 'click', /* Event that triggers the lightbox */
125
- closeTrigger: 'click', /* Event that triggers the closing of the lightbox */
126
- filter: null, /* Selector to filter events. Think $(...).on('click', filter, eventHandler) */
127
- root: 'body', /* Where to append featherlights */
128
- openSpeed: 250, /* Duration of opening animation */
129
- closeSpeed: 250, /* Duration of closing animation */
130
- closeOnClick: 'background', /* Close lightbox on click ('background', 'anywhere' or false) */
131
- closeOnEsc: true, /* Close lightbox when pressing esc */
132
- closeIcon: '&#10005;', /* Close icon */
133
- loading: '', /* Content to show while initial content is loading */
134
- persist: false, /* If set, the content will persist and will be shown again when opened again. 'shared' is a special value when binding multiple elements for them to share the same content */
135
- otherClose: null, /* Selector for alternate close buttons (e.g. "a.close") */
136
- beforeOpen: $.noop, /* Called before open. can return false to prevent opening of lightbox. Gets event as parameter, this contains all data */
137
- beforeContent: $.noop, /* Called when content is loaded. Gets event as parameter, this contains all data */
138
- beforeClose: $.noop, /* Called before close. can return false to prevent opening of lightbox. Gets event as parameter, this contains all data */
139
- afterOpen: $.noop, /* Called after open. Gets event as parameter, this contains all data */
140
- afterContent: $.noop, /* Called after content is ready and has been set. Gets event as parameter, this contains all data */
141
- afterClose: $.noop, /* Called after close. Gets event as parameter, this contains all data */
142
- onKeyUp: $.noop, /* Called on key up for the frontmost featherlight */
143
- onResize: $.noop, /* Called after new content and when a window is resized */
144
- type: null, /* Specify type of lightbox. If unset, it will check for the targetAttrs value. */
145
- contentFilters: ['jquery', 'image', 'html', 'ajax', 'iframe', 'text'], /* List of content filters to use to determine the content */
146
-
147
- /*** methods ***/
148
- /* setup iterates over a single instance of featherlight and prepares the background and binds the events */
149
- setup: function(target, config){
150
- /* all arguments are optional */
151
- if (typeof target === 'object' && target instanceof $ === false && !config) {
152
- config = target;
153
- target = undefined;
154
- }
155
-
156
- var self = $.extend(this, config, {target: target}),
157
- css = !self.resetCss ? self.namespace : self.namespace+'-reset', /* by adding -reset to the classname, we reset all the default css */
158
- $background = $(self.background || [
159
- '<div class="'+css+'-loading '+css+'">',
160
- '<div class="'+css+'-content">',
161
- '<button class="'+css+'-close-icon '+ self.namespace + '-close" aria-label="Close">',
162
- self.closeIcon,
163
- '</button>',
164
- '<div class="'+self.namespace+'-inner">' + self.loading + '</div>',
165
- '</div>',
166
- '</div>'].join('')),
167
- closeButtonSelector = '.'+self.namespace+'-close' + (self.otherClose ? ',' + self.otherClose : '');
168
-
169
- self.$instance = $background.clone().addClass(self.variant); /* clone DOM for the background, wrapper and the close button */
170
-
171
- /* close when click on background/anywhere/null or closebox */
172
- self.$instance.on(self.closeTrigger+'.'+self.namespace, function(event) {
173
- if(event.isDefaultPrevented()) {
174
- return;
175
- }
176
- var $target = $(event.target);
177
- if( ('background' === self.closeOnClick && $target.is('.'+self.namespace))
178
- || 'anywhere' === self.closeOnClick
179
- || $target.closest(closeButtonSelector).length ){
180
- self.close(event);
181
- event.preventDefault();
182
- }
183
- });
184
-
185
- return this;
186
- },
187
-
188
- /* this method prepares the content and converts it into a jQuery object or a promise */
189
- getContent: function(){
190
- if(this.persist !== false && this.$content) {
191
- return this.$content;
192
- }
193
- var self = this,
194
- filters = this.constructor.contentFilters,
195
- readTargetAttr = function(name){ return self.$currentTarget && self.$currentTarget.attr(name); },
196
- targetValue = readTargetAttr(self.targetAttr),
197
- data = self.target || targetValue || '';
198
-
199
- /* Find which filter applies */
200
- var filter = filters[self.type]; /* check explicit type like {type: 'image'} */
201
-
202
- /* check explicit type like data-featherlight="image" */
203
- if(!filter && data in filters) {
204
- filter = filters[data];
205
- data = self.target && targetValue;
206
- }
207
- data = data || readTargetAttr('href') || '';
208
-
209
- /* check explicity type & content like {image: 'photo.jpg'} */
210
- if(!filter) {
211
- for(var filterName in filters) {
212
- if(self[filterName]) {
213
- filter = filters[filterName];
214
- data = self[filterName];
215
- }
216
- }
217
- }
218
-
219
- /* otherwise it's implicit, run checks */
220
- if(!filter) {
221
- var target = data;
222
- data = null;
223
- $.each(self.contentFilters, function() {
224
- filter = filters[this];
225
- if(filter.test) {
226
- data = filter.test(target);
227
- }
228
- if(!data && filter.regex && target.match && target.match(filter.regex)) {
229
- data = target;
230
- }
231
- return !data;
232
- });
233
- if(!data) {
234
- if('console' in window){ window.console.error('Featherlight: no content filter found ' + (target ? ' for "' + target + '"' : ' (no target specified)')); }
235
- return false;
236
- }
237
- }
238
- /* Process it */
239
- return filter.process.call(self, data);
240
- },
241
-
242
- /* sets the content of $instance to $content */
243
- setContent: function($content){
244
- this.$instance.removeClass(this.namespace+'-loading');
245
-
246
- /* we need a special class for the iframe */
247
- this.$instance.toggleClass(this.namespace+'-iframe', $content.is('iframe'));
248
-
249
- /* replace content by appending to existing one before it is removed
250
- this insures that featherlight-inner remain at the same relative
251
- position to any other items added to featherlight-content */
252
- this.$instance.find('.'+this.namespace+'-inner')
253
- .not($content) /* excluded new content, important if persisted */
254
- .slice(1).remove().end() /* In the unexpected event where there are many inner elements, remove all but the first one */
255
- .replaceWith($.contains(this.$instance[0], $content[0]) ? '' : $content);
256
-
257
- this.$content = $content.addClass(this.namespace+'-inner');
258
-
259
- return this;
260
- },
261
-
262
- /* opens the lightbox. "this" contains $instance with the lightbox, and with the config.
263
- Returns a promise that is resolved after is successfully opened. */
264
- open: function(event){
265
- var self = this;
266
- self.$instance.hide().appendTo(self.root);
267
- if((!event || !event.isDefaultPrevented())
268
- && self.beforeOpen(event) !== false) {
269
-
270
- if(event){
271
- event.preventDefault();
272
- }
273
- var $content = self.getContent();
274
-
275
- if($content) {
276
- opened.push(self);
277
-
278
- toggleGlobalEvents(true);
279
-
280
- self.$instance.fadeIn(self.openSpeed);
281
- self.beforeContent(event);
282
-
283
- /* Set content and show */
284
- return $.when($content)
285
- .always(function($content){
286
- self.setContent($content);
287
- self.afterContent(event);
288
- })
289
- .then(self.$instance.promise())
290
- /* Call afterOpen after fadeIn is done */
291
- .done(function(){ self.afterOpen(event); });
292
- }
293
- }
294
- self.$instance.detach();
295
- return $.Deferred().reject().promise();
296
- },
297
-
298
- /* closes the lightbox. "this" contains $instance with the lightbox, and with the config
299
- returns a promise, resolved after the lightbox is successfully closed. */
300
- close: function(event){
301
- var self = this,
302
- deferred = $.Deferred();
303
-
304
- if(self.beforeClose(event) === false) {
305
- deferred.reject();
306
- } else {
307
-
308
- if (0 === pruneOpened(self).length) {
309
- toggleGlobalEvents(false);
310
- }
311
-
312
- self.$instance.fadeOut(self.closeSpeed,function(){
313
- self.$instance.detach();
314
- self.afterClose(event);
315
- deferred.resolve();
316
- });
317
- }
318
- return deferred.promise();
319
- },
320
-
321
- /* resizes the content so it fits in visible area and keeps the same aspect ratio.
322
- Does nothing if either the width or the height is not specified.
323
- Called automatically on window resize.
324
- Override if you want different behavior. */
325
- resize: function(w, h) {
326
- if (w && h) {
327
- /* Reset apparent image size first so container grows */
328
- this.$content.css('width', '').css('height', '');
329
- /* Calculate the worst ratio so that dimensions fit */
330
- /* Note: -1 to avoid rounding errors */
331
- var ratio = Math.max(
332
- w / (this.$content.parent().width()-1),
333
- h / (this.$content.parent().height()-1));
334
- /* Resize content */
335
- if (ratio > 1) {
336
- ratio = h / Math.floor(h / ratio); /* Round ratio down so height calc works */
337
- this.$content.css('width', '' + w / ratio + 'px').css('height', '' + h / ratio + 'px');
338
- }
339
- }
340
- },
341
-
342
- /* Utility function to chain callbacks
343
- [Warning: guru-level]
344
- Used be extensions that want to let users specify callbacks but
345
- also need themselves to use the callbacks.
346
- The argument 'chain' has callback names as keys and function(super, event)
347
- as values. That function is meant to call `super` at some point.
348
- */
349
- chainCallbacks: function(chain) {
350
- for (var name in chain) {
351
- this[name] = $.proxy(chain[name], this, $.proxy(this[name], this));
352
- }
353
- }
354
- };
355
-
356
- $.extend(Featherlight, {
357
- id: 0, /* Used to id single featherlight instances */
358
- autoBind: '[data-featherlight]', /* Will automatically bind elements matching this selector. Clear or set before onReady */
359
- defaults: Featherlight.prototype, /* You can access and override all defaults using $.featherlight.defaults, which is just a synonym for $.featherlight.prototype */
360
- /* Contains the logic to determine content */
361
- contentFilters: {
362
- jquery: {
363
- regex: /^[#.]\w/, /* Anything that starts with a class name or identifiers */
364
- test: function(elem) { return elem instanceof $ && elem; },
365
- process: function(elem) { return this.persist !== false ? $(elem) : $(elem).clone(true); }
366
- },
367
- image: {
368
- regex: /\.(png|jpg|jpeg|gif|tiff?|bmp|svg)(\?\S*)?$/i,
369
- process: function(url) {
370
- var self = this,
371
- deferred = $.Deferred(),
372
- img = new Image(),
373
- $img = $('<img src="'+url+'" alt="" class="'+self.namespace+'-image" />');
374
- img.onload = function() {
375
- /* Store naturalWidth & height for IE8 */
376
- $img.naturalWidth = img.width; $img.naturalHeight = img.height;
377
- deferred.resolve( $img );
378
- };
379
- img.onerror = function() { deferred.reject($img); };
380
- img.src = url;
381
- return deferred.promise();
382
- }
383
- },
384
- html: {
385
- regex: /^\s*<[\w!][^<]*>/, /* Anything that starts with some kind of valid tag */
386
- process: function(html) { return $(html); }
387
- },
388
- ajax: {
389
- regex: /./, /* At this point, any content is assumed to be an URL */
390
- process: function(url) {
391
- var self = this,
392
- deferred = $.Deferred();
393
- /* we are using load so one can specify a target with: url.html #targetelement */
394
- var $container = $('<div></div>').load(url, function(response, status){
395
- if ( status !== "error" ) {
396
- deferred.resolve($container.contents());
397
- }
398
- deferred.fail();
399
- });
400
- return deferred.promise();
401
- }
402
- },
403
- iframe: {
404
- process: function(url) {
405
- var deferred = new $.Deferred();
406
- var $content = $('<iframe/>');
407
- var css = parseAttrs(this, 'iframe');
408
- var attrs = slice(css, iFrameAttributeSet);
409
- $content.hide()
410
- .attr('src', url)
411
- .attr(attrs)
412
- .css(css)
413
- .on('load', function() { deferred.resolve($content.show()); })
414
- // We can't move an <iframe> and avoid reloading it,
415
- // so let's put it in place ourselves right now:
416
- .appendTo(this.$instance.find('.' + this.namespace + '-content'));
417
- return deferred.promise();
418
- }
419
- },
420
- text: {
421
- process: function(text) { return $('<div>', {text: text}); }
422
- }
423
- },
424
-
425
- functionAttributes: ['beforeOpen', 'afterOpen', 'beforeContent', 'afterContent', 'beforeClose', 'afterClose'],
426
-
427
- /*** class methods ***/
428
- /* read element's attributes starting with data-featherlight- */
429
- readElementConfig: function(element, namespace) {
430
- var Klass = this,
431
- regexp = new RegExp('^data-' + namespace + '-(.*)'),
432
- config = {};
433
- if (element && element.attributes) {
434
- $.each(element.attributes, function(){
435
- var match = this.name.match(regexp);
436
- if (match) {
437
- var val = this.value,
438
- name = $.camelCase(match[1]);
439
- if ($.inArray(name, Klass.functionAttributes) >= 0) { /* jshint -W054 */
440
- val = new Function(val); /* jshint +W054 */
441
- } else {
442
- try { val = JSON.parse(val); }
443
- catch(e) {}
444
- }
445
- config[name] = val;
446
- }
447
- });
448
- }
449
- return config;
450
- },
451
-
452
- /* Used to create a Featherlight extension
453
- [Warning: guru-level]
454
- Creates the extension's prototype that in turn
455
- inherits Featherlight's prototype.
456
- Could be used to extend an extension too...
457
- This is pretty high level wizardy, it comes pretty much straight
458
- from CoffeeScript and won't teach you anything about Featherlight
459
- as it's not really specific to this library.
460
- My suggestion: move along and keep your sanity.
461
- */
462
- extend: function(child, defaults) {
463
- /* Setup class hierarchy, adapted from CoffeeScript */
464
- var Ctor = function(){ this.constructor = child; };
465
- Ctor.prototype = this.prototype;
466
- child.prototype = new Ctor();
467
- child.__super__ = this.prototype;
468
- /* Copy class methods & attributes */
469
- $.extend(child, this, defaults);
470
- child.defaults = child.prototype;
471
- return child;
472
- },
473
-
474
- attach: function($source, $content, config) {
475
- var Klass = this;
476
- if (typeof $content === 'object' && $content instanceof $ === false && !config) {
477
- config = $content;
478
- $content = undefined;
479
- }
480
- /* make a copy */
481
- config = $.extend({}, config);
482
-
483
- /* Only for openTrigger, filter & namespace... */
484
- var namespace = config.namespace || Klass.defaults.namespace,
485
- tempConfig = $.extend({}, Klass.defaults, Klass.readElementConfig($source[0], namespace), config),
486
- sharedPersist;
487
- var handler = function(event) {
488
- var $target = $(event.currentTarget);
489
- /* ... since we might as well compute the config on the actual target */
490
- var elemConfig = $.extend(
491
- {$source: $source, $currentTarget: $target},
492
- Klass.readElementConfig($source[0], tempConfig.namespace),
493
- Klass.readElementConfig(event.currentTarget, tempConfig.namespace),
494
- config);
495
- var fl = sharedPersist || $target.data('featherlight-persisted') || new Klass($content, elemConfig);
496
- if(fl.persist === 'shared') {
497
- sharedPersist = fl;
498
- } else if(fl.persist !== false) {
499
- $target.data('featherlight-persisted', fl);
500
- }
501
- if (elemConfig.$currentTarget.blur) {
502
- elemConfig.$currentTarget.blur(); // Otherwise 'enter' key might trigger the dialog again
503
- }
504
- fl.open(event);
505
- };
506
-
507
- $source.on(tempConfig.openTrigger+'.'+tempConfig.namespace, tempConfig.filter, handler);
508
-
509
- return {filter: tempConfig.filter, handler: handler};
510
- },
511
-
512
- current: function() {
513
- var all = this.opened();
514
- return all[all.length - 1] || null;
515
- },
516
-
517
- opened: function() {
518
- var klass = this;
519
- pruneOpened();
520
- return $.grep(opened, function(fl) { return fl instanceof klass; } );
521
- },
522
-
523
- close: function(event) {
524
- var cur = this.current();
525
- if(cur) { return cur.close(event); }
526
- },
527
-
528
- /* Does the auto binding on startup.
529
- Meant only to be used by Featherlight and its extensions
530
- */
531
- _onReady: function() {
532
- var Klass = this;
533
- if(Klass.autoBind){
534
- var $autobound = $(Klass.autoBind);
535
- /* Bind existing elements */
536
- $autobound.each(function(){
537
- Klass.attach($(this));
538
- });
539
- /* If a click propagates to the document level, then we have an item that was added later on */
540
- $(document).on('click', Klass.autoBind, function(evt) {
541
- if (evt.isDefaultPrevented()) {
542
- return;
543
- }
544
- var $cur = $(evt.currentTarget);
545
- var len = $autobound.length;
546
- $autobound = $autobound.add($cur);
547
- if(len === $autobound.length) {
548
- return; /* already bound */
549
- }
550
- /* Bind featherlight */
551
- var data = Klass.attach($cur);
552
- /* Dispatch event directly */
553
- if (!data.filter || $(evt.target).parentsUntil($cur, data.filter).length > 0) {
554
- data.handler(evt);
555
- }
556
- });
557
- }
558
- },
559
-
560
- /* Featherlight uses the onKeyUp callback to intercept the escape key.
561
- Private to Featherlight.
562
- */
563
- _callbackChain: {
564
- onKeyUp: function(_super, event){
565
- if(27 === event.keyCode) {
566
- if (this.closeOnEsc) {
567
- $.featherlight.close(event);
568
- }
569
- return false;
570
- } else {
571
- return _super(event);
572
- }
573
- },
574
-
575
- beforeOpen: function(_super, event) {
576
- // Used to disable scrolling
577
- $(document.documentElement).addClass('with-featherlight');
578
-
579
- // Remember focus:
580
- this._previouslyActive = document.activeElement;
581
-
582
- // Disable tabbing:
583
- // See http://stackoverflow.com/questions/1599660/which-html-elements-can-receive-focus
584
- this._$previouslyTabbable = $("a, input, select, textarea, iframe, button, iframe, [contentEditable=true]")
585
- .not('[tabindex]')
586
- .not(this.$instance.find('button'));
587
-
588
- this._$previouslyWithTabIndex = $('[tabindex]').not('[tabindex="-1"]');
589
- this._previousWithTabIndices = this._$previouslyWithTabIndex.map(function(_i, elem) {
590
- return $(elem).attr('tabindex');
591
- });
592
-
593
- this._$previouslyWithTabIndex.add(this._$previouslyTabbable).attr('tabindex', -1);
594
-
595
- if (document.activeElement.blur) {
596
- document.activeElement.blur();
597
- }
598
- return _super(event);
599
- },
600
-
601
- afterClose: function(_super, event) {
602
- var r = _super(event);
603
- // Restore focus
604
- var self = this;
605
- this._$previouslyTabbable.removeAttr('tabindex');
606
- this._$previouslyWithTabIndex.each(function(i, elem) {
607
- $(elem).attr('tabindex', self._previousWithTabIndices[i]);
608
- });
609
- this._previouslyActive.focus();
610
- // Restore scroll
611
- if(Featherlight.opened().length === 0) {
612
- $(document.documentElement).removeClass('with-featherlight');
613
- }
614
- return r;
615
- },
616
-
617
- onResize: function(_super, event){
618
- this.resize(this.$content.naturalWidth, this.$content.naturalHeight);
619
- return _super(event);
620
- },
621
-
622
- afterContent: function(_super, event){
623
- var r = _super(event);
624
- this.$instance.find('[autofocus]:not([disabled])').focus();
625
- this.onResize(event);
626
- return r;
627
- }
628
- }
629
- });
630
-
631
- $.featherlight = Featherlight;
632
-
633
- /* bind jQuery elements to trigger featherlight */
634
- $.fn.featherlight = function($content, config) {
635
- Featherlight.attach(this, $content, config);
636
- return this;
637
- };
638
-
639
- /* bind featherlight on ready if config autoBind is set */
640
- $(document).ready(function(){ Featherlight._onReady(); });
641
- }(jQuery));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
resources/js/global-plugin.js CHANGED
@@ -131,7 +131,7 @@ if ( typeof icwp_wpsf_vars_hp !== 'undefined' ) {
131
  },
132
  open: function () {
133
  // close dialog by clicking the overlay behind it
134
- jQuery( '.ui-widget-overlay' ).bind( 'click', function () {
135
  jQuery( this ).dialog( 'close' );
136
  } )
137
  },
@@ -221,50 +221,6 @@ if ( typeof icwp_wpsf_vars_hp !== 'undefined' ) {
221
  iCWP_WPSF_HackGuard_Reinstall.initialise();
222
  }
223
 
224
- if ( typeof icwp_wpsf_vars_lg !== 'undefined' ) {
225
- var iCWP_WPSF_LoginGuard_BackupCodes = new function () {
226
- this.initialise = function () {
227
- jQuery( document ).ready( function () {
228
- jQuery( document ).on( "click", "a#IcwpWpsfGenBackupLoginCode", genBackupCode );
229
- jQuery( document ).on( "click", "a#IcwpWpsfDelBackupLoginCode", deleteBackupCode );
230
- } );
231
- };
232
-
233
- var genBackupCode = function ( event ) {
234
- event.preventDefault();
235
- iCWP_WPSF_BodyOverlay.show();
236
-
237
- jQuery.post( ajaxurl, icwp_wpsf_vars_lg.ajax_gen_backup_codes,
238
- function ( oResponse ) {
239
- alert( 'Your login backup code: ' + oResponse.data.code );
240
- }
241
- ).always( function () {
242
- location.reload( true );
243
- }
244
- );
245
-
246
- return false;
247
- };
248
-
249
- var deleteBackupCode = function ( event ) {
250
- event.preventDefault();
251
- iCWP_WPSF_BodyOverlay.show();
252
-
253
- jQuery.post( ajaxurl, icwp_wpsf_vars_lg.ajax_del_backup_codes,
254
- function ( oResponse ) {
255
- }
256
- ).always( function () {
257
- location.reload( true );
258
- // iCWP_WPSF_BodyOverlay.hide();
259
- }
260
- );
261
-
262
- return false;
263
- };
264
- }();
265
- iCWP_WPSF_LoginGuard_BackupCodes.initialise();
266
- }
267
-
268
  var iCWP_WPSF_Growl = new function () {
269
 
270
  this.showMessage = function ( sMessage, bSuccess ) {
131
  },
132
  open: function () {
133
  // close dialog by clicking the overlay behind it
134
+ jQuery( '.ui-widget-overlay' ).on( 'click', function () {
135
  jQuery( this ).dialog( 'close' );
136
  } )
137
  },
221
  iCWP_WPSF_HackGuard_Reinstall.initialise();
222
  }
223
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  var iCWP_WPSF_Growl = new function () {
225
 
226
  this.showMessage = function ( sMessage, bSuccess ) {
resources/js/jquery.fancybox.min.js DELETED
@@ -1,12 +0,0 @@
1
- // ==================================================
2
- // fancyBox v3.2.10
3
- //
4
- // Licensed GPLv3 for open source use
5
- // or fancyBox Commercial License for commercial use
6
- //
7
- // http://fancyapps.com/fancybox/
8
- // Copyright 2017 fancyApps
9
- //
10
- // ==================================================
11
- !function(t,e,n,o){"use strict";function i(t){var e=n(t.currentTarget),o=t.data?t.data.options:{},i=e.attr("data-fancybox")||"",a=0,s=[];t.isDefaultPrevented()||(t.preventDefault(),i?(s=o.selector?n(o.selector):t.data?t.data.items:[],s=s.length?s.filter('[data-fancybox="'+i+'"]'):n('[data-fancybox="'+i+'"]'),a=s.index(e),a<0&&(a=0)):s=[e],n.fancybox.open(s,o,a))}if(n){if(n.fn.fancybox)return void("console"in t&&console.log("fancyBox already initialized"));var a={loop:!1,margin:[44,0],gutter:50,keyboard:!0,arrows:!0,infobar:!0,toolbar:!0,buttons:["slideShow","fullScreen","thumbs","share","close"],idleTime:3,smallBtn:"auto",protect:!1,modal:!1,image:{preload:"auto"},ajax:{settings:{data:{fancybox:!0}}},iframe:{tpl:'<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" frameborder="0" vspace="0" hspace="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen allowtransparency="true" src=""></iframe>',preload:!0,css:{},attr:{scrolling:"auto"}},defaultType:"image",animationEffect:"zoom",animationDuration:500,zoomOpacity:"auto",transitionEffect:"fade",transitionDuration:366,slideClass:"",baseClass:"",baseTpl:'<div class="fancybox-container" role="dialog" tabindex="-1"><div class="fancybox-bg"></div><div class="fancybox-inner"><div class="fancybox-infobar"><span data-fancybox-index></span>&nbsp;/&nbsp;<span data-fancybox-count></span></div><div class="fancybox-toolbar">{{buttons}}</div><div class="fancybox-navigation">{{arrows}}</div><div class="fancybox-stage"></div><div class="fancybox-caption-wrap"><div class="fancybox-caption"></div></div></div></div>',spinnerTpl:'<div class="fancybox-loading"></div>',errorTpl:'<div class="fancybox-error"><p>{{ERROR}}<p></div>',btnTpl:{download:'<a download data-fancybox-download class="fancybox-button fancybox-button--download" title="{{DOWNLOAD}}"><svg viewBox="0 0 40 40"><path d="M20,23 L20,8 L20,23 L13,16 L20,23 L27,16 L20,23 M26,28 L13,28 L27,28 L14,28" /></svg></a>',zoom:'<button data-fancybox-zoom class="fancybox-button fancybox-button--zoom" title="{{ZOOM}}"><svg viewBox="0 0 40 40"><path d="M 18,17 m-8,0 a 8,8 0 1,0 16,0 a 8,8 0 1,0 -16,0 M25,23 L31,29 L25,23" /></svg></button>',close:'<button data-fancybox-close class="fancybox-button fancybox-button--close" title="{{CLOSE}}"><svg viewBox="0 0 40 40"><path d="M10,10 L30,30 M30,10 L10,30" /></svg></button>',smallBtn:'<button data-fancybox-close class="fancybox-close-small" title="{{CLOSE}}"></button>',arrowLeft:'<button data-fancybox-prev class="fancybox-button fancybox-button--arrow_left" title="{{PREV}}"><svg viewBox="0 0 40 40"><path d="M10,20 L30,20 L10,20 L18,28 L10,20 L18,12 L10,20"></path></svg></button>',arrowRight:'<button data-fancybox-next class="fancybox-button fancybox-button--arrow_right" title="{{NEXT}}"><svg viewBox="0 0 40 40"><path d="M30,20 L10,20 L30,20 L22,28 L30,20 L22,12 L30,20"></path></svg></button>'},parentEl:"body",autoFocus:!1,backFocus:!0,trapFocus:!0,fullScreen:{autoStart:!1},touch:{vertical:!0,momentum:!0},hash:null,media:{},slideShow:{autoStart:!1,speed:4e3},thumbs:{autoStart:!1,hideOnClose:!0,parentEl:".fancybox-container",axis:"y"},wheel:"auto",onInit:n.noop,beforeLoad:n.noop,afterLoad:n.noop,beforeShow:n.noop,afterShow:n.noop,beforeClose:n.noop,afterClose:n.noop,onActivate:n.noop,onDeactivate:n.noop,clickContent:function(t,e){return"image"===t.type&&"zoom"},clickSlide:"close",clickOutside:"close",dblclickContent:!1,dblclickSlide:!1,dblclickOutside:!1,mobile:{idleTime:!1,margin:0,clickContent:function(t,e){return"image"===t.type&&"toggleControls"},clickSlide:function(t,e){return"image"===t.type?"toggleControls":"close"},dblclickContent:function(t,e){return"image"===t.type&&"zoom"},dblclickSlide:function(t,e){return"image"===t.type&&"zoom"}},lang:"en",i18n:{en:{CLOSE:"Close",NEXT:"Next",PREV:"Previous",ERROR:"The requested content cannot be loaded. <br/> Please try again later.",PLAY_START:"Start slideshow",PLAY_STOP:"Pause slideshow",FULL_SCREEN:"Full screen",THUMBS:"Thumbnails",DOWNLOAD:"Download",SHARE:"Share",ZOOM:"Zoom"},de:{CLOSE:"Schliessen",NEXT:"Weiter",PREV:"Zurück",ERROR:"Die angeforderten Daten konnten nicht geladen werden. <br/> Bitte versuchen Sie es später nochmal.",PLAY_START:"Diaschau starten",PLAY_STOP:"Diaschau beenden",FULL_SCREEN:"Vollbild",THUMBS:"Vorschaubilder",DOWNLOAD:"Herunterladen",SHARE:"Teilen",ZOOM:"Maßstab"}}},s=n(t),r=n(e),c=0,l=function(t){return t&&t.hasOwnProperty&&t instanceof n},u=function(){return t.requestAnimationFrame||t.webkitRequestAnimationFrame||t.mozRequestAnimationFrame||t.oRequestAnimationFrame||function(e){return t.setTimeout(e,1e3/60)}}(),d=function(){var t,n=e.createElement("fakeelement"),i={transition:"transitionend",OTransition:"oTransitionEnd",MozTransition:"transitionend",WebkitTransition:"webkitTransitionEnd"};for(t in i)if(n.style[t]!==o)return i[t];return"transitionend"}(),f=function(t){return t&&t.length&&t[0].offsetHeight},p=function(t,o,i){var a=this;a.opts=n.extend(!0,{index:i},n.fancybox.defaults,o||{}),n.fancybox.isMobile&&(a.opts=n.extend(!0,{},a.opts,a.opts.mobile)),o&&n.isArray(o.buttons)&&(a.opts.buttons=o.buttons),a.id=a.opts.id||++c,a.group=[],a.currIndex=parseInt(a.opts.index,10)||0,a.prevIndex=null,a.prevPos=null,a.currPos=0,a.firstRun=null,a.createGroup(t),a.group.length&&(a.$lastFocus=n(e.activeElement).blur(),a.slides={},a.init())};n.extend(p.prototype,{init:function(){var i,a,s,c=this,l=c.group[c.currIndex],u=l.opts,d=n.fancybox.scrollbarWidth;c.scrollTop=r.scrollTop(),c.scrollLeft=r.scrollLeft(),n.fancybox.getInstance()||(n("body").addClass("fancybox-active"),/iPad|iPhone|iPod/.test(navigator.userAgent)&&!t.MSStream?"image"!==l.type&&n("body").css("top",n("body").scrollTop()*-1).addClass("fancybox-iosfix"):!n.fancybox.isMobile&&e.body.scrollHeight>t.innerHeight&&(d===o&&(i=n('<div style="width:50px;height:50px;overflow:scroll;" />').appendTo("body"),d=n.fancybox.scrollbarWidth=i[0].offsetWidth-i[0].clientWidth,i.remove()),n("head").append('<style id="fancybox-style-noscroll" type="text/css">.compensate-for-scrollbar { margin-right: '+d+"px; }</style>"),n("body").addClass("compensate-for-scrollbar"))),s="",n.each(u.buttons,function(t,e){s+=u.btnTpl[e]||""}),a=n(c.translate(c,u.baseTpl.replace("{{buttons}}",s).replace("{{arrows}}",u.btnTpl.arrowLeft+u.btnTpl.arrowRight))).attr("id","fancybox-container-"+c.id).addClass("fancybox-is-hidden").addClass(u.baseClass).data("FancyBox",c).appendTo(u.parentEl),c.$refs={container:a},["bg","inner","infobar","toolbar","stage","caption","navigation"].forEach(function(t){c.$refs[t]=a.find(".fancybox-"+t)}),c.trigger("onInit"),c.activate(),c.jumpTo(c.currIndex)},translate:function(t,e){var n=t.opts.i18n[t.opts.lang];return e.replace(/\{\{(\w+)\}\}/g,function(t,e){var i=n[e];return i===o?t:i})},createGroup:function(t){var e=this,i=n.makeArray(t);n.each(i,function(t,i){var a,s,r,c,l,u={},d={};n.isPlainObject(i)?(u=i,d=i.opts||i):"object"===n.type(i)&&n(i).length?(a=n(i),d=a.data(),d=n.extend({},d,d.options||{}),d.$orig=a,u.src=d.src||a.attr("href"),u.type||u.src||(u.type="inline",u.src=i)):u={type:"html",src:i+""},u.opts=n.extend(!0,{},e.opts,d),n.isArray(d.buttons)&&(u.opts.buttons=d.buttons),s=u.type||u.opts.type,c=u.src||"",!s&&c&&(c.match(/(^data:image\/[a-z0-9+\/=]*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp|svg|ico)((\?|#).*)?$)/i)?s="image":c.match(/\.(pdf)((\?|#).*)?$/i)?s="pdf":(r=c.match(/\.(mp4|mov|ogv)((\?|#).*)?$/i))?(s="video",u.opts.videoFormat||(u.opts.videoFormat="video/"+("ogv"===r[1]?"ogg":r[1]))):"#"===c.charAt(0)&&(s="inline")),s?u.type=s:e.trigger("objectNeedsType",u),u.index=e.group.length,u.opts.$orig&&!u.opts.$orig.length&&delete u.opts.$orig,!u.opts.$thumb&&u.opts.$orig&&(u.opts.$thumb=u.opts.$orig.find("img:first")),u.opts.$thumb&&!u.opts.$thumb.length&&delete u.opts.$thumb,"function"===n.type(u.opts.caption)&&(u.opts.caption=u.opts.caption.apply(i,[e,u])),"function"===n.type(e.opts.caption)&&(u.opts.caption=e.opts.caption.apply(i,[e,u])),u.opts.caption instanceof n||(u.opts.caption=u.opts.caption===o?"":u.opts.caption+""),"ajax"===s&&(l=c.split(/\s+/,2),l.length>1&&(u.src=l.shift(),u.opts.filter=l.shift())),"auto"==u.opts.smallBtn&&(n.inArray(s,["html","inline","ajax"])>-1?(u.opts.toolbar=!1,u.opts.smallBtn=!0):u.opts.smallBtn=!1),"pdf"===s&&(u.type="iframe",u.opts.iframe.preload=!1),u.opts.modal&&(u.opts=n.extend(!0,u.opts,{infobar:0,toolbar:0,smallBtn:0,keyboard:0,slideShow:0,fullScreen:0,thumbs:0,touch:0,clickContent:!1,clickSlide:!1,clickOutside:!1,dblclickContent:!1,dblclickSlide:!1,dblclickOutside:!1})),e.group.push(u)})},addEvents:function(){var o=this;o.removeEvents(),o.$refs.container.on("click.fb-close","[data-fancybox-close]",function(t){t.stopPropagation(),t.preventDefault(),o.close(t)}).on("click.fb-prev touchend.fb-prev","[data-fancybox-prev]",function(t){t.stopPropagation(),t.preventDefault(),o.previous()}).on("click.fb-next touchend.fb-next","[data-fancybox-next]",function(t){t.stopPropagation(),t.preventDefault(),o.next()}).on("click.fb","[data-fancybox-zoom]",function(t){o[o.isScaledDown()?"scaleToActual":"scaleToFit"]()}),s.on("orientationchange.fb resize.fb",function(t){t&&t.originalEvent&&"resize"===t.originalEvent.type?u(function(){o.update()}):(o.$refs.stage.hide(),setTimeout(function(){o.$refs.stage.show(),o.update()},600))}),r.on("focusin.fb",function(t){var i=n.fancybox?n.fancybox.getInstance():null;i.isClosing||!i.current||!i.current.opts.trapFocus||n(t.target).hasClass("fancybox-container")||n(t.target).is(e)||i&&"fixed"!==n(t.target).css("position")&&!i.$refs.container.has(t.target).length&&(t.stopPropagation(),i.focus(),s.scrollTop(o.scrollTop).scrollLeft(o.scrollLeft))}),r.on("keydown.fb",function(t){var e=o.current,i=t.keyCode||t.which;if(e&&e.opts.keyboard&&!n(t.target).is("input")&&!n(t.target).is("textarea"))return 8===i||27===i?(t.preventDefault(),void o.close(t)):37===i||38===i?(t.preventDefault(),void o.previous()):39===i||40===i?(t.preventDefault(),void o.next()):void o.trigger("afterKeydown",t,i)}),o.group[o.currIndex].opts.idleTime&&(o.idleSecondsCounter=0,r.on("mousemove.fb-idle mouseleave.fb-idle mousedown.fb-idle touchstart.fb-idle touchmove.fb-idle scroll.fb-idle keydown.fb-idle",function(t){o.idleSecondsCounter=0,o.isIdle&&o.showControls(),o.isIdle=!1}),o.idleInterval=t.setInterval(function(){o.idleSecondsCounter++,o.idleSecondsCounter>=o.group[o.currIndex].opts.idleTime&&!o.isDragging&&(o.isIdle=!0,o.idleSecondsCounter=0,o.hideControls())},1e3))},removeEvents:function(){var e=this;s.off("orientationchange.fb resize.fb"),r.off("focusin.fb keydown.fb .fb-idle"),this.$refs.container.off(".fb-close .fb-prev .fb-next"),e.idleInterval&&(t.clearInterval(e.idleInterval),e.idleInterval=null)},previous:function(t){return this.jumpTo(this.currPos-1,t)},next:function(t){return this.jumpTo(this.currPos+1,t)},jumpTo:function(t,e,i){var a,s,r,c,l,u,d,p=this,h=p.group.length;if(!(p.isDragging||p.isClosing||p.isAnimating&&p.firstRun)){if(t=parseInt(t,10),s=p.current?p.current.opts.loop:p.opts.loop,!s&&(t<0||t>=h))return!1;if(a=p.firstRun=null===p.firstRun,!(h<2&&!a&&p.isDragging)){if(c=p.current,p.prevIndex=p.currIndex,p.prevPos=p.currPos,r=p.createSlide(t),h>1&&((s||r.index>0)&&p.createSlide(t-1),(s||r.index<h-1)&&p.createSlide(t+1)),p.current=r,p.currIndex=r.index,p.currPos=r.pos,p.trigger("beforeShow",a),p.updateControls(),u=n.fancybox.getTranslate(r.$slide),r.isMoved=(0!==u.left||0!==u.top)&&!r.$slide.hasClass("fancybox-animated"),r.forcedDuration=o,n.isNumeric(e)?r.forcedDuration=e:e=r.opts[a?"animationDuration":"transitionDuration"],e=parseInt(e,10),a)return r.opts.animationEffect&&e&&p.$refs.container.css("transition-duration",e+"ms"),p.$refs.container.removeClass("fancybox-is-hidden"),f(p.$refs.container),p.$refs.container.addClass("fancybox-is-open"),r.$slide.addClass("fancybox-slide--current"),p.loadSlide(r),void p.preload("image");n.each(p.slides,function(t,e){n.fancybox.stop(e.$slide)}),r.$slide.removeClass("fancybox-slide--next fancybox-slide--previous").addClass("fancybox-slide--current"),r.isMoved?(l=Math.round(r.$slide.width()),n.each(p.slides,function(t,o){var i=o.pos-r.pos;n.fancybox.animate(o.$slide,{top:0,left:i*l+i*o.opts.gutter},e,function(){o.$slide.removeAttr("style").removeClass("fancybox-slide--next fancybox-slide--previous"),o.pos===p.currPos&&(r.isMoved=!1,p.complete())})})):p.$refs.stage.children().removeAttr("style"),r.isLoaded?p.revealContent(r):p.loadSlide(r),p.preload("image"),c.pos!==r.pos&&(d="fancybox-slide--"+(c.pos>r.pos?"next":"previous"),c.$slide.removeClass("fancybox-slide--complete fancybox-slide--current fancybox-slide--next fancybox-slide--previous"),c.isComplete=!1,e&&(r.isMoved||r.opts.transitionEffect)&&(r.isMoved?c.$slide.addClass(d):(d="fancybox-animated "+d+" fancybox-fx-"+r.opts.transitionEffect,n.fancybox.animate(c.$slide,d,e,function(){c.$slide.removeClass(d).removeAttr("style")}))))}}},createSlide:function(t){var e,o,i=this;return o=t%i.group.length,o=o<0?i.group.length+o:o,!i.slides[t]&&i.group[o]&&(e=n('<div class="fancybox-slide"></div>').appendTo(i.$refs.stage),i.slides[t]=n.extend(!0,{},i.group[o],{pos:t,$slide:e,isLoaded:!1}),i.updateSlide(i.slides[t])),i.slides[t]},scaleToActual:function(t,e,i){var a,s,r,c,l,u=this,d=u.current,f=d.$content,p=parseInt(d.$slide.width(),10),h=parseInt(d.$slide.height(),10),g=d.width,b=d.height;"image"!=d.type||d.hasError||!f||u.isAnimating||(n.fancybox.stop(f),u.isAnimating=!0,t=t===o?.5*p:t,e=e===o?.5*h:e,a=n.fancybox.getTranslate(f),c=g/a.width,l=b/a.height,s=.5*p-.5*g,r=.5*h-.5*b,g>p&&(s=a.left*c-(t*c-t),s>0&&(s=0),s<p-g&&(s=p-g)),b>h&&(r=a.top*l-(e*l-e),r>0&&(r=0),r<h-b&&(r=h-b)),u.updateCursor(g,b),n.fancybox.animate(f,{top:r,left:s,scaleX:c,scaleY:l},i||330,function(){u.isAnimating=!1}),u.SlideShow&&u.SlideShow.isActive&&u.SlideShow.stop())},scaleToFit:function(t){var e,o=this,i=o.current,a=i.$content;"image"!=i.type||i.hasError||!a||o.isAnimating||(n.fancybox.stop(a),o.isAnimating=!0,e=o.getFitPos(i),o.updateCursor(e.width,e.height),n.fancybox.animate(a,{top:e.top,left:e.left,scaleX:e.width/a.width(),scaleY:e.height/a.height()},t||330,function(){o.isAnimating=!1}))},getFitPos:function(t){var e,o,i,a,s,r=this,c=t.$content,l=t.width,u=t.height,d=t.opts.margin;return!(!c||!c.length||!l&&!u)&&("number"===n.type(d)&&(d=[d,d]),2==d.length&&(d=[d[0],d[1],d[0],d[1]]),e=parseInt(r.$refs.stage.width(),10)-(d[1]+d[3]),o=parseInt(r.$refs.stage.height(),10)-(d[0]+d[2]),i=Math.min(1,e/l,o/u),a=Math.floor(i*l),s=Math.floor(i*u),{top:Math.floor(.5*(o-s))+d[0],left:Math.floor(.5*(e-a))+d[3],width:a,height:s})},update:function(){var t=this;n.each(t.slides,function(e,n){t.updateSlide(n)})},updateSlide:function(t,e){var o=this,i=t&&t.$content;i&&(t.width||t.height)&&(o.isAnimating=!1,n.fancybox.stop(i),n.fancybox.setTranslate(i,o.getFitPos(t)),t.pos===o.currPos&&o.updateCursor()),t.$slide.trigger("refresh"),o.trigger("onUpdate",t)},centerSlide:function(t,e){var i,a,s=this;s.current&&(i=Math.round(t.$slide.width()),a=t.pos-s.current.pos,n.fancybox.animate(t.$slide,{top:0,left:a*i+a*t.opts.gutter,opacity:1},e===o?0:e,null,!1))},updateCursor:function(t,e){var n,i=this,a=i.$refs.container.removeClass("fancybox-is-zoomable fancybox-can-zoomIn fancybox-can-drag fancybox-can-zoomOut");i.current&&!i.isClosing&&(i.isZoomable()?(a.addClass("fancybox-is-zoomable"),n=t!==o&&e!==o?t<i.current.width&&e<i.current.height:i.isScaledDown(),n?a.addClass("fancybox-can-zoomIn"):i.current.opts.touch?a.addClass("fancybox-can-drag"):a.addClass("fancybox-can-zoomOut")):i.current.opts.touch&&a.addClass("fancybox-can-drag"))},isZoomable:function(){var t,e=this,o=e.current;if(o&&!e.isClosing)return!!("image"===o.type&&o.isLoaded&&!o.hasError&&("zoom"===o.opts.clickContent||n.isFunction(o.opts.clickContent)&&"zoom"===o.opts.clickContent(o))&&(t=e.getFitPos(o),o.width>t.width||o.height>t.height))},isScaledDown:function(){var t=this,e=t.current,o=e.$content,i=!1;return o&&(i=n.fancybox.getTranslate(o),i=i.width<e.width||i.height<e.height),i},canPan:function(){var t=this,e=t.current,n=e.$content,o=!1;return n&&(o=t.getFitPos(e),o=Math.abs(n.width()-o.width)>1||Math.abs(n.height()-o.height)>1),o},loadSlide:function(t){var e,o,i,a=this;if(!t.isLoading&&!t.isLoaded){switch(t.isLoading=!0,a.trigger("beforeLoad",t),e=t.type,o=t.$slide,o.off("refresh").trigger("onReset").addClass("fancybox-slide--"+(e||"unknown")).addClass(t.opts.slideClass),e){case"image":a.setImage(t);break;case"iframe":a.setIframe(t);break;case"html":a.setContent(t,t.src||t.content);break;case"inline":n(t.src).length?a.setContent(t,n(t.src)):a.setError(t);break;case"ajax":a.showLoading(t),i=n.ajax(n.extend({},t.opts.ajax.settings,{url:t.src,success:function(e,n){"success"===n&&a.setContent(t,e)},error:function(e,n){e&&"abort"!==n&&a.setError(t)}})),o.one("onReset",function(){i.abort()});break;case"video":a.setContent(t,'<video controls><source src="'+t.src+'" type="'+t.opts.videoFormat+"\">Your browser doesn't support HTML5 video</video>");break;default:a.setError(t)}return!0}},setImage:function(e){var o,i,a,s,r=this,c=e.opts.srcset||e.opts.image.srcset;if(c){a=t.devicePixelRatio||1,s=t.innerWidth*a,i=c.split(",").map(function(t){var e={};return t.trim().split(/\s+/).forEach(function(t,n){var o=parseInt(t.substring(0,t.length-1),10);return 0===n?e.url=t:void(o&&(e.value=o,e.postfix=t[t.length-1]))}),e}),i.sort(function(t,e){return t.value-e.value});for(var l=0;l<i.length;l++){var u=i[l];if("w"===u.postfix&&u.value>=s||"x"===u.postfix&&u.value>=a){o=u;break}}!o&&i.length&&(o=i[i.length-1]),o&&(e.src=o.url,e.width&&e.height&&"w"==o.postfix&&(e.height=e.width/e.height*o.value,e.width=o.value))}e.$content=n('<div class="fancybox-image-wrap"></div>').addClass("fancybox-is-hidden").appendTo(e.$slide),e.opts.preload!==!1&&e.opts.width&&e.opts.height&&(e.opts.thumb||e.opts.$thumb)?(e.width=e.opts.width,e.height=e.opts.height,e.$ghost=n("<img />").one("error",function(){n(this).remove(),e.$ghost=null,r.setBigImage(e)}).one("load",function(){r.afterLoad(e),r.setBigImage(e)}).addClass("fancybox-image").appendTo(e.$content).attr("src",e.opts.thumb||e.opts.$thumb.attr("src"))):r.setBigImage(e)},setBigImage:function(t){var e=this,o=n("<img />");t.$image=o.one("error",function(){e.setError(t)}).one("load",function(){clearTimeout(t.timouts),t.timouts=null,e.isClosing||(t.width=t.opts.width||this.naturalWidth,t.height=t.opts.height||this.naturalHeight,t.opts.image.srcset&&o.attr("sizes","100vw").attr("srcset",t.opts.image.srcset),e.hideLoading(t),t.$ghost?t.timouts=setTimeout(function(){t.timouts=null,t.$ghost.hide()},Math.min(300,Math.max(1e3,t.height/1600))):e.afterLoad(t))}).addClass("fancybox-image").attr("src",t.src).appendTo(t.$content),(o[0].complete||"complete"==o[0].readyState)&&o[0].naturalWidth&&o[0].naturalHeight?o.trigger("load"):o[0].error?o.trigger("error"):t.timouts=setTimeout(function(){o[0].complete||t.hasError||e.showLoading(t)},100)},setIframe:function(t){var e,i=this,a=t.opts.iframe,s=t.$slide;t.$content=n('<div class="fancybox-content'+(a.preload?" fancybox-is-hidden":"")+'"></div>').css(a.css).appendTo(s),e=n(a.tpl.replace(/\{rnd\}/g,(new Date).getTime())).attr(a.attr).appendTo(t.$content),a.preload?(i.showLoading(t),e.on("load.fb error.fb",function(e){this.isReady=1,t.$slide.trigger("refresh"),i.afterLoad(t)}),s.on("refresh.fb",function(){var n,i,s,r=t.$content,c=a.css.width,l=a.css.height;if(1===e[0].isReady){try{i=e.contents(),s=i.find("body")}catch(t){}s&&s.length&&(c===o&&(n=e[0].contentWindow.document.documentElement.scrollWidth,c=Math.ceil(s.outerWidth(!0)+(r.width()-n)),c+=r.outerWidth()-r.innerWidth()),l===o&&(l=Math.ceil(s.outerHeight(!0)),l+=r.outerHeight()-r.innerHeight()),c&&r.width(c),l&&r.height(l)),r.removeClass("fancybox-is-hidden")}})):this.afterLoad(t),e.attr("src",t.src),t.opts.smallBtn===!0&&t.$content.prepend(i.translate(t,t.opts.btnTpl.smallBtn)),s.one("onReset",function(){try{n(this).find("iframe").hide().attr("src","//about:blank")}catch(t){}n(this).empty(),t.isLoaded=!1})},setContent:function(t,e){var o=this;o.isClosing||(o.hideLoading(t),t.$slide.empty(),l(e)&&e.parent().length?(e.parent(".fancybox-slide--inline").trigger("onReset"),t.$placeholder=n("<div></div>").hide().insertAfter(e),e.css("display","inline-block")):t.hasError||("string"===n.type(e)&&(e=n("<div>").append(n.trim(e)).contents(),3===e[0].nodeType&&(e=n("<div>").html(e))),t.opts.filter&&(e=n("<div>").html(e).find(t.opts.filter))),t.$slide.one("onReset",function(){n(this).find("video,audio").trigger("pause"),t.$placeholder&&(t.$placeholder.after(e.hide()).remove(),t.$placeholder=null),t.$smallBtn&&(t.$smallBtn.remove(),t.$smallBtn=null),t.hasError||(n(this).empty(),t.isLoaded=!1)}),t.$content=n(e).appendTo(t.$slide),this.afterLoad(t))},setError:function(t){t.hasError=!0,t.$slide.removeClass("fancybox-slide--"+t.type),this.setContent(t,this.translate(t,t.opts.errorTpl))},showLoading:function(t){var e=this;t=t||e.current,t&&!t.$spinner&&(t.$spinner=n(e.opts.spinnerTpl).appendTo(t.$slide))},hideLoading:function(t){var e=this;t=t||e.current,t&&t.$spinner&&(t.$spinner.remove(),delete t.$spinner)},afterLoad:function(t){var e=this;e.isClosing||(t.isLoading=!1,t.isLoaded=!0,e.trigger("afterLoad",t),e.hideLoading(t),t.opts.smallBtn&&!t.$smallBtn&&(t.$smallBtn=n(e.translate(t,t.opts.btnTpl.smallBtn)).appendTo(t.$content.filter("div,form").first())),t.opts.protect&&t.$content&&!t.hasError&&(t.$content.on("contextmenu.fb",function(t){return 2==t.button&&t.preventDefault(),!0}),"image"===t.type&&n('<div class="fancybox-spaceball"></div>').appendTo(t.$content)),e.revealContent(t))},revealContent:function(t){var e,i,a,s,r,c=this,l=t.$slide,u=!1;return e=t.opts[c.firstRun?"animationEffect":"transitionEffect"],a=t.opts[c.firstRun?"animationDuration":"transitionDuration"],a=parseInt(t.forcedDuration===o?a:t.forcedDuration,10),!t.isMoved&&t.pos===c.currPos&&a||(e=!1),"zoom"!==e||t.pos===c.currPos&&a&&"image"===t.type&&!t.hasError&&(u=c.getThumbPos(t))||(e="fade"),"zoom"===e?(r=c.getFitPos(t),r.scaleX=r.width/u.width,r.scaleY=r.height/u.height,delete r.width,delete r.height,s=t.opts.zoomOpacity,"auto"==s&&(s=Math.abs(t.width/t.height-u.width/u.height)>.1),s&&(u.opacity=.1,r.opacity=1),n.fancybox.setTranslate(t.$content.removeClass("fancybox-is-hidden"),u),f(t.$content),void n.fancybox.animate(t.$content,r,a,function(){c.complete()})):(c.updateSlide(t),e?(n.fancybox.stop(l),i="fancybox-animated fancybox-slide--"+(t.pos>=c.prevPos?"next":"previous")+" fancybox-fx-"+e,l.removeAttr("style").removeClass("fancybox-slide--current fancybox-slide--next fancybox-slide--previous").addClass(i),t.$content.removeClass("fancybox-is-hidden"),f(l),void n.fancybox.animate(l,"fancybox-slide--current",a,function(e){l.removeClass(i).removeAttr("style"),t.pos===c.currPos&&c.complete()},!0)):(f(l),t.$content.removeClass("fancybox-is-hidden"),void(t.pos===c.currPos&&c.complete())))},getThumbPos:function(o){var i,a=this,s=!1,r=function(e){for(var o,i=e[0],a=i.getBoundingClientRect(),s=[];null!==i.parentElement;)"hidden"!==n(i.parentElement).css("overflow")&&"auto"!==n(i.parentElement).css("overflow")||s.push(i.parentElement.getBoundingClientRect()),i=i.parentElement;return o=s.every(function(t){var e=Math.min(a.right,t.right)-Math.max(a.left,t.left),n=Math.min(a.bottom,t.bottom)-Math.max(a.top,t.top);return e>0&&n>0}),o&&a.bottom>0&&a.right>0&&a.left<n(t).width()&&a.top<n(t).height()},c=o.opts.$thumb,l=c?c.offset():0;return l&&c[0].ownerDocument===e&&r(c)&&(i=a.$refs.stage.offset(),s={top:l.top-i.top+parseFloat(c.css("border-top-width")||0),left:l.left-i.left+parseFloat(c.css("border-left-width")||0),width:c.width(),height:c.height(),scaleX:1,scaleY:1}),s},complete:function(){var t=this,o=t.current,i={};o.isMoved||!o.isLoaded||o.isComplete||(o.isComplete=!0,o.$slide.siblings().trigger("onReset"),t.preload("inline"),f(o.$slide),o.$slide.addClass("fancybox-slide--complete"),n.each(t.slides,function(e,o){o.pos>=t.currPos-1&&o.pos<=t.currPos+1?i[o.pos]=o:o&&(n.fancybox.stop(o.$slide),o.$slide.off().remove())}),t.slides=i,t.updateCursor(),t.trigger("afterShow"),o.$slide.find("video,audio").first().trigger("play"),(n(e.activeElement).is("[disabled]")||o.opts.autoFocus&&"image"!=o.type&&"iframe"!==o.type)&&t.focus())},preload:function(t){var e=this,n=e.slides[e.currPos+1],o=e.slides[e.currPos-1];n&&n.type===t&&e.loadSlide(n),o&&o.type===t&&e.loadSlide(o)},focus:function(){var t,e=this.current;this.isClosing||(e&&e.isComplete&&(t=e.$slide.find("input[autofocus]:enabled:visible:first"),t.length||(t=e.$slide.find("button,:input,[tabindex],a").filter(":enabled:visible:first"))),t=t&&t.length?t:this.$refs.container,t.focus())},activate:function(){var t=this;n(".fancybox-container").each(function(){var e=n(this).data("FancyBox");e&&e.id!==t.id&&!e.isClosing&&(e.trigger("onDeactivate"),e.removeEvents(),e.isVisible=!1)}),t.isVisible=!0,(t.current||t.isIdle)&&(t.update(),t.updateControls()),t.trigger("onActivate"),t.addEvents()},close:function(t,e){var o,i,a,s,r,c,l=this,p=l.current,h=function(){l.cleanUp(t)};return!l.isClosing&&(l.isClosing=!0,l.trigger("beforeClose",t)===!1?(l.isClosing=!1,u(function(){l.update()}),!1):(l.removeEvents(),p.timouts&&clearTimeout(p.timouts),a=p.$content,o=p.opts.animationEffect,i=n.isNumeric(e)?e:o?p.opts.animationDuration:0,p.$slide.off(d).removeClass("fancybox-slide--complete fancybox-slide--next fancybox-slide--previous fancybox-animated"),p.$slide.siblings().trigger("onReset").remove(),i&&l.$refs.container.removeClass("fancybox-is-open").addClass("fancybox-is-closing"),l.hideLoading(p),l.hideControls(),l.updateCursor(),"zoom"!==o||t!==!0&&a&&i&&"image"===p.type&&!p.hasError&&(c=l.getThumbPos(p))||(o="fade"),"zoom"===o?(n.fancybox.stop(a),r=n.fancybox.getTranslate(a),r.width=r.width*r.scaleX,r.height=r.height*r.scaleY,s=p.opts.zoomOpacity,"auto"==s&&(s=Math.abs(p.width/p.height-c.width/c.height)>.1),s&&(c.opacity=0),r.scaleX=r.width/c.width,r.scaleY=r.height/c.height,r.width=c.width,r.height=c.height,n.fancybox.setTranslate(p.$content,r),f(p.$content),n.fancybox.animate(p.$content,c,i,h),!0):(o&&i?t===!0?setTimeout(h,i):n.fancybox.animate(p.$slide.removeClass("fancybox-slide--current"),"fancybox-animated fancybox-slide--previous fancybox-fx-"+o,i,h):h(),!0)))},cleanUp:function(t){var o,i,a=this,r=n("body");a.current.$slide.trigger("onReset"),a.$refs.container.empty().remove(),a.trigger("afterClose",t),a.$lastFocus&&a.current.opts.backFocus&&a.$lastFocus.focus(),a.current=null,o=n.fancybox.getInstance(),o?o.activate():(s.scrollTop(a.scrollTop).scrollLeft(a.scrollLeft),r.removeClass("fancybox-active compensate-for-scrollbar"),r.hasClass("fancybox-iosfix")&&(i=parseInt(e.body.style.top,10),r.removeClass("fancybox-iosfix").css("top","").scrollTop(i*-1)),n("#fancybox-style-noscroll").remove())},trigger:function(t,e){var o,i=Array.prototype.slice.call(arguments,1),a=this,s=e&&e.opts?e:a.current;return s?i.unshift(s):s=a,i.unshift(a),n.isFunction(s.opts[t])&&(o=s.opts[t].apply(s,i)),o===!1?o:void("afterClose"!==t&&a.$refs?a.$refs.container.trigger(t+".fb",i):r.trigger(t+".fb",i))},updateControls:function(t){var e=this,n=e.current,o=n.index,i=n.opts.caption,a=e.$refs.container,s=e.$refs.caption;n.$slide.trigger("refresh"),e.$caption=i&&i.length?s.html(i):null,e.isHiddenControls||e.isIdle||e.showControls(),a.find("[data-fancybox-count]").html(e.group.length),a.find("[data-fancybox-index]").html(o+1),a.find("[data-fancybox-prev]").prop("disabled",!n.opts.loop&&o<=0),a.find("[data-fancybox-next]").prop("disabled",!n.opts.loop&&o>=e.group.length-1),"image"===n.type?a.find("[data-fancybox-download]").attr("href",n.opts.image.src||n.src).show():a.find("[data-fancybox-download],[data-fancybox-zoom]").hide()},hideControls:function(){this.isHiddenControls=!0,this.$refs.container.removeClass("fancybox-show-infobar fancybox-show-toolbar fancybox-show-caption fancybox-show-nav")},showControls:function(){var t=this,e=t.current?t.current.opts:t.opts,n=t.$refs.container;t.isHiddenControls=!1,t.idleSecondsCounter=0,n.toggleClass("fancybox-show-toolbar",!(!e.toolbar||!e.buttons)).toggleClass("fancybox-show-infobar",!!(e.infobar&&t.group.length>1)).toggleClass("fancybox-show-nav",!!(e.arrows&&t.group.length>1)).toggleClass("fancybox-is-modal",!!e.modal),t.$caption?n.addClass("fancybox-show-caption "):n.removeClass("fancybox-show-caption")},toggleControls:function(){this.isHiddenControls?this.showControls():this.hideControls()}}),n.fancybox={version:"3.2.10",defaults:a,getInstance:function(t){var e=n('.fancybox-container:not(".fancybox-is-closing"):last').data("FancyBox"),o=Array.prototype.slice.call(arguments,1);return e instanceof p&&("string"===n.type(t)?e[t].apply(e,o):"function"===n.type(t)&&t.apply(e,o),e)},open:function(t,e,n){return new p(t,e,n)},close:function(t){var e=this.getInstance();e&&(e.close(),t===!0&&this.close())},destroy:function(){this.close(!0),r.off("click.fb-start")},isMobile:e.createTouch!==o&&/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),use3d:function(){var n=e.createElement("div");return t.getComputedStyle&&t.getComputedStyle(n).getPropertyValue("transform")&&!(e.documentMode&&e.documentMode<11)}(),getTranslate:function(t){var e;if(!t||!t.length)return!1;if(e=t.eq(0).css("transform"),e&&e.indexOf("matrix")!==-1?(e=e.split("(")[1],e=e.split(")")[0],e=e.split(",")):e=[],e.length)e=e.length>10?[e[13],e[12],e[0],e[5]]:[e[5],e[4],e[0],e[3]],e=e.map(parseFloat);else{e=[0,0,1,1];var n=/\.*translate\((.*)px,(.*)px\)/i,o=n.exec(t.eq(0).attr("style"));o&&(e[0]=parseFloat(o[2]),e[1]=parseFloat(o[1]))}return{top:e[0],left:e[1],scaleX:e[2],scaleY:e[3],opacity:parseFloat(t.css("opacity")),width:t.width(),height:t.height()}},setTranslate:function(t,e){var n="",i={};if(t&&e)return e.left===o&&e.top===o||(n=(e.left===o?t.position().left:e.left)+"px, "+(e.top===o?t.position().top:e.top)+"px",n=this.use3d?"translate3d("+n+", 0px)":"translate("+n+")"),e.scaleX!==o&&e.scaleY!==o&&(n=(n.length?n+" ":"")+"scale("+e.scaleX+", "+e.scaleY+")"),n.length&&(i.transform=n),e.opacity!==o&&(i.opacity=e.opacity),e.width!==o&&(i.width=e.width),e.height!==o&&(i.height=e.height),t.css(i)},animate:function(t,e,i,a,s){n.isFunction(i)&&(a=i,i=null),n.isPlainObject(e)||t.removeAttr("style"),t.on(d,function(i){(!i||!i.originalEvent||t.is(i.originalEvent.target)&&"z-index"!=i.originalEvent.propertyName)&&(n.fancybox.stop(t),n.isPlainObject(e)?(e.scaleX!==o&&e.scaleY!==o&&(t.css("transition-duration",""),e.width=Math.round(t.width()*e.scaleX),e.height=Math.round(t.height()*e.scaleY),e.scaleX=1,e.scaleY=1,n.fancybox.setTranslate(t,e)),s===!1&&t.removeAttr("style")):s!==!0&&t.removeClass(e),n.isFunction(a)&&a(i))}),n.isNumeric(i)&&t.css("transition-duration",i+"ms"),n.isPlainObject(e)?n.fancybox.setTranslate(t,e):t.addClass(e),e.scaleX&&t.hasClass("fancybox-image-wrap")&&t.parent().addClass("fancybox-is-scaling"),t.data("timer",setTimeout(function(){t.trigger("transitionend")},i+16))},stop:function(t){clearTimeout(t.data("timer")),t.off("transitionend").css("transition-duration",""),t.hasClass("fancybox-image-wrap")&&t.parent().removeClass("fancybox-is-scaling")}},n.fn.fancybox=function(t){var e;return t=t||{},e=t.selector||!1,e?n("body").off("click.fb-start",e).on("click.fb-start",e,{options:t},i):this.off("click.fb-start").on("click.fb-start",{items:this,options:t},i),this},r.on("click.fb-start","[data-fancybox]",i)}}(window,document,window.jQuery||jQuery),function(t){"use strict";var e=function(e,n,o){if(e)return o=o||"","object"===t.type(o)&&(o=t.param(o,!0)),t.each(n,function(t,n){e=e.replace("$"+t,n||"")}),o.length&&(e+=(e.indexOf("?")>0?"&":"?")+o),e},n={youtube:{matcher:/(youtube\.com|youtu\.be|youtube\-nocookie\.com)\/(watch\?(.*&)?v=|v\/|u\/|embed\/?)?(videoseries\?list=(.*)|[\w-]{11}|\?listType=(.*)&list=(.*))(.*)/i,params:{autoplay:1,autohide:1,fs:1,rel:0,hd:1,wmode:"transparent",enablejsapi:1,html5:1},paramPlace:8,type:"iframe",url:"//www.youtube.com/embed/$4",thumb:"//img.youtube.com/vi/$4/hqdefault.jpg"
12
- },vimeo:{matcher:/^.+vimeo.com\/(.*\/)?([\d]+)(.*)?/,params:{autoplay:1,hd:1,show_title:1,show_byline:1,show_portrait:0,fullscreen:1,api:1},paramPlace:3,type:"iframe",url:"//player.vimeo.com/video/$2"},metacafe:{matcher:/metacafe.com\/watch\/(\d+)\/(.*)?/,type:"iframe",url:"//www.metacafe.com/embed/$1/?ap=1"},dailymotion:{matcher:/dailymotion.com\/video\/(.*)\/?(.*)/,params:{additionalInfos:0,autoStart:1},type:"iframe",url:"//www.dailymotion.com/embed/video/$1"},vine:{matcher:/vine.co\/v\/([a-zA-Z0-9\?\=\-]+)/,type:"iframe",url:"//vine.co/v/$1/embed/simple"},instagram:{matcher:/(instagr\.am|instagram\.com)\/p\/([a-zA-Z0-9_\-]+)\/?/i,type:"image",url:"//$1/p/$2/media/?size=l"},gmap_place:{matcher:/(maps\.)?google\.([a-z]{2,3}(\.[a-z]{2})?)\/(((maps\/(place\/(.*)\/)?\@(.*),(\d+.?\d+?)z))|(\?ll=))(.*)?/i,type:"iframe",url:function(t){return"//maps.google."+t[2]+"/?ll="+(t[9]?t[9]+"&z="+Math.floor(t[10])+(t[12]?t[12].replace(/^\//,"&"):""):t[12])+"&output="+(t[12]&&t[12].indexOf("layer=c")>0?"svembed":"embed")}},gmap_search:{matcher:/(maps\.)?google\.([a-z]{2,3}(\.[a-z]{2})?)\/(maps\/search\/)(.*)/i,type:"iframe",url:function(t){return"//maps.google."+t[2]+"/maps?q="+t[5].replace("query=","q=").replace("api=1","")+"&output=embed"}}};t(document).on("objectNeedsType.fb",function(o,i,a){var s,r,c,l,u,d,f,p=a.src||"",h=!1;s=t.extend(!0,{},n,a.opts.media),t.each(s,function(n,o){if(c=p.match(o.matcher)){if(h=o.type,d={},o.paramPlace&&c[o.paramPlace]){u=c[o.paramPlace],"?"==u[0]&&(u=u.substring(1)),u=u.split("&");for(var i=0;i<u.length;++i){var s=u[i].split("=",2);2==s.length&&(d[s[0]]=decodeURIComponent(s[1].replace(/\+/g," ")))}}return l=t.extend(!0,{},o.params,a.opts[n],d),p="function"===t.type(o.url)?o.url.call(this,c,l,a):e(o.url,c,l),r="function"===t.type(o.thumb)?o.thumb.call(this,c,l,a):e(o.thumb,c),"vimeo"===n&&(p=p.replace("&%23","#")),!1}}),h?(a.src=p,a.type=h,a.opts.thumb||a.opts.$thumb&&a.opts.$thumb.length||(a.opts.thumb=r),"iframe"===h&&(t.extend(!0,a.opts,{iframe:{preload:!1,attr:{scrolling:"no"}}}),a.contentProvider=f,a.opts.slideClass+=" fancybox-slide--"+("gmap_place"==f||"gmap_search"==f?"map":"video"))):p&&(a.type=a.opts.defaultType)})}(window.jQuery||jQuery),function(t,e,n){"use strict";var o=function(){return t.requestAnimationFrame||t.webkitRequestAnimationFrame||t.mozRequestAnimationFrame||t.oRequestAnimationFrame||function(e){return t.setTimeout(e,1e3/60)}}(),i=function(){return t.cancelAnimationFrame||t.webkitCancelAnimationFrame||t.mozCancelAnimationFrame||t.oCancelAnimationFrame||function(e){t.clearTimeout(e)}}(),a=function(e){var n=[];e=e.originalEvent||e||t.e,e=e.touches&&e.touches.length?e.touches:e.changedTouches&&e.changedTouches.length?e.changedTouches:[e];for(var o in e)e[o].pageX?n.push({x:e[o].pageX,y:e[o].pageY}):e[o].clientX&&n.push({x:e[o].clientX,y:e[o].clientY});return n},s=function(t,e,n){return e&&t?"x"===n?t.x-e.x:"y"===n?t.y-e.y:Math.sqrt(Math.pow(t.x-e.x,2)+Math.pow(t.y-e.y,2)):0},r=function(t){if(t.is('a,area,button,[role="button"],input,label,select,summary,textarea')||n.isFunction(t.get(0).onclick)||t.data("selectable"))return!0;for(var e=0,o=t[0].attributes,i=o.length;e<i;e++)if("data-fancybox-"===o[e].nodeName.substr(0,14))return!0;return!1},c=function(e){var n=t.getComputedStyle(e)["overflow-y"],o=t.getComputedStyle(e)["overflow-x"],i=("scroll"===n||"auto"===n)&&e.scrollHeight>e.clientHeight,a=("scroll"===o||"auto"===o)&&e.scrollWidth>e.clientWidth;return i||a},l=function(t){for(var e=!1;;){if(e=c(t.get(0)))break;if(t=t.parent(),!t.length||t.hasClass("fancybox-stage")||t.is("body"))break}return e},u=function(t){var e=this;e.instance=t,e.$bg=t.$refs.bg,e.$stage=t.$refs.stage,e.$container=t.$refs.container,e.destroy(),e.$container.on("touchstart.fb.touch mousedown.fb.touch",n.proxy(e,"ontouchstart"))};u.prototype.destroy=function(){this.$container.off(".fb.touch")},u.prototype.ontouchstart=function(o){var i=this,c=n(o.target),u=i.instance,d=u.current,f=d.$content,p="touchstart"==o.type;if(p&&i.$container.off("mousedown.fb.touch"),(!o.originalEvent||2!=o.originalEvent.button)&&c.length&&!r(c)&&!r(c.parent())&&(c.is("img")||!(o.originalEvent.clientX>c[0].clientWidth+c.offset().left))){if(!d||i.instance.isAnimating||i.instance.isClosing)return o.stopPropagation(),void o.preventDefault();if(i.realPoints=i.startPoints=a(o),i.startPoints){if(o.stopPropagation(),i.startEvent=o,i.canTap=!0,i.$target=c,i.$content=f,i.opts=d.opts.touch,i.isPanning=!1,i.isSwiping=!1,i.isZooming=!1,i.isScrolling=!1,i.sliderStartPos=i.sliderLastPos||{top:0,left:0},i.contentStartPos=n.fancybox.getTranslate(i.$content),i.contentLastPos=null,i.startTime=(new Date).getTime(),i.distanceX=i.distanceY=i.distance=0,i.canvasWidth=Math.round(d.$slide[0].clientWidth),i.canvasHeight=Math.round(d.$slide[0].clientHeight),n(e).off(".fb.touch").on(p?"touchend.fb.touch touchcancel.fb.touch":"mouseup.fb.touch mouseleave.fb.touch",n.proxy(i,"ontouchend")).on(p?"touchmove.fb.touch":"mousemove.fb.touch",n.proxy(i,"ontouchmove")),n.fancybox.isMobile&&e.addEventListener("scroll",i.onscroll,!0),!i.opts&&!u.canPan()||!c.is(i.$stage)&&!i.$stage.find(c).length)return void(c.is("img")&&o.preventDefault());n.fancybox.isMobile&&(l(c)||l(c.parent()))||o.preventDefault(),1===i.startPoints.length&&("image"===d.type&&(i.contentStartPos.width>i.canvasWidth+1||i.contentStartPos.height>i.canvasHeight+1)?(n.fancybox.stop(i.$content),i.$content.css("transition-duration",""),i.isPanning=!0):i.isSwiping=!0,i.$container.addClass("fancybox-controls--isGrabbing")),2!==i.startPoints.length||u.isAnimating||d.hasError||"image"!==d.type||!d.isLoaded&&!d.$ghost||(i.canTap=!1,i.isSwiping=!1,i.isPanning=!1,i.isZooming=!0,n.fancybox.stop(i.$content),i.$content.css("transition-duration",""),i.centerPointStartX=.5*(i.startPoints[0].x+i.startPoints[1].x)-n(t).scrollLeft(),i.centerPointStartY=.5*(i.startPoints[0].y+i.startPoints[1].y)-n(t).scrollTop(),i.percentageOfImageAtPinchPointX=(i.centerPointStartX-i.contentStartPos.left)/i.contentStartPos.width,i.percentageOfImageAtPinchPointY=(i.centerPointStartY-i.contentStartPos.top)/i.contentStartPos.height,i.startDistanceBetweenFingers=s(i.startPoints[0],i.startPoints[1]))}}},u.prototype.onscroll=function(t){self.isScrolling=!0},u.prototype.ontouchmove=function(t){var e=this,o=n(t.target);return e.isScrolling||!o.is(e.$stage)&&!e.$stage.find(o).length?void(e.canTap=!1):(e.newPoints=a(t),void((e.opts||e.instance.canPan())&&e.newPoints&&e.newPoints.length&&(e.isSwiping&&e.isSwiping===!0||t.preventDefault(),e.distanceX=s(e.newPoints[0],e.startPoints[0],"x"),e.distanceY=s(e.newPoints[0],e.startPoints[0],"y"),e.distance=s(e.newPoints[0],e.startPoints[0]),e.distance>0&&(e.isSwiping?e.onSwipe(t):e.isPanning?e.onPan():e.isZooming&&e.onZoom()))))},u.prototype.onSwipe=function(e){var a,s=this,r=s.isSwiping,c=s.sliderStartPos.left||0;if(r!==!0)"x"==r&&(s.distanceX>0&&(s.instance.group.length<2||0===s.instance.current.index&&!s.instance.current.opts.loop)?c+=Math.pow(s.distanceX,.8):s.distanceX<0&&(s.instance.group.length<2||s.instance.current.index===s.instance.group.length-1&&!s.instance.current.opts.loop)?c-=Math.pow(-s.distanceX,.8):c+=s.distanceX),s.sliderLastPos={top:"x"==r?0:s.sliderStartPos.top+s.distanceY,left:c},s.requestId&&(i(s.requestId),s.requestId=null),s.requestId=o(function(){s.sliderLastPos&&(n.each(s.instance.slides,function(t,e){var o=e.pos-s.instance.currPos;n.fancybox.setTranslate(e.$slide,{top:s.sliderLastPos.top,left:s.sliderLastPos.left+o*s.canvasWidth+o*e.opts.gutter})}),s.$container.addClass("fancybox-is-sliding"))});else if(Math.abs(s.distance)>10){if(s.canTap=!1,s.instance.group.length<2&&s.opts.vertical?s.isSwiping="y":s.instance.isDragging||s.opts.vertical===!1||"auto"===s.opts.vertical&&n(t).width()>800?s.isSwiping="x":(a=Math.abs(180*Math.atan2(s.distanceY,s.distanceX)/Math.PI),s.isSwiping=a>45&&a<135?"y":"x"),s.canTap=!1,"y"===s.isSwiping&&n.fancybox.isMobile&&(l(s.$target)||l(s.$target.parent())))return void(s.isScrolling=!0);s.instance.isDragging=s.isSwiping,s.startPoints=s.newPoints,n.each(s.instance.slides,function(t,e){n.fancybox.stop(e.$slide),e.$slide.css("transition-duration",""),e.inTransition=!1,e.pos===s.instance.current.pos&&(s.sliderStartPos.left=n.fancybox.getTranslate(e.$slide).left)}),s.instance.SlideShow&&s.instance.SlideShow.isActive&&s.instance.SlideShow.stop()}},u.prototype.onPan=function(){var t=this;return s(t.newPoints[0],t.realPoints[0])<(n.fancybox.isMobile?10:5)?void(t.startPoints=t.newPoints):(t.canTap=!1,t.contentLastPos=t.limitMovement(),t.requestId&&(i(t.requestId),t.requestId=null),void(t.requestId=o(function(){n.fancybox.setTranslate(t.$content,t.contentLastPos)})))},u.prototype.limitMovement=function(){var t,e,n,o,i,a,s=this,r=s.canvasWidth,c=s.canvasHeight,l=s.distanceX,u=s.distanceY,d=s.contentStartPos,f=d.left,p=d.top,h=d.width,g=d.height;return i=h>r?f+l:f,a=p+u,t=Math.max(0,.5*r-.5*h),e=Math.max(0,.5*c-.5*g),n=Math.min(r-h,.5*r-.5*h),o=Math.min(c-g,.5*c-.5*g),h>r&&(l>0&&i>t&&(i=t-1+Math.pow(-t+f+l,.8)||0),l<0&&i<n&&(i=n+1-Math.pow(n-f-l,.8)||0)),g>c&&(u>0&&a>e&&(a=e-1+Math.pow(-e+p+u,.8)||0),u<0&&a<o&&(a=o+1-Math.pow(o-p-u,.8)||0)),{top:a,left:i,scaleX:d.scaleX,scaleY:d.scaleY}},u.prototype.limitPosition=function(t,e,n,o){var i=this,a=i.canvasWidth,s=i.canvasHeight;return n>a?(t=t>0?0:t,t=t<a-n?a-n:t):t=Math.max(0,a/2-n/2),o>s?(e=e>0?0:e,e=e<s-o?s-o:e):e=Math.max(0,s/2-o/2),{top:e,left:t}},u.prototype.onZoom=function(){var e=this,a=e.contentStartPos.width,r=e.contentStartPos.height,c=e.contentStartPos.left,l=e.contentStartPos.top,u=s(e.newPoints[0],e.newPoints[1]),d=u/e.startDistanceBetweenFingers,f=Math.floor(a*d),p=Math.floor(r*d),h=(a-f)*e.percentageOfImageAtPinchPointX,g=(r-p)*e.percentageOfImageAtPinchPointY,b=(e.newPoints[0].x+e.newPoints[1].x)/2-n(t).scrollLeft(),m=(e.newPoints[0].y+e.newPoints[1].y)/2-n(t).scrollTop(),y=b-e.centerPointStartX,v=m-e.centerPointStartY,x=c+(h+y),w=l+(g+v),$={top:w,left:x,scaleX:e.contentStartPos.scaleX*d,scaleY:e.contentStartPos.scaleY*d};e.canTap=!1,e.newWidth=f,e.newHeight=p,e.contentLastPos=$,e.requestId&&(i(e.requestId),e.requestId=null),e.requestId=o(function(){n.fancybox.setTranslate(e.$content,e.contentLastPos)})},u.prototype.ontouchend=function(t){var o=this,s=Math.max((new Date).getTime()-o.startTime,1),r=o.isSwiping,c=o.isPanning,l=o.isZooming,u=o.isScrolling;return o.endPoints=a(t),o.$container.removeClass("fancybox-controls--isGrabbing"),n(e).off(".fb.touch"),e.removeEventListener("scroll",o.onscroll,!0),o.requestId&&(i(o.requestId),o.requestId=null),o.isSwiping=!1,o.isPanning=!1,o.isZooming=!1,o.isScrolling=!1,o.instance.isDragging=!1,o.canTap?o.onTap(t):(o.speed=366,o.velocityX=o.distanceX/s*.5,o.velocityY=o.distanceY/s*.5,o.speedX=Math.max(.5*o.speed,Math.min(1.5*o.speed,1/Math.abs(o.velocityX)*o.speed)),void(c?o.endPanning():l?o.endZooming():o.endSwiping(r,u)))},u.prototype.endSwiping=function(t,e){var o=this,i=!1,a=o.instance.group.length;o.sliderLastPos=null,"y"==t&&!e&&Math.abs(o.distanceY)>50?(n.fancybox.animate(o.instance.current.$slide,{top:o.sliderStartPos.top+o.distanceY+150*o.velocityY,opacity:0},150),i=o.instance.close(!0,300)):"x"==t&&o.distanceX>50&&a>1?i=o.instance.previous(o.speedX):"x"==t&&o.distanceX<-50&&a>1&&(i=o.instance.next(o.speedX)),i!==!1||"x"!=t&&"y"!=t||(e||a<2?o.instance.centerSlide(o.instance.current,150):o.instance.jumpTo(o.instance.current.index)),o.$container.removeClass("fancybox-is-sliding")},u.prototype.endPanning=function(){var t,e,o,i=this;i.contentLastPos&&(i.opts.momentum===!1?(t=i.contentLastPos.left,e=i.contentLastPos.top):(t=i.contentLastPos.left+i.velocityX*i.speed,e=i.contentLastPos.top+i.velocityY*i.speed),o=i.limitPosition(t,e,i.contentStartPos.width,i.contentStartPos.height),o.width=i.contentStartPos.width,o.height=i.contentStartPos.height,n.fancybox.animate(i.$content,o,330))},u.prototype.endZooming=function(){var t,e,o,i,a=this,s=a.instance.current,r=a.newWidth,c=a.newHeight;a.contentLastPos&&(t=a.contentLastPos.left,e=a.contentLastPos.top,i={top:e,left:t,width:r,height:c,scaleX:1,scaleY:1},n.fancybox.setTranslate(a.$content,i),r<a.canvasWidth&&c<a.canvasHeight?a.instance.scaleToFit(150):r>s.width||c>s.height?a.instance.scaleToActual(a.centerPointStartX,a.centerPointStartY,150):(o=a.limitPosition(t,e,r,c),n.fancybox.setTranslate(a.content,n.fancybox.getTranslate(a.$content)),n.fancybox.animate(a.$content,o,150)))},u.prototype.onTap=function(t){var e,o=this,i=n(t.target),s=o.instance,r=s.current,c=t&&a(t)||o.startPoints,l=c[0]?c[0].x-o.$stage.offset().left:0,u=c[0]?c[0].y-o.$stage.offset().top:0,d=function(e){var i=r.opts[e];if(n.isFunction(i)&&(i=i.apply(s,[r,t])),i)switch(i){case"close":s.close(o.startEvent);break;case"toggleControls":s.toggleControls(!0);break;case"next":s.next();break;case"nextOrClose":s.group.length>1?s.next():s.close(o.startEvent);break;case"zoom":"image"==r.type&&(r.isLoaded||r.$ghost)&&(s.canPan()?s.scaleToFit():s.isScaledDown()?s.scaleToActual(l,u):s.group.length<2&&s.close(o.startEvent))}};if((!t.originalEvent||2!=t.originalEvent.button)&&(i.is("img")||!(l>i[0].clientWidth+i.offset().left))){if(i.is(".fancybox-bg,.fancybox-inner,.fancybox-outer,.fancybox-container"))e="Outside";else if(i.is(".fancybox-slide"))e="Slide";else{if(!s.current.$content||!s.current.$content.find(i).addBack().filter(i).length)return;e="Content"}if(o.tapped){if(clearTimeout(o.tapped),o.tapped=null,Math.abs(l-o.tapX)>50||Math.abs(u-o.tapY)>50)return this;d("dblclick"+e)}else o.tapX=l,o.tapY=u,r.opts["dblclick"+e]&&r.opts["dblclick"+e]!==r.opts["click"+e]?o.tapped=setTimeout(function(){o.tapped=null,d("click"+e)},500):d("click"+e);return this}},n(e).on("onActivate.fb",function(t,e){e&&!e.Guestures&&(e.Guestures=new u(e))})}(window,document,window.jQuery||jQuery),function(t,e){"use strict";e.extend(!0,e.fancybox.defaults,{btnTpl:{slideShow:'<button data-fancybox-play class="fancybox-button fancybox-button--play" title="{{PLAY_START}}"><svg viewBox="0 0 40 40"><path d="M13,12 L27,20 L13,27 Z" /><path d="M15,10 v19 M23,10 v19" /></svg></button>'},slideShow:{autoStart:!1,speed:3e3}});var n=function(t){this.instance=t,this.init()};e.extend(n.prototype,{timer:null,isActive:!1,$button:null,init:function(){var t=this;t.$button=t.instance.$refs.toolbar.find("[data-fancybox-play]").on("click",function(){t.toggle()}),(t.instance.group.length<2||!t.instance.group[t.instance.currIndex].opts.slideShow)&&t.$button.hide()},set:function(t){var e=this;e.instance&&e.instance.current&&(t===!0||e.instance.current.opts.loop||e.instance.currIndex<e.instance.group.length-1)?e.timer=setTimeout(function(){e.isActive&&e.instance.jumpTo((e.instance.currIndex+1)%e.instance.group.length)},e.instance.current.opts.slideShow.speed):(e.stop(),e.instance.idleSecondsCounter=0,e.instance.showControls())},clear:function(){var t=this;clearTimeout(t.timer),t.timer=null},start:function(){var t=this,e=t.instance.current;e&&(t.isActive=!0,t.$button.attr("title",e.opts.i18n[e.opts.lang].PLAY_STOP).removeClass("fancybox-button--play").addClass("fancybox-button--pause"),t.set(!0))},stop:function(){var t=this,e=t.instance.current;t.clear(),t.$button.attr("title",e.opts.i18n[e.opts.lang].PLAY_START).removeClass("fancybox-button--pause").addClass("fancybox-button--play"),t.isActive=!1},toggle:function(){var t=this;t.isActive?t.stop():t.start()}}),e(t).on({"onInit.fb":function(t,e){e&&!e.SlideShow&&(e.SlideShow=new n(e))},"beforeShow.fb":function(t,e,n,o){var i=e&&e.SlideShow;o?i&&n.opts.slideShow.autoStart&&i.start():i&&i.isActive&&i.clear()},"afterShow.fb":function(t,e,n){var o=e&&e.SlideShow;o&&o.isActive&&o.set()},"afterKeydown.fb":function(n,o,i,a,s){var r=o&&o.SlideShow;!r||!i.opts.slideShow||80!==s&&32!==s||e(t.activeElement).is("button,a,input")||(a.preventDefault(),r.toggle())},"beforeClose.fb onDeactivate.fb":function(t,e){var n=e&&e.SlideShow;n&&n.stop()}}),e(t).on("visibilitychange",function(){var n=e.fancybox.getInstance(),o=n&&n.SlideShow;o&&o.isActive&&(t.hidden?o.clear():o.set())})}(document,window.jQuery||jQuery),function(t,e){"use strict";var n=function(){var e,n,o,i=[["requestFullscreen","exitFullscreen","fullscreenElement","fullscreenEnabled","fullscreenchange","fullscreenerror"],["webkitRequestFullscreen","webkitExitFullscreen","webkitFullscreenElement","webkitFullscreenEnabled","webkitfullscreenchange","webkitfullscreenerror"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitCurrentFullScreenElement","webkitCancelFullScreen","webkitfullscreenchange","webkitfullscreenerror"],["mozRequestFullScreen","mozCancelFullScreen","mozFullScreenElement","mozFullScreenEnabled","mozfullscreenchange","mozfullscreenerror"],["msRequestFullscreen","msExitFullscreen","msFullscreenElement","msFullscreenEnabled","MSFullscreenChange","MSFullscreenError"]],a={};for(n=0;n<i.length;n++)if(e=i[n],e&&e[1]in t){for(o=0;o<e.length;o++)a[i[0][o]]=e[o];return a}return!1}();if(!n)return void(e&&e.fancybox&&(e.fancybox.defaults.btnTpl.fullScreen=!1));var o={request:function(e){e=e||t.documentElement,e[n.requestFullscreen](e.ALLOW_KEYBOARD_INPUT)},exit:function(){t[n.exitFullscreen]()},toggle:function(e){e=e||t.documentElement,this.isFullscreen()?this.exit():this.request(e)},isFullscreen:function(){return Boolean(t[n.fullscreenElement])},enabled:function(){return Boolean(t[n.fullscreenEnabled])}};e.extend(!0,e.fancybox.defaults,{btnTpl:{fullScreen:'<button data-fancybox-fullscreen class="fancybox-button fancybox-button--fullscreen" title="{{FULL_SCREEN}}"><svg viewBox="0 0 40 40"><path d="M9,12 h22 v16 h-22 v-16 v16 h22 v-16 Z" /></svg></button>'},fullScreen:{autoStart:!1}}),e(t).on({"onInit.fb":function(t,e){var n;e&&e.group[e.currIndex].opts.fullScreen?(n=e.$refs.container,n.on("click.fb-fullscreen","[data-fancybox-fullscreen]",function(t){t.stopPropagation(),t.preventDefault(),o.toggle(n[0])}),e.opts.fullScreen&&e.opts.fullScreen.autoStart===!0&&o.request(n[0]),e.FullScreen=o):e&&e.$refs.toolbar.find("[data-fancybox-fullscreen]").hide()},"afterKeydown.fb":function(t,e,n,o,i){e&&e.FullScreen&&70===i&&(o.preventDefault(),e.FullScreen.toggle(e.$refs.container[0]))},"beforeClose.fb":function(t){t&&t.FullScreen&&o.exit()}}),e(t).on(n.fullscreenchange,function(){var t=o.isFullscreen(),n=e.fancybox.getInstance();n&&(n.current&&"image"===n.current.type&&n.isAnimating&&(n.current.$content.css("transition","none"),n.isAnimating=!1,n.update(!0,!0,0)),n.trigger("onFullscreenChange",t),n.$refs.container.toggleClass("fancybox-is-fullscreen",t))})}(document,window.jQuery||jQuery),function(t,e){"use strict";e.fancybox.defaults=e.extend(!0,{btnTpl:{thumbs:'<button data-fancybox-thumbs class="fancybox-button fancybox-button--thumbs" title="{{THUMBS}}"><svg viewBox="0 0 120 120"><path d="M30,30 h14 v14 h-14 Z M50,30 h14 v14 h-14 Z M70,30 h14 v14 h-14 Z M30,50 h14 v14 h-14 Z M50,50 h14 v14 h-14 Z M70,50 h14 v14 h-14 Z M30,70 h14 v14 h-14 Z M50,70 h14 v14 h-14 Z M70,70 h14 v14 h-14 Z" /></svg></button>'},thumbs:{autoStart:!1,hideOnClose:!0,parentEl:".fancybox-container",axis:"y"}},e.fancybox.defaults);var n=function(t){this.init(t)};e.extend(n.prototype,{$button:null,$grid:null,$list:null,isVisible:!1,isActive:!1,init:function(t){var e=this;e.instance=t,t.Thumbs=e;var n=t.group[0],o=t.group[1];e.opts=t.group[t.currIndex].opts.thumbs,e.$button=t.$refs.toolbar.find("[data-fancybox-thumbs]"),e.opts&&n&&o&&("image"==n.type||n.opts.thumb||n.opts.$thumb)&&("image"==o.type||o.opts.thumb||o.opts.$thumb)?(e.$button.show().on("click",function(){e.toggle()}),e.isActive=!0):e.$button.hide()},create:function(){var t,n,o=this,i=o.instance,a=o.opts.parentEl;o.$grid=e('<div class="fancybox-thumbs fancybox-thumbs-'+o.opts.axis+'"></div>').appendTo(i.$refs.container.find(a).addBack().filter(a)),t="<ul>",e.each(i.group,function(e,o){n=o.opts.thumb||(o.opts.$thumb?o.opts.$thumb.attr("src"):null),n||"image"!==o.type||(n=o.src),n&&n.length&&(t+='<li data-index="'+e+'" tabindex="0" class="fancybox-thumbs-loading"><img data-src="'+n+'" /></li>')}),t+="</ul>",o.$list=e(t).appendTo(o.$grid).on("click","li",function(){i.jumpTo(e(this).data("index"))}),o.$list.find("img").hide().one("load",function(){var t,n,o,i,a=e(this).parent().removeClass("fancybox-thumbs-loading"),s=a.outerWidth(),r=a.outerHeight();t=this.naturalWidth||this.width,n=this.naturalHeight||this.height,o=t/s,i=n/r,o>=1&&i>=1&&(o>i?(t/=i,n=r):(t=s,n/=o)),e(this).css({width:Math.floor(t),height:Math.floor(n),"margin-top":n>r?Math.floor(.3*r-.3*n):Math.floor(.5*r-.5*n),"margin-left":Math.floor(.5*s-.5*t)}).show()}).each(function(){this.src=e(this).data("src")}),"x"===o.opts.axis&&o.$list.width(parseInt(o.$grid.css("padding-right"))+i.group.length*o.$list.children().eq(0).outerWidth(!0)+"px")},focus:function(t){var e,n,o=this,i=o.$list;o.instance.current&&(e=i.children().removeClass("fancybox-thumbs-active").filter('[data-index="'+o.instance.current.index+'"]').addClass("fancybox-thumbs-active"),n=e.position(),"y"===o.opts.axis&&(n.top<0||n.top>i.height()-e.outerHeight())?i.stop().animate({scrollTop:i.scrollTop()+n.top},t):"x"===o.opts.axis&&(n.left<i.parent().scrollLeft()||n.left>i.parent().scrollLeft()+(i.parent().width()-e.outerWidth()))&&i.parent().stop().animate({scrollLeft:n.left},t))},update:function(){this.instance.$refs.container.toggleClass("fancybox-show-thumbs",this.isVisible),this.isVisible?(this.$grid||this.create(),this.instance.trigger("onThumbsShow"),this.focus(0)):this.$grid&&this.instance.trigger("onThumbsHide"),this.instance.update()},hide:function(){this.isVisible=!1,this.update()},show:function(){this.isVisible=!0,this.update()},toggle:function(){this.isVisible=!this.isVisible,this.update()}}),e(t).on({"onInit.fb":function(t,e){var o;e&&!e.Thumbs&&(o=new n(e),o.isActive&&o.opts.autoStart===!0&&o.show())},"beforeShow.fb":function(t,e,n,o){var i=e&&e.Thumbs;i&&i.isVisible&&i.focus(o?0:250)},"afterKeydown.fb":function(t,e,n,o,i){var a=e&&e.Thumbs;a&&a.isActive&&71===i&&(o.preventDefault(),a.toggle())},"beforeClose.fb":function(t,e){var n=e&&e.Thumbs;n&&n.isVisible&&n.opts.hideOnClose!==!1&&n.$grid.hide()}})}(document,window.jQuery),function(t,e){"use strict";function n(t){var e={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;","`":"&#x60;","=":"&#x3D;"};return String(t).replace(/[&<>"'`=\/]/g,function(t){return e[t]})}e.extend(!0,e.fancybox.defaults,{btnTpl:{share:'<button data-fancybox-share class="fancybox-button fancybox-button--share" title="{{SHARE}}"><svg viewBox="0 0 40 40"><path d="M6,30 C8,18 19,16 23,16 L23,16 L23,10 L33,20 L23,29 L23,24 C19,24 8,27 6,30 Z"></svg></button>'},share:{tpl:'<div class="fancybox-share"><h1>{{SHARE}}</h1><p class="fancybox-share__links"><a class="fancybox-share__button fancybox-share__button--fb" href="https://www.facebook.com/sharer/sharer.php?u={{url}}"><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="m287 456v-299c0-21 6-35 35-35h38v-63c-7-1-29-3-55-3-54 0-91 33-91 94v306m143-254h-205v72h196" /></svg><span>Facebook</span></a><a class="fancybox-share__button fancybox-share__button--pt" href="https://www.pinterest.com/pin/create/button/?url={{url}}&description={{descr}}&media={{media}}"><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="m265 56c-109 0-164 78-164 144 0 39 15 74 47 87 5 2 10 0 12-5l4-19c2-6 1-8-3-13-9-11-15-25-15-45 0-58 43-110 113-110 62 0 96 38 96 88 0 67-30 122-73 122-24 0-42-19-36-44 6-29 20-60 20-81 0-19-10-35-31-35-25 0-44 26-44 60 0 21 7 36 7 36l-30 125c-8 37-1 83 0 87 0 3 4 4 5 2 2-3 32-39 42-75l16-64c8 16 31 29 56 29 74 0 124-67 124-157 0-69-58-132-146-132z" fill="#fff"/></svg><span>Pinterest</span></a><a class="fancybox-share__button fancybox-share__button--tw" href="https://twitter.com/intent/tweet?url={{url}}&text={{descr}}"><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="m456 133c-14 7-31 11-47 13 17-10 30-27 37-46-15 10-34 16-52 20-61-62-157-7-141 75-68-3-129-35-169-85-22 37-11 86 26 109-13 0-26-4-37-9 0 39 28 72 65 80-12 3-25 4-37 2 10 33 41 57 77 57-42 30-77 38-122 34 170 111 378-32 359-208 16-11 30-25 41-42z" /></svg><span>Twitter</span></a></p><p><input class="fancybox-share__input" type="text" value="{{url_raw}}" /></p></div>'}}),e(t).on("click","[data-fancybox-share]",function(){var t,o,i=e.fancybox.getInstance();i&&(t=i.current.opts.hash===!1?i.current.src:window.location,o=i.current.opts.share.tpl.replace(/\{\{media\}\}/g,"image"===i.current.type?encodeURIComponent(i.current.src):"").replace(/\{\{url\}\}/g,encodeURIComponent(t)).replace(/\{\{url_raw\}\}/g,n(t)).replace(/\{\{descr\}\}/g,i.$caption?encodeURIComponent(i.$caption.text()):""),e.fancybox.open({src:i.translate(i,o),type:"html",opts:{animationEffect:"fade",animationDuration:250,afterLoad:function(t,e){e.$content.find(".fancybox-share__links a").click(function(){return window.open(this.href,"Share","width=550, height=450"),!1})}}}))})}(document,window.jQuery||jQuery),function(t,e,n){"use strict";function o(){var t=e.location.hash.substr(1),n=t.split("-"),o=n.length>1&&/^\+?\d+$/.test(n[n.length-1])?parseInt(n.pop(-1),10)||1:1,i=n.join("-");return o<1&&(o=1),{hash:t,index:o,gallery:i}}function i(t){var e;""!==t.gallery&&(e=n("[data-fancybox='"+n.escapeSelector(t.gallery)+"']").eq(t.index-1),e.length||(e=n("#"+n.escapeSelector(t.gallery))),e.length&&(s=!1,e.trigger("click")))}function a(t){var e;return!!t&&(e=t.current?t.current.opts:t.opts,e.hash||(e.$orig?e.$orig.data("fancybox"):""))}n.escapeSelector||(n.escapeSelector=function(t){var e=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g,n=function(t,e){return e?"\0"===t?"�":t.slice(0,-1)+"\\"+t.charCodeAt(t.length-1).toString(16)+" ":"\\"+t};return(t+"").replace(e,n)});var s=!0,r=null,c=null;n(function(){n.fancybox.defaults.hash!==!1&&(n(t).on({"onInit.fb":function(t,e){var n,i;e.group[e.currIndex].opts.hash!==!1&&(n=o(),i=a(e),i&&n.gallery&&i==n.gallery&&(e.currIndex=n.index-1))},"beforeShow.fb":function(n,o,i){var l;i&&i.opts.hash!==!1&&(l=a(o),l&&""!==l&&(e.location.hash.indexOf(l)<0&&(o.opts.origHash=e.location.hash),r=l+(o.group.length>1?"-"+(i.index+1):""),"replaceState"in e.history?(c&&clearTimeout(c),c=setTimeout(function(){e.history[s?"pushState":"replaceState"]({},t.title,e.location.pathname+e.location.search+"#"+r),c=null,s=!1},300)):e.location.hash=r))},"beforeClose.fb":function(o,i,s){var l,u;c&&clearTimeout(c),s.opts.hash!==!1&&(l=a(i),u=i&&i.opts.origHash?i.opts.origHash:"",l&&""!==l&&("replaceState"in history?e.history.replaceState({},t.title,e.location.pathname+e.location.search+u):(e.location.hash=u,n(e).scrollTop(i.scrollTop).scrollLeft(i.scrollLeft))),r=null)}}),n(e).on("hashchange.fb",function(){var t=o();n.fancybox.getInstance()?!r||r===t.gallery+"-"+t.index||1===t.index&&r==t.gallery||(r=null,n.fancybox.close()):""!==t.gallery&&i(t)}),setTimeout(function(){i(o())},50))})}(document,window,window.jQuery||jQuery),function(t,e){"use strict";var n=(new Date).getTime();e(t).on({"onInit.fb":function(t,e,o){e.$refs.stage.on("mousewheel DOMMouseScroll wheel MozMousePixelScroll",function(t){var o=e.current,i=(new Date).getTime();e.group.length<1||o.opts.wheel===!1||"auto"===o.opts.wheel&&"image"!==o.type||(t.preventDefault(),t.stopPropagation(),o.$slide.hasClass("fancybox-animated")||(t=t.originalEvent||t,i-n<250||(n=i,e[(-t.deltaY||-t.deltaX||t.wheelDelta||-t.detail)<0?"next":"previous"]())))})}})}(document,window.jQuery||jQuery);
 
 
 
 
 
 
 
 
 
 
 
 
resources/js/jquery.steps.min.js DELETED
@@ -1,6 +0,0 @@
1
- /*!
2
- * jQuery Steps v1.1.0 - 09/04/2014
3
- * Copyright (c) 2014 Rafael Staib (http://www.jquery-steps.com)
4
- * Licensed under MIT http://www.opensource.org/licenses/MIT
5
- */
6
- !function(a,b){function c(a,b){o(a).push(b)}function d(d,e,f){var g=d.children(e.headerTag),h=d.children(e.bodyTag);g.length>h.length?R(Z,"contents"):g.length<h.length&&R(Z,"titles");var i=e.startIndex;if(f.stepCount=g.length,e.saveState&&a.cookie){var j=a.cookie(U+q(d)),k=parseInt(j,0);!isNaN(k)&&k<f.stepCount&&(i=k)}f.currentIndex=i,g.each(function(e){var f=a(this),g=h.eq(e),i=g.data("mode"),j=null==i?$.html:r($,/^\s*$/.test(i)||isNaN(i)?i:parseInt(i,0)),k=j===$.html||g.data("url")===b?"":g.data("url"),l=j!==$.html&&"1"===g.data("loaded"),m=a.extend({},bb,{title:f.html(),content:j===$.html?g.html():"",contentUrl:k,contentMode:j,contentLoaded:l});c(d,m)})}function e(a){a.triggerHandler("canceled")}function f(a,b){return a.currentIndex-b}function g(b,c){var d=i(b);b.unbind(d).removeData("uid").removeData("options").removeData("state").removeData("steps").removeData("eventNamespace").find(".actions a").unbind(d),b.removeClass(c.clearFixCssClass+" vertical");var e=b.find(".content > *");e.removeData("loaded").removeData("mode").removeData("url"),e.removeAttr("id").removeAttr("role").removeAttr("tabindex").removeAttr("class").removeAttr("style")._removeAria("labelledby")._removeAria("hidden"),b.find(".content > [data-mode='async'],.content > [data-mode='iframe']").empty();var f=a('<{0} class="{1}"></{0}>'.format(b.get(0).tagName,b.attr("class"))),g=b._id();return null!=g&&""!==g&&f._id(g),f.html(b.find(".content").html()),b.after(f),b.remove(),f}function h(a,b){var c=a.find(".steps li").eq(b.currentIndex);a.triggerHandler("finishing",[b.currentIndex])?(c.addClass("done").removeClass("error"),a.triggerHandler("finished",[b.currentIndex])):c.addClass("error")}function i(a){var b=a.data("eventNamespace");return null==b&&(b="."+q(a),a.data("eventNamespace",b)),b}function j(a,b){var c=q(a);return a.find("#"+c+V+b)}function k(a,b){var c=q(a);return a.find("#"+c+W+b)}function l(a,b){var c=q(a);return a.find("#"+c+X+b)}function m(a){return a.data("options")}function n(a){return a.data("state")}function o(a){return a.data("steps")}function p(a,b){var c=o(a);return(0>b||b>=c.length)&&R(Y),c[b]}function q(a){var b=a.data("uid");return null==b&&(b=a._id(),null==b&&(b="steps-uid-".concat(T),a._id(b)),T++,a.data("uid",b)),b}function r(a,c){if(S("enumType",a),S("keyOrValue",c),"string"==typeof c){var d=a[c];return d===b&&R("The enum key '{0}' does not exist.",c),d}if("number"==typeof c){for(var e in a)if(a[e]===c)return c;R("Invalid enum value '{0}'.",c)}else R("Invalid key or value type.")}function s(a,b,c){return B(a,b,c,v(c,1))}function t(a,b,c){return B(a,b,c,f(c,1))}function u(a,b,c,d){if((0>d||d>=c.stepCount)&&R(Y),!(b.forceMoveForward&&d<c.currentIndex)){var e=c.currentIndex;return a.triggerHandler("stepChanging",[c.currentIndex,d])?(c.currentIndex=d,O(a,b,c),E(a,b,c,e),D(a,b,c),A(a,b,c),P(a,b,c,d,e,function(){a.triggerHandler("stepChanged",[d,e])})):a.find(".steps li").eq(e).addClass("error"),!0}}function v(a,b){return a.currentIndex+b}function w(b){var c=a.extend(!0,{},cb,b);return this.each(function(){var b=a(this),e={currentIndex:c.startIndex,currentStep:null,stepCount:0,transitionElement:null};b.data("options",c),b.data("state",e),b.data("steps",[]),d(b,c,e),J(b,c,e),G(b,c),c.autoFocus&&0===T&&j(b,c.startIndex).focus(),b.triggerHandler("init",[c.startIndex])})}function x(b,c,d,e,f){(0>e||e>d.stepCount)&&R(Y),f=a.extend({},bb,f),y(b,e,f),d.currentIndex!==d.stepCount&&d.currentIndex>=e&&(d.currentIndex++,O(b,c,d)),d.stepCount++;var g=b.find(".content"),h=a("<{0}>{1}</{0}>".format(c.headerTag,f.title)),i=a("<{0}></{0}>".format(c.bodyTag));return(null==f.contentMode||f.contentMode===$.html)&&i.html(f.content),0===e?g.prepend(i).prepend(h):k(b,e-1).after(i).after(h),K(b,d,i,e),N(b,c,d,h,e),F(b,c,d,e),e===d.currentIndex&&E(b,c,d),D(b,c,d),b}function y(a,b,c){o(a).splice(b,0,c)}function z(b){var c=a(this),d=m(c),e=n(c);if(d.suppressPaginationOnFocus&&c.find(":focus").is(":input"))return b.preventDefault(),!1;var f={left:37,right:39};b.keyCode===f.left?(b.preventDefault(),t(c,d,e)):b.keyCode===f.right&&(b.preventDefault(),s(c,d,e))}function A(b,c,d){if(d.stepCount>0){var e=d.currentIndex,f=p(b,e);if(!c.enableContentCache||!f.contentLoaded)switch(r($,f.contentMode)){case $.iframe:b.find(".content > .body").eq(d.currentIndex).empty().html('<iframe src="'+f.contentUrl+'" frameborder="0" scrolling="no" />').data("loaded","1");break;case $.async:var g=k(b,e)._aria("busy","true").empty().append(M(c.loadingTemplate,{text:c.labels.loading}));a.ajax({url:f.contentUrl,cache:!1}).done(function(a){g.empty().html(a)._aria("busy","false").data("loaded","1"),b.triggerHandler("contentLoaded",[e])})}}}function B(a,b,c,d){var e=c.currentIndex;if(d>=0&&d<c.stepCount&&!(b.forceMoveForward&&d<c.currentIndex)){var f=j(a,d),g=f.parent(),h=g.hasClass("disabled");return g._enableAria(),f.click(),e===c.currentIndex&&h?(g._enableAria(!1),!1):!0}return!1}function C(b){b.preventDefault();var c=a(this),d=c.parent().parent().parent().parent(),f=m(d),g=n(d),i=c.attr("href");switch(i.substring(i.lastIndexOf("#")+1)){case"cancel":e(d);break;case"finish":h(d,g);break;case"next":s(d,f,g);break;case"previous":t(d,f,g)}}function D(a,b,c){if(b.enablePagination){var d=a.find(".actions a[href$='#finish']").parent(),e=a.find(".actions a[href$='#next']").parent();if(!b.forceMoveForward){var f=a.find(".actions a[href$='#previous']").parent();f._enableAria(c.currentIndex>0)}b.enableFinishButton&&b.showFinishButtonAlways?(d._enableAria(c.stepCount>0),e._enableAria(c.stepCount>1&&c.stepCount>c.currentIndex+1)):(d._showAria(b.enableFinishButton&&c.stepCount===c.currentIndex+1),e._showAria(0===c.stepCount||c.stepCount>c.currentIndex+1)._enableAria(c.stepCount>c.currentIndex+1||!b.enableFinishButton))}}function E(b,c,d,e){var f=j(b,d.currentIndex),g=a('<span class="current-info audible">'+c.labels.current+" </span>"),h=b.find(".content > .title");if(null!=e){var i=j(b,e);i.parent().addClass("done").removeClass("error")._selectAria(!1),h.eq(e).removeClass("current").next(".body").removeClass("current"),g=i.find(".current-info"),f.focus()}f.prepend(g).parent()._selectAria().removeClass("done")._enableAria(),h.eq(d.currentIndex).addClass("current").next(".body").addClass("current")}function F(a,b,c,d){for(var e=q(a),f=d;f<c.stepCount;f++){var g=e+V+f,h=e+W+f,i=e+X+f,j=a.find(".title").eq(f)._id(i);a.find(".steps a").eq(f)._id(g)._aria("controls",h).attr("href","#"+i).html(M(b.titleTemplate,{index:f+1,title:j.html()})),a.find(".body").eq(f)._id(h)._aria("labelledby",i)}}function G(a,b){var c=i(a);a.bind("canceled"+c,b.onCanceled),a.bind("contentLoaded"+c,b.onContentLoaded),a.bind("finishing"+c,b.onFinishing),a.bind("finished"+c,b.onFinished),a.bind("init"+c,b.onInit),a.bind("stepChanging"+c,b.onStepChanging),a.bind("stepChanged"+c,b.onStepChanged),b.enableKeyNavigation&&a.bind("keyup"+c,z),a.find(".actions a").bind("click"+c,C)}function H(a,b,c,d){return 0>d||d>=c.stepCount||c.currentIndex===d?!1:(I(a,d),c.currentIndex>d&&(c.currentIndex--,O(a,b,c)),c.stepCount--,l(a,d).remove(),k(a,d).remove(),j(a,d).parent().remove(),0===d&&a.find(".steps li").first().addClass("first"),d===c.stepCount&&a.find(".steps li").eq(d).addClass("last"),F(a,b,c,d),D(a,b,c),!0)}function I(a,b){o(a).splice(b,1)}function J(b,c,d){var e='<{0} class="{1}">{2}</{0}>',f=r(_,c.stepsOrientation),g=f===_.vertical?" vertical":"",h=a(e.format(c.contentContainerTag,"content "+c.clearFixCssClass,b.html())),i=a(e.format(c.stepsContainerTag,"steps "+c.clearFixCssClass,'<ul role="tablist"></ul>')),j=h.children(c.headerTag),k=h.children(c.bodyTag);b.attr("role","application").empty().append(i).append(h).addClass(c.cssClass+" "+c.clearFixCssClass+g),k.each(function(c){K(b,d,a(this),c)}),j.each(function(e){N(b,c,d,a(this),e)}),E(b,c,d),L(b,c,d)}function K(a,b,c,d){var e=q(a),f=e+W+d,g=e+X+d;c._id(f).attr("role","tabpanel")._aria("labelledby",g).addClass("body")._showAria(b.currentIndex===d)}function L(a,b,c){if(b.enablePagination){var d='<{0} class="actions {1}"><ul role="menu" aria-label="{2}">{3}</ul></{0}>',e='<li><a href="#{0}" role="menuitem">{1}</a></li>',f="";b.forceMoveForward||(f+=e.format("previous",b.labels.previous)),f+=e.format("next",b.labels.next),b.enableFinishButton&&(f+=e.format("finish",b.labels.finish)),b.enableCancelButton&&(f+=e.format("cancel",b.labels.cancel)),a.append(d.format(b.actionContainerTag,b.clearFixCssClass,b.labels.pagination,f)),D(a,b,c),A(a,b,c)}}function M(a,c){for(var d=a.match(/#([a-z]*)#/gi),e=0;e<d.length;e++){var f=d[e],g=f.substring(1,f.length-1);c[g]===b&&R("The key '{0}' does not exist in the substitute collection!",g),a=a.replace(f,c[g])}return a}function N(b,c,d,e,f){var g=q(b),h=g+V+f,j=g+W+f,k=g+X+f,l=b.find(".steps > ul"),m=M(c.titleTemplate,{index:f+1,title:e.html()}),n=a('<li role="tab"><a id="'+h+'" href="#'+k+'" aria-controls="'+j+'">'+m+"</a></li>");n._enableAria(c.enableAllSteps||d.currentIndex>f),d.currentIndex>f&&n.addClass("done"),e._id(k).attr("tabindex","-1").addClass("title"),0===f?l.prepend(n):l.find("li").eq(f-1).after(n),0===f&&l.find("li").removeClass("first").eq(f).addClass("first"),f===d.stepCount-1&&l.find("li").removeClass("last").eq(f).addClass("last"),n.children("a").bind("click"+i(b),Q)}function O(b,c,d){c.saveState&&a.cookie&&a.cookie(U+q(b),d.currentIndex)}function P(b,c,d,e,f,g){var h=b.find(".content > .body"),i=r(ab,c.transitionEffect),j=c.transitionEffectSpeed,k=h.eq(e),l=h.eq(f);switch(i){case ab.fade:case ab.slide:var m=i===ab.fade?"fadeOut":"slideUp",o=i===ab.fade?"fadeIn":"slideDown";d.transitionElement=k,l[m](j,function(){var b=a(this)._showAria(!1).parent().parent(),c=n(b);c.transitionElement&&(c.transitionElement[o](j,function(){a(this)._showAria()}).promise().done(g),c.transitionElement=null)});break;case ab.slideLeft:var p=l.outerWidth(!0),q=e>f?-p:p,s=e>f?p:-p;a.when(l.animate({left:q},j,function(){a(this)._showAria(!1)}),k.css("left",s+"px")._showAria().animate({left:0},j)).done(g);break;default:a.when(l._showAria(!1),k._showAria()).done(g)}}function Q(b){b.preventDefault();var c=a(this),d=c.parent().parent().parent().parent(),e=m(d),f=n(d),g=f.currentIndex;if(c.parent().is(":not(.disabled):not(.current)")){var h=c.attr("href"),i=parseInt(h.substring(h.lastIndexOf("-")+1),0);u(d,e,f,i)}return g===f.currentIndex?(j(d,g).focus(),!1):void 0}function R(a){throw arguments.length>1&&(a=a.format(Array.prototype.slice.call(arguments,1))),new Error(a)}function S(a,b){null==b&&R("The argument '{0}' is null or undefined.",a)}a.fn.extend({_aria:function(a,b){return this.attr("aria-"+a,b)},_removeAria:function(a){return this.removeAttr("aria-"+a)},_enableAria:function(a){return null==a||a?this.removeClass("disabled")._aria("disabled","false"):this.addClass("disabled")._aria("disabled","true")},_showAria:function(a){return null==a||a?this.show()._aria("hidden","false"):this.hide()._aria("hidden","true")},_selectAria:function(a){return null==a||a?this.addClass("current")._aria("selected","true"):this.removeClass("current")._aria("selected","false")},_id:function(a){return a?this.attr("id",a):this.attr("id")}}),String.prototype.format||(String.prototype.format=function(){for(var b=1===arguments.length&&a.isArray(arguments[0])?arguments[0]:arguments,c=this,d=0;d<b.length;d++){var e=new RegExp("\\{"+d+"\\}","gm");c=c.replace(e,b[d])}return c});var T=0,U="jQu3ry_5teps_St@te_",V="-t-",W="-p-",X="-h-",Y="Index out of range.",Z="One or more corresponding step {0} are missing.";a.fn.steps=function(b){return a.fn.steps[b]?a.fn.steps[b].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof b&&b?void a.error("Method "+b+" does not exist on jQuery.steps"):w.apply(this,arguments)},a.fn.steps.add=function(a){var b=n(this);return x(this,m(this),b,b.stepCount,a)},a.fn.steps.destroy=function(){return g(this,m(this))},a.fn.steps.finish=function(){h(this,n(this))},a.fn.steps.getCurrentIndex=function(){return n(this).currentIndex},a.fn.steps.getCurrentStep=function(){return p(this,n(this).currentIndex)},a.fn.steps.getStep=function(a){return p(this,a)},a.fn.steps.insert=function(a,b){return x(this,m(this),n(this),a,b)},a.fn.steps.next=function(){return s(this,m(this),n(this))},a.fn.steps.previous=function(){return t(this,m(this),n(this))},a.fn.steps.remove=function(a){return H(this,m(this),n(this),a)},a.fn.steps.setStep=function(){throw new Error("Not yet implemented!")},a.fn.steps.skip=function(){throw new Error("Not yet implemented!")};var $=a.fn.steps.contentMode={html:0,iframe:1,async:2},_=a.fn.steps.stepsOrientation={horizontal:0,vertical:1},ab=a.fn.steps.transitionEffect={none:0,fade:1,slide:2,slideLeft:3},bb=a.fn.steps.stepModel={title:"",content:"",contentUrl:"",contentMode:$.html,contentLoaded:!1},cb=a.fn.steps.defaults={headerTag:"h1",bodyTag:"div",contentContainerTag:"div",actionContainerTag:"div",stepsContainerTag:"div",cssClass:"wizard",clearFixCssClass:"clearfix",stepsOrientation:_.horizontal,titleTemplate:'<span class="number">#index#.</span> #title#',loadingTemplate:'<span class="spinner"></span> #text#',autoFocus:!1,enableAllSteps:!1,enableKeyNavigation:!0,enablePagination:!0,suppressPaginationOnFocus:!0,enableContentCache:!0,enableCancelButton:!1,enableFinishButton:!0,preloadContent:!1,showFinishButtonAlways:!1,forceMoveForward:!1,saveState:!1,startIndex:0,transitionEffect:ab.none,transitionEffectSpeed:200,onStepChanging:function(){return!0},onStepChanged:function(){},onCanceled:function(){},onFinishing:function(){return!0},onFinished:function(){},onContentLoaded:function(){},onInit:function(){},labels:{cancel:"Cancel",current:"current step:",pagination:"Pagination",finish:"Finish",next:"Next",previous:"Previous",loading:"Loading ..."}}}(jQuery);
 
 
 
 
 
 
resources/js/jquery/fancybox.min.js ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // ==================================================
2
+ // fancyBox v3.5.7
3
+ //
4
+ // Licensed GPLv3 for open source use
5
+ // or fancyBox Commercial License for commercial use
6
+ //
7
+ // http://fancyapps.com/fancybox/
8
+ // Copyright 2019 fancyApps
9
+ //
10
+ // ==================================================
11
+ !function(t,e,n,o){"use strict";function i(t,e){var o,i,a,s=[],r=0;t&&t.isDefaultPrevented()||(t.preventDefault(),e=e||{},t&&t.data&&(e=h(t.data.options,e)),o=e.$target||n(t.currentTarget).trigger("blur"),(a=n.fancybox.getInstance())&&a.$trigger&&a.$trigger.is(o)||(e.selector?s=n(e.selector):(i=o.attr("data-fancybox")||"",i?(s=t.data?t.data.items:[],s=s.length?s.filter('[data-fancybox="'+i+'"]'):n('[data-fancybox="'+i+'"]')):s=[o]),r=n(s).index(o),r<0&&(r=0),a=n.fancybox.open(s,e,r),a.$trigger=o))}if(t.console=t.console||{info:function(t){}},n){if(n.fn.fancybox)return void console.info("fancyBox already initialized");var a={closeExisting:!1,loop:!1,gutter:50,keyboard:!0,preventCaptionOverlap:!0,arrows:!0,infobar:!0,smallBtn:"auto",toolbar:"auto",buttons:["zoom","slideShow","thumbs","close"],idleTime:3,protect:!1,modal:!1,image:{preload:!1},ajax:{settings:{data:{fancybox:!0}}},iframe:{tpl:'<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" allowfullscreen="allowfullscreen" allow="autoplay; fullscreen" src=""></iframe>',preload:!0,css:{},attr:{scrolling:"auto"}},video:{tpl:'<video class="fancybox-video" controls controlsList="nodownload" poster="{{poster}}"><source src="{{src}}" type="{{format}}" />Sorry, your browser doesn\'t support embedded videos, <a href="{{src}}">download</a> and watch with your favorite video player!</video>',format:"",autoStart:!0},defaultType:"image",animationEffect:"zoom",animationDuration:366,zoomOpacity:"auto",transitionEffect:"fade",transitionDuration:366,slideClass:"",baseClass:"",baseTpl:'<div class="fancybox-container" role="dialog" tabindex="-1"><div class="fancybox-bg"></div><div class="fancybox-inner"><div class="fancybox-infobar"><span data-fancybox-index></span>&nbsp;/&nbsp;<span data-fancybox-count></span></div><div class="fancybox-toolbar">{{buttons}}</div><div class="fancybox-navigation">{{arrows}}</div><div class="fancybox-stage"></div><div class="fancybox-caption"><div class="fancybox-caption__body"></div></div></div></div>',spinnerTpl:'<div class="fancybox-loading"></div>',errorTpl:'<div class="fancybox-error"><p>{{ERROR}}</p></div>',btnTpl:{download:'<a download data-fancybox-download class="fancybox-button fancybox-button--download" title="{{DOWNLOAD}}" href="javascript:;"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18.62 17.09V19H5.38v-1.91zm-2.97-6.96L17 11.45l-5 4.87-5-4.87 1.36-1.32 2.68 2.64V5h1.92v7.77z"/></svg></a>',zoom:'<button data-fancybox-zoom class="fancybox-button fancybox-button--zoom" title="{{ZOOM}}"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18.7 17.3l-3-3a5.9 5.9 0 0 0-.6-7.6 5.9 5.9 0 0 0-8.4 0 5.9 5.9 0 0 0 0 8.4 5.9 5.9 0 0 0 7.7.7l3 3a1 1 0 0 0 1.3 0c.4-.5.4-1 0-1.5zM8.1 13.8a4 4 0 0 1 0-5.7 4 4 0 0 1 5.7 0 4 4 0 0 1 0 5.7 4 4 0 0 1-5.7 0z"/></svg></button>',close:'<button data-fancybox-close class="fancybox-button fancybox-button--close" title="{{CLOSE}}"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 10.6L6.6 5.2 5.2 6.6l5.4 5.4-5.4 5.4 1.4 1.4 5.4-5.4 5.4 5.4 1.4-1.4-5.4-5.4 5.4-5.4-1.4-1.4-5.4 5.4z"/></svg></button>',arrowLeft:'<button data-fancybox-prev class="fancybox-button fancybox-button--arrow_left" title="{{PREV}}"><div><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M11.28 15.7l-1.34 1.37L5 12l4.94-5.07 1.34 1.38-2.68 2.72H19v1.94H8.6z"/></svg></div></button>',arrowRight:'<button data-fancybox-next class="fancybox-button fancybox-button--arrow_right" title="{{NEXT}}"><div><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M15.4 12.97l-2.68 2.72 1.34 1.38L19 12l-4.94-5.07-1.34 1.38 2.68 2.72H5v1.94z"/></svg></div></button>',smallBtn:'<button type="button" data-fancybox-close class="fancybox-button fancybox-close-small" title="{{CLOSE}}"><svg xmlns="http://www.w3.org/2000/svg" version="1" viewBox="0 0 24 24"><path d="M13 12l5-5-1-1-5 5-5-5-1 1 5 5-5 5 1 1 5-5 5 5 1-1z"/></svg></button>'},parentEl:"body",hideScrollbar:!0,autoFocus:!0,backFocus:!0,trapFocus:!0,fullScreen:{autoStart:!1},touch:{vertical:!0,momentum:!0},hash:null,media:{},slideShow:{autoStart:!1,speed:3e3},thumbs:{autoStart:!1,hideOnClose:!0,parentEl:".fancybox-container",axis:"y"},wheel:"auto",onInit:n.noop,beforeLoad:n.noop,afterLoad:n.noop,beforeShow:n.noop,afterShow:n.noop,beforeClose:n.noop,afterClose:n.noop,onActivate:n.noop,onDeactivate:n.noop,clickContent:function(t,e){return"image"===t.type&&"zoom"},clickSlide:"close",clickOutside:"close",dblclickContent:!1,dblclickSlide:!1,dblclickOutside:!1,mobile:{preventCaptionOverlap:!1,idleTime:!1,clickContent:function(t,e){return"image"===t.type&&"toggleControls"},clickSlide:function(t,e){return"image"===t.type?"toggleControls":"close"},dblclickContent:function(t,e){return"image"===t.type&&"zoom"},dblclickSlide:function(t,e){return"image"===t.type&&"zoom"}},lang:"en",i18n:{en:{CLOSE:"Close",NEXT:"Next",PREV:"Previous",ERROR:"The requested content cannot be loaded. <br/> Please try again later.",PLAY_START:"Start slideshow",PLAY_STOP:"Pause slideshow",FULL_SCREEN:"Full screen",THUMBS:"Thumbnails",DOWNLOAD:"Download",SHARE:"Share",ZOOM:"Zoom"},de:{CLOSE:"Schlie&szlig;en",NEXT:"Weiter",PREV:"Zur&uuml;ck",ERROR:"Die angeforderten Daten konnten nicht geladen werden. <br/> Bitte versuchen Sie es sp&auml;ter nochmal.",PLAY_START:"Diaschau starten",PLAY_STOP:"Diaschau beenden",FULL_SCREEN:"Vollbild",THUMBS:"Vorschaubilder",DOWNLOAD:"Herunterladen",SHARE:"Teilen",ZOOM:"Vergr&ouml;&szlig;ern"}}},s=n(t),r=n(e),c=0,l=function(t){return t&&t.hasOwnProperty&&t instanceof n},d=function(){return t.requestAnimationFrame||t.webkitRequestAnimationFrame||t.mozRequestAnimationFrame||t.oRequestAnimationFrame||function(e){return t.setTimeout(e,1e3/60)}}(),u=function(){return t.cancelAnimationFrame||t.webkitCancelAnimationFrame||t.mozCancelAnimationFrame||t.oCancelAnimationFrame||function(e){t.clearTimeout(e)}}(),f=function(){var t,n=e.createElement("fakeelement"),o={transition:"transitionend",OTransition:"oTransitionEnd",MozTransition:"transitionend",WebkitTransition:"webkitTransitionEnd"};for(t in o)if(void 0!==n.style[t])return o[t];return"transitionend"}(),p=function(t){return t&&t.length&&t[0].offsetHeight},h=function(t,e){var o=n.extend(!0,{},t,e);return n.each(e,function(t,e){n.isArray(e)&&(o[t]=e)}),o},g=function(t){var o,i;return!(!t||t.ownerDocument!==e)&&(n(".fancybox-container").css("pointer-events","none"),o={x:t.getBoundingClientRect().left+t.offsetWidth/2,y:t.getBoundingClientRect().top+t.offsetHeight/2},i=e.elementFromPoint(o.x,o.y)===t,n(".fancybox-container").css("pointer-events",""),i)},b=function(t,e,o){var i=this;i.opts=h({index:o},n.fancybox.defaults),n.isPlainObject(e)&&(i.opts=h(i.opts,e)),n.fancybox.isMobile&&(i.opts=h(i.opts,i.opts.mobile)),i.id=i.opts.id||++c,i.currIndex=parseInt(i.opts.index,10)||0,i.prevIndex=null,i.prevPos=null,i.currPos=0,i.firstRun=!0,i.group=[],i.slides={},i.addContent(t),i.group.length&&i.init()};n.extend(b.prototype,{init:function(){var o,i,a=this,s=a.group[a.currIndex],r=s.opts;r.closeExisting&&n.fancybox.close(!0),n("body").addClass("fancybox-active"),!n.fancybox.getInstance()&&!1!==r.hideScrollbar&&!n.fancybox.isMobile&&e.body.scrollHeight>t.innerHeight&&(n("head").append('<style id="fancybox-style-noscroll" type="text/css">.compensate-for-scrollbar{margin-right:'+(t.innerWidth-e.documentElement.clientWidth)+"px;}</style>"),n("body").addClass("compensate-for-scrollbar")),i="",n.each(r.buttons,function(t,e){i+=r.btnTpl[e]||""}),o=n(a.translate(a,r.baseTpl.replace("{{buttons}}",i).replace("{{arrows}}",r.btnTpl.arrowLeft+r.btnTpl.arrowRight))).attr("id","fancybox-container-"+a.id).addClass(r.baseClass).data("FancyBox",a).appendTo(r.parentEl),a.$refs={container:o},["bg","inner","infobar","toolbar","stage","caption","navigation"].forEach(function(t){a.$refs[t]=o.find(".fancybox-"+t)}),a.trigger("onInit"),a.activate(),a.jumpTo(a.currIndex)},translate:function(t,e){var n=t.opts.i18n[t.opts.lang]||t.opts.i18n.en;return e.replace(/\{\{(\w+)\}\}/g,function(t,e){return void 0===n[e]?t:n[e]})},addContent:function(t){var e,o=this,i=n.makeArray(t);n.each(i,function(t,e){var i,a,s,r,c,l={},d={};n.isPlainObject(e)?(l=e,d=e.opts||e):"object"===n.type(e)&&n(e).length?(i=n(e),d=i.data()||{},d=n.extend(!0,{},d,d.options),d.$orig=i,l.src=o.opts.src||d.src||i.attr("href"),l.type||l.src||(l.type="inline",l.src=e)):l={type:"html",src:e+""},l.opts=n.extend(!0,{},o.opts,d),n.isArray(d.buttons)&&(l.opts.buttons=d.buttons),n.fancybox.isMobile&&l.opts.mobile&&(l.opts=h(l.opts,l.opts.mobile)),a=l.type||l.opts.type,r=l.src||"",!a&&r&&((s=r.match(/\.(mp4|mov|ogv|webm)((\?|#).*)?$/i))?(a="video",l.opts.video.format||(l.opts.video.format="video/"+("ogv"===s[1]?"ogg":s[1]))):r.match(/(^data:image\/[a-z0-9+\/=]*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp|svg|ico)((\?|#).*)?$)/i)?a="image":r.match(/\.(pdf)((\?|#).*)?$/i)?(a="iframe",l=n.extend(!0,l,{contentType:"pdf",opts:{iframe:{preload:!1}}})):"#"===r.charAt(0)&&(a="inline")),a?l.type=a:o.trigger("objectNeedsType",l),l.contentType||(l.contentType=n.inArray(l.type,["html","inline","ajax"])>-1?"html":l.type),l.index=o.group.length,"auto"==l.opts.smallBtn&&(l.opts.smallBtn=n.inArray(l.type,["html","inline","ajax"])>-1),"auto"===l.opts.toolbar&&(l.opts.toolbar=!l.opts.smallBtn),l.$thumb=l.opts.$thumb||null,l.opts.$trigger&&l.index===o.opts.index&&(l.$thumb=l.opts.$trigger.find("img:first"),l.$thumb.length&&(l.opts.$orig=l.opts.$trigger)),l.$thumb&&l.$thumb.length||!l.opts.$orig||(l.$thumb=l.opts.$orig.find("img:first")),l.$thumb&&!l.$thumb.length&&(l.$thumb=null),l.thumb=l.opts.thumb||(l.$thumb?l.$thumb[0].src:null),"function"===n.type(l.opts.caption)&&(l.opts.caption=l.opts.caption.apply(e,[o,l])),"function"===n.type(o.opts.caption)&&(l.opts.caption=o.opts.caption.apply(e,[o,l])),l.opts.caption instanceof n||(l.opts.caption=void 0===l.opts.caption?"":l.opts.caption+""),"ajax"===l.type&&(c=r.split(/\s+/,2),c.length>1&&(l.src=c.shift(),l.opts.filter=c.shift())),l.opts.modal&&(l.opts=n.extend(!0,l.opts,{trapFocus:!0,infobar:0,toolbar:0,smallBtn:0,keyboard:0,slideShow:0,fullScreen:0,thumbs:0,touch:0,clickContent:!1,clickSlide:!1,clickOutside:!1,dblclickContent:!1,dblclickSlide:!1,dblclickOutside:!1})),o.group.push(l)}),Object.keys(o.slides).length&&(o.updateControls(),(e=o.Thumbs)&&e.isActive&&(e.create(),e.focus()))},addEvents:function(){var e=this;e.removeEvents(),e.$refs.container.on("click.fb-close","[data-fancybox-close]",function(t){t.stopPropagation(),t.preventDefault(),e.close(t)}).on("touchstart.fb-prev click.fb-prev","[data-fancybox-prev]",function(t){t.stopPropagation(),t.preventDefault(),e.previous()}).on("touchstart.fb-next click.fb-next","[data-fancybox-next]",function(t){t.stopPropagation(),t.preventDefault(),e.next()}).on("click.fb","[data-fancybox-zoom]",function(t){e[e.isScaledDown()?"scaleToActual":"scaleToFit"]()}),s.on("orientationchange.fb resize.fb",function(t){t&&t.originalEvent&&"resize"===t.originalEvent.type?(e.requestId&&u(e.requestId),e.requestId=d(function(){e.update(t)})):(e.current&&"iframe"===e.current.type&&e.$refs.stage.hide(),setTimeout(function(){e.$refs.stage.show(),e.update(t)},n.fancybox.isMobile?600:250))}),r.on("keydown.fb",function(t){var o=n.fancybox?n.fancybox.getInstance():null,i=o.current,a=t.keyCode||t.which;if(9==a)return void(i.opts.trapFocus&&e.focus(t));if(!(!i.opts.keyboard||t.ctrlKey||t.altKey||t.shiftKey||n(t.target).is("input,textarea,video,audio,select")))return 8===a||27===a?(t.preventDefault(),void e.close(t)):37===a||38===a?(t.preventDefault(),void e.previous()):39===a||40===a?(t.preventDefault(),void e.next()):void e.trigger("afterKeydown",t,a)}),e.group[e.currIndex].opts.idleTime&&(e.idleSecondsCounter=0,r.on("mousemove.fb-idle mouseleave.fb-idle mousedown.fb-idle touchstart.fb-idle touchmove.fb-idle scroll.fb-idle keydown.fb-idle",function(t){e.idleSecondsCounter=0,e.isIdle&&e.showControls(),e.isIdle=!1}),e.idleInterval=t.setInterval(function(){++e.idleSecondsCounter>=e.group[e.currIndex].opts.idleTime&&!e.isDragging&&(e.isIdle=!0,e.idleSecondsCounter=0,e.hideControls())},1e3))},removeEvents:function(){var e=this;s.off("orientationchange.fb resize.fb"),r.off("keydown.fb .fb-idle"),this.$refs.container.off(".fb-close .fb-prev .fb-next"),e.idleInterval&&(t.clearInterval(e.idleInterval),e.idleInterval=null)},previous:function(t){return this.jumpTo(this.currPos-1,t)},next:function(t){return this.jumpTo(this.currPos+1,t)},jumpTo:function(t,e){var o,i,a,s,r,c,l,d,u,f=this,h=f.group.length;if(!(f.isDragging||f.isClosing||f.isAnimating&&f.firstRun)){if(t=parseInt(t,10),!(a=f.current?f.current.opts.loop:f.opts.loop)&&(t<0||t>=h))return!1;if(o=f.firstRun=!Object.keys(f.slides).length,r=f.current,f.prevIndex=f.currIndex,f.prevPos=f.currPos,s=f.createSlide(t),h>1&&((a||s.index<h-1)&&f.createSlide(t+1),(a||s.index>0)&&f.createSlide(t-1)),f.current=s,f.currIndex=s.index,f.currPos=s.pos,f.trigger("beforeShow",o),f.updateControls(),s.forcedDuration=void 0,n.isNumeric(e)?s.forcedDuration=e:e=s.opts[o?"animationDuration":"transitionDuration"],e=parseInt(e,10),i=f.isMoved(s),s.$slide.addClass("fancybox-slide--current"),o)return s.opts.animationEffect&&e&&f.$refs.container.css("transition-duration",e+"ms"),f.$refs.container.addClass("fancybox-is-open").trigger("focus"),f.loadSlide(s),void f.preload("image");c=n.fancybox.getTranslate(r.$slide),l=n.fancybox.getTranslate(f.$refs.stage),n.each(f.slides,function(t,e){n.fancybox.stop(e.$slide,!0)}),r.pos!==s.pos&&(r.isComplete=!1),r.$slide.removeClass("fancybox-slide--complete fancybox-slide--current"),i?(u=c.left-(r.pos*c.width+r.pos*r.opts.gutter),n.each(f.slides,function(t,o){o.$slide.removeClass("fancybox-animated").removeClass(function(t,e){return(e.match(/(^|\s)fancybox-fx-\S+/g)||[]).join(" ")});var i=o.pos*c.width+o.pos*o.opts.gutter;n.fancybox.setTranslate(o.$slide,{top:0,left:i-l.left+u}),o.pos!==s.pos&&o.$slide.addClass("fancybox-slide--"+(o.pos>s.pos?"next":"previous")),p(o.$slide),n.fancybox.animate(o.$slide,{top:0,left:(o.pos-s.pos)*c.width+(o.pos-s.pos)*o.opts.gutter},e,function(){o.$slide.css({transform:"",opacity:""}).removeClass("fancybox-slide--next fancybox-slide--previous"),o.pos===f.currPos&&f.complete()})})):e&&s.opts.transitionEffect&&(d="fancybox-animated fancybox-fx-"+s.opts.transitionEffect,r.$slide.addClass("fancybox-slide--"+(r.pos>s.pos?"next":"previous")),n.fancybox.animate(r.$slide,d,e,function(){r.$slide.removeClass(d).removeClass("fancybox-slide--next fancybox-slide--previous")},!1)),s.isLoaded?f.revealContent(s):f.loadSlide(s),f.preload("image")}},createSlide:function(t){var e,o,i=this;return o=t%i.group.length,o=o<0?i.group.length+o:o,!i.slides[t]&&i.group[o]&&(e=n('<div class="fancybox-slide"></div>').appendTo(i.$refs.stage),i.slides[t]=n.extend(!0,{},i.group[o],{pos:t,$slide:e,isLoaded:!1}),i.updateSlide(i.slides[t])),i.slides[t]},scaleToActual:function(t,e,o){var i,a,s,r,c,l=this,d=l.current,u=d.$content,f=n.fancybox.getTranslate(d.$slide).width,p=n.fancybox.getTranslate(d.$slide).height,h=d.width,g=d.height;l.isAnimating||l.isMoved()||!u||"image"!=d.type||!d.isLoaded||d.hasError||(l.isAnimating=!0,n.fancybox.stop(u),t=void 0===t?.5*f:t,e=void 0===e?.5*p:e,i=n.fancybox.getTranslate(u),i.top-=n.fancybox.getTranslate(d.$slide).top,i.left-=n.fancybox.getTranslate(d.$slide).left,r=h/i.width,c=g/i.height,a=.5*f-.5*h,s=.5*p-.5*g,h>f&&(a=i.left*r-(t*r-t),a>0&&(a=0),a<f-h&&(a=f-h)),g>p&&(s=i.top*c-(e*c-e),s>0&&(s=0),s<p-g&&(s=p-g)),l.updateCursor(h,g),n.fancybox.animate(u,{top:s,left:a,scaleX:r,scaleY:c},o||366,function(){l.isAnimating=!1}),l.SlideShow&&l.SlideShow.isActive&&l.SlideShow.stop())},scaleToFit:function(t){var e,o=this,i=o.current,a=i.$content;o.isAnimating||o.isMoved()||!a||"image"!=i.type||!i.isLoaded||i.hasError||(o.isAnimating=!0,n.fancybox.stop(a),e=o.getFitPos(i),o.updateCursor(e.width,e.height),n.fancybox.animate(a,{top:e.top,left:e.left,scaleX:e.width/a.width(),scaleY:e.height/a.height()},t||366,function(){o.isAnimating=!1}))},getFitPos:function(t){var e,o,i,a,s=this,r=t.$content,c=t.$slide,l=t.width||t.opts.width,d=t.height||t.opts.height,u={};return!!(t.isLoaded&&r&&r.length)&&(e=n.fancybox.getTranslate(s.$refs.stage).width,o=n.fancybox.getTranslate(s.$refs.stage).height,e-=parseFloat(c.css("paddingLeft"))+parseFloat(c.css("paddingRight"))+parseFloat(r.css("marginLeft"))+parseFloat(r.css("marginRight")),o-=parseFloat(c.css("paddingTop"))+parseFloat(c.css("paddingBottom"))+parseFloat(r.css("marginTop"))+parseFloat(r.css("marginBottom")),l&&d||(l=e,d=o),i=Math.min(1,e/l,o/d),l*=i,d*=i,l>e-.5&&(l=e),d>o-.5&&(d=o),"image"===t.type?(u.top=Math.floor(.5*(o-d))+parseFloat(c.css("paddingTop")),u.left=Math.floor(.5*(e-l))+parseFloat(c.css("paddingLeft"))):"video"===t.contentType&&(a=t.opts.width&&t.opts.height?l/d:t.opts.ratio||16/9,d>l/a?d=l/a:l>d*a&&(l=d*a)),u.width=l,u.height=d,u)},update:function(t){var e=this;n.each(e.slides,function(n,o){e.updateSlide(o,t)})},updateSlide:function(t,e){var o=this,i=t&&t.$content,a=t.width||t.opts.width,s=t.height||t.opts.height,r=t.$slide;o.adjustCaption(t),i&&(a||s||"video"===t.contentType)&&!t.hasError&&(n.fancybox.stop(i),n.fancybox.setTranslate(i,o.getFitPos(t)),t.pos===o.currPos&&(o.isAnimating=!1,o.updateCursor())),o.adjustLayout(t),r.length&&(r.trigger("refresh"),t.pos===o.currPos&&o.$refs.toolbar.add(o.$refs.navigation.find(".fancybox-button--arrow_right")).toggleClass("compensate-for-scrollbar",r.get(0).scrollHeight>r.get(0).clientHeight)),o.trigger("onUpdate",t,e)},centerSlide:function(t){var e=this,o=e.current,i=o.$slide;!e.isClosing&&o&&(i.siblings().css({transform:"",opacity:""}),i.parent().children().removeClass("fancybox-slide--previous fancybox-slide--next"),n.fancybox.animate(i,{top:0,left:0,opacity:1},void 0===t?0:t,function(){i.css({transform:"",opacity:""}),o.isComplete||e.complete()},!1))},isMoved:function(t){var e,o,i=t||this.current;return!!i&&(o=n.fancybox.getTranslate(this.$refs.stage),e=n.fancybox.getTranslate(i.$slide),!i.$slide.hasClass("fancybox-animated")&&(Math.abs(e.top-o.top)>.5||Math.abs(e.left-o.left)>.5))},updateCursor:function(t,e){var o,i,a=this,s=a.current,r=a.$refs.container;s&&!a.isClosing&&a.Guestures&&(r.removeClass("fancybox-is-zoomable fancybox-can-zoomIn fancybox-can-zoomOut fancybox-can-swipe fancybox-can-pan"),o=a.canPan(t,e),i=!!o||a.isZoomable(),r.toggleClass("fancybox-is-zoomable",i),n("[data-fancybox-zoom]").prop("disabled",!i),o?r.addClass("fancybox-can-pan"):i&&("zoom"===s.opts.clickContent||n.isFunction(s.opts.clickContent)&&"zoom"==s.opts.clickContent(s))?r.addClass("fancybox-can-zoomIn"):s.opts.touch&&(s.opts.touch.vertical||a.group.length>1)&&"video"!==s.contentType&&r.addClass("fancybox-can-swipe"))},isZoomable:function(){var t,e=this,n=e.current;if(n&&!e.isClosing&&"image"===n.type&&!n.hasError){if(!n.isLoaded)return!0;if((t=e.getFitPos(n))&&(n.width>t.width||n.height>t.height))return!0}return!1},isScaledDown:function(t,e){var o=this,i=!1,a=o.current,s=a.$content;return void 0!==t&&void 0!==e?i=t<a.width&&e<a.height:s&&(i=n.fancybox.getTranslate(s),i=i.width<a.width&&i.height<a.height),i},canPan:function(t,e){var o=this,i=o.current,a=null,s=!1;return"image"===i.type&&(i.isComplete||t&&e)&&!i.hasError&&(s=o.getFitPos(i),void 0!==t&&void 0!==e?a={width:t,height:e}:i.isComplete&&(a=n.fancybox.getTranslate(i.$content)),a&&s&&(s=Math.abs(a.width-s.width)>1.5||Math.abs(a.height-s.height)>1.5)),s},loadSlide:function(t){var e,o,i,a=this;if(!t.isLoading&&!t.isLoaded){if(t.isLoading=!0,!1===a.trigger("beforeLoad",t))return t.isLoading=!1,!1;switch(e=t.type,o=t.$slide,o.off("refresh").trigger("onReset").addClass(t.opts.slideClass),e){case"image":a.setImage(t);break;case"iframe":a.setIframe(t);break;case"html":a.setContent(t,t.src||t.content);break;case"video":a.setContent(t,t.opts.video.tpl.replace(/\{\{src\}\}/gi,t.src).replace("{{format}}",t.opts.videoFormat||t.opts.video.format||"").replace("{{poster}}",t.thumb||""));break;case"inline":n(t.src).length?a.setContent(t,n(t.src)):a.setError(t);break;case"ajax":a.showLoading(t),i=n.ajax(n.extend({},t.opts.ajax.settings,{url:t.src,success:function(e,n){"success"===n&&a.setContent(t,e)},error:function(e,n){e&&"abort"!==n&&a.setError(t)}})),o.one("onReset",function(){i.abort()});break;default:a.setError(t)}return!0}},setImage:function(t){var o,i=this;setTimeout(function(){var e=t.$image;i.isClosing||!t.isLoading||e&&e.length&&e[0].complete||t.hasError||i.showLoading(t)},50),i.checkSrcset(t),t.$content=n('<div class="fancybox-content"></div>').addClass("fancybox-is-hidden").appendTo(t.$slide.addClass("fancybox-slide--image")),!1!==t.opts.preload&&t.opts.width&&t.opts.height&&t.thumb&&(t.width=t.opts.width,t.height=t.opts.height,o=e.createElement("img"),o.onerror=function(){n(this).remove(),t.$ghost=null},o.onload=function(){i.afterLoad(t)},t.$ghost=n(o).addClass("fancybox-image").appendTo(t.$content).attr("src",t.thumb)),i.setBigImage(t)},checkSrcset:function(e){var n,o,i,a,s=e.opts.srcset||e.opts.image.srcset;if(s){i=t.devicePixelRatio||1,a=t.innerWidth*i,o=s.split(",").map(function(t){var e={};return t.trim().split(/\s+/).forEach(function(t,n){var o=parseInt(t.substring(0,t.length-1),10);if(0===n)return e.url=t;o&&(e.value=o,e.postfix=t[t.length-1])}),e}),o.sort(function(t,e){return t.value-e.value});for(var r=0;r<o.length;r++){var c=o[r];if("w"===c.postfix&&c.value>=a||"x"===c.postfix&&c.value>=i){n=c;break}}!n&&o.length&&(n=o[o.length-1]),n&&(e.src=n.url,e.width&&e.height&&"w"==n.postfix&&(e.height=e.width/e.height*n.value,e.width=n.value),e.opts.srcset=s)}},setBigImage:function(t){var o=this,i=e.createElement("img"),a=n(i);t.$image=a.one("error",function(){o.setError(t)}).one("load",function(){var e;t.$ghost||(o.resolveImageSlideSize(t,this.naturalWidth,this.naturalHeight),o.afterLoad(t)),o.isClosing||(t.opts.srcset&&(e=t.opts.sizes,e&&"auto"!==e||(e=(t.width/t.height>1&&s.width()/s.height()>1?"100":Math.round(t.width/t.height*100))+"vw"),a.attr("sizes",e).attr("srcset",t.opts.srcset)),t.$ghost&&setTimeout(function(){t.$ghost&&!o.isClosing&&t.$ghost.hide()},Math.min(300,Math.max(1e3,t.height/1600))),o.hideLoading(t))}).addClass("fancybox-image").attr("src",t.src).appendTo(t.$content),(i.complete||"complete"==i.readyState)&&a.naturalWidth&&a.naturalHeight?a.trigger("load"):i.error&&a.trigger("error")},resolveImageSlideSize:function(t,e,n){var o=parseInt(t.opts.width,10),i=parseInt(t.opts.height,10);t.width=e,t.height=n,o>0&&(t.width=o,t.height=Math.floor(o*n/e)),i>0&&(t.width=Math.floor(i*e/n),t.height=i)},setIframe:function(t){var e,o=this,i=t.opts.iframe,a=t.$slide;t.$content=n('<div class="fancybox-content'+(i.preload?" fancybox-is-hidden":"")+'"></div>').css(i.css).appendTo(a),a.addClass("fancybox-slide--"+t.contentType),t.$iframe=e=n(i.tpl.replace(/\{rnd\}/g,(new Date).getTime())).attr(i.attr).appendTo(t.$content),i.preload?(o.showLoading(t),e.on("load.fb error.fb",function(e){this.isReady=1,t.$slide.trigger("refresh"),o.afterLoad(t)}),a.on("refresh.fb",function(){var n,o,s=t.$content,r=i.css.width,c=i.css.height;if(1===e[0].isReady){try{n=e.contents(),o=n.find("body")}catch(t){}o&&o.length&&o.children().length&&(a.css("overflow","visible"),s.css({width:"100%","max-width":"100%",height:"9999px"}),void 0===r&&(r=Math.ceil(Math.max(o[0].clientWidth,o.outerWidth(!0)))),s.css("width",r||"").css("max-width",""),void 0===c&&(c=Math.ceil(Math.max(o[0].clientHeight,o.outerHeight(!0)))),s.css("height",c||""),a.css("overflow","auto")),s.removeClass("fancybox-is-hidden")}})):o.afterLoad(t),e.attr("src",t.src),a.one("onReset",function(){try{n(this).find("iframe").hide().unbind().attr("src","//about:blank")}catch(t){}n(this).off("refresh.fb").empty(),t.isLoaded=!1,t.isRevealed=!1})},setContent:function(t,e){var o=this;o.isClosing||(o.hideLoading(t),t.$content&&n.fancybox.stop(t.$content),t.$slide.empty(),l(e)&&e.parent().length?((e.hasClass("fancybox-content")||e.parent().hasClass("fancybox-content"))&&e.parents(".fancybox-slide").trigger("onReset"),t.$placeholder=n("<div>").hide().insertAfter(e),e.css("display","inline-block")):t.hasError||("string"===n.type(e)&&(e=n("<div>").append(n.trim(e)).contents()),t.opts.filter&&(e=n("<div>").html(e).find(t.opts.filter))),t.$slide.one("onReset",function(){n(this).find("video,audio").trigger("pause"),t.$placeholder&&(t.$placeholder.after(e.removeClass("fancybox-content").hide()).remove(),t.$placeholder=null),t.$smallBtn&&(t.$smallBtn.remove(),t.$smallBtn=null),t.hasError||(n(this).empty(),t.isLoaded=!1,t.isRevealed=!1)}),n(e).appendTo(t.$slide),n(e).is("video,audio")&&(n(e).addClass("fancybox-video"),n(e).wrap("<div></div>"),t.contentType="video",t.opts.width=t.opts.width||n(e).attr("width"),t.opts.height=t.opts.height||n(e).attr("height")),t.$content=t.$slide.children().filter("div,form,main,video,audio,article,.fancybox-content").first(),t.$content.siblings().hide(),t.$content.length||(t.$content=t.$slide.wrapInner("<div></div>").children().first()),t.$content.addClass("fancybox-content"),t.$slide.addClass("fancybox-slide--"+t.contentType),o.afterLoad(t))},setError:function(t){t.hasError=!0,t.$slide.trigger("onReset").removeClass("fancybox-slide--"+t.contentType).addClass("fancybox-slide--error"),t.contentType="html",this.setContent(t,this.translate(t,t.opts.errorTpl)),t.pos===this.currPos&&(this.isAnimating=!1)},showLoading:function(t){var e=this;(t=t||e.current)&&!t.$spinner&&(t.$spinner=n(e.translate(e,e.opts.spinnerTpl)).appendTo(t.$slide).hide().fadeIn("fast"))},hideLoading:function(t){var e=this;(t=t||e.current)&&t.$spinner&&(t.$spinner.stop().remove(),delete t.$spinner)},afterLoad:function(t){var e=this;e.isClosing||(t.isLoading=!1,t.isLoaded=!0,e.trigger("afterLoad",t),e.hideLoading(t),!t.opts.smallBtn||t.$smallBtn&&t.$smallBtn.length||(t.$smallBtn=n(e.translate(t,t.opts.btnTpl.smallBtn)).appendTo(t.$content)),t.opts.protect&&t.$content&&!t.hasError&&(t.$content.on("contextmenu.fb",function(t){return 2==t.button&&t.preventDefault(),!0}),"image"===t.type&&n('<div class="fancybox-spaceball"></div>').appendTo(t.$content)),e.adjustCaption(t),e.adjustLayout(t),t.pos===e.currPos&&e.updateCursor(),e.revealContent(t))},adjustCaption:function(t){var e,n=this,o=t||n.current,i=o.opts.caption,a=o.opts.preventCaptionOverlap,s=n.$refs.caption,r=!1;s.toggleClass("fancybox-caption--separate",a),a&&i&&i.length&&(o.pos!==n.currPos?(e=s.clone().appendTo(s.parent()),e.children().eq(0).empty().html(i),r=e.outerHeight(!0),e.empty().remove()):n.$caption&&(r=n.$caption.outerHeight(!0)),o.$slide.css("padding-bottom",r||""))},adjustLayout:function(t){var e,n,o,i,a=this,s=t||a.current;s.isLoaded&&!0!==s.opts.disableLayoutFix&&(s.$content.css("margin-bottom",""),s.$content.outerHeight()>s.$slide.height()+.5&&(o=s.$slide[0].style["padding-bottom"],i=s.$slide.css("padding-bottom"),parseFloat(i)>0&&(e=s.$slide[0].scrollHeight,s.$slide.css("padding-bottom",0),Math.abs(e-s.$slide[0].scrollHeight)<1&&(n=i),s.$slide.css("padding-bottom",o))),s.$content.css("margin-bottom",n))},revealContent:function(t){var e,o,i,a,s=this,r=t.$slide,c=!1,l=!1,d=s.isMoved(t),u=t.isRevealed;return t.isRevealed=!0,e=t.opts[s.firstRun?"animationEffect":"transitionEffect"],i=t.opts[s.firstRun?"animationDuration":"transitionDuration"],i=parseInt(void 0===t.forcedDuration?i:t.forcedDuration,10),!d&&t.pos===s.currPos&&i||(e=!1),"zoom"===e&&(t.pos===s.currPos&&i&&"image"===t.type&&!t.hasError&&(l=s.getThumbPos(t))?c=s.getFitPos(t):e="fade"),"zoom"===e?(s.isAnimating=!0,c.scaleX=c.width/l.width,c.scaleY=c.height/l.height,a=t.opts.zoomOpacity,"auto"==a&&(a=Math.abs(t.width/t.height-l.width/l.height)>.1),a&&(l.opacity=.1,c.opacity=1),n.fancybox.setTranslate(t.$content.removeClass("fancybox-is-hidden"),l),p(t.$content),void n.fancybox.animate(t.$content,c,i,function(){s.isAnimating=!1,s.complete()})):(s.updateSlide(t),e?(n.fancybox.stop(r),o="fancybox-slide--"+(t.pos>=s.prevPos?"next":"previous")+" fancybox-animated fancybox-fx-"+e,r.addClass(o).removeClass("fancybox-slide--current"),t.$content.removeClass("fancybox-is-hidden"),p(r),"image"!==t.type&&t.$content.hide().show(0),void n.fancybox.animate(r,"fancybox-slide--current",i,function(){r.removeClass(o).css({transform:"",opacity:""}),t.pos===s.currPos&&s.complete()},!0)):(t.$content.removeClass("fancybox-is-hidden"),u||!d||"image"!==t.type||t.hasError||t.$content.hide().fadeIn("fast"),void(t.pos===s.currPos&&s.complete())))},getThumbPos:function(t){var e,o,i,a,s,r=!1,c=t.$thumb;return!(!c||!g(c[0]))&&(e=n.fancybox.getTranslate(c),o=parseFloat(c.css("border-top-width")||0),i=parseFloat(c.css("border-right-width")||0),a=parseFloat(c.css("border-bottom-width")||0),s=parseFloat(c.css("border-left-width")||0),r={top:e.top+o,left:e.left+s,width:e.width-i-s,height:e.height-o-a,scaleX:1,scaleY:1},e.width>0&&e.height>0&&r)},complete:function(){var t,e=this,o=e.current,i={};!e.isMoved()&&o.isLoaded&&(o.isComplete||(o.isComplete=!0,o.$slide.siblings().trigger("onReset"),e.preload("inline"),p(o.$slide),o.$slide.addClass("fancybox-slide--complete"),n.each(e.slides,function(t,o){o.pos>=e.currPos-1&&o.pos<=e.currPos+1?i[o.pos]=o:o&&(n.fancybox.stop(o.$slide),o.$slide.off().remove())}),e.slides=i),e.isAnimating=!1,e.updateCursor(),e.trigger("afterShow"),o.opts.video.autoStart&&o.$slide.find("video,audio").filter(":visible:first").trigger("play").one("ended",function(){Document.exitFullscreen?Document.exitFullscreen():this.webkitExitFullscreen&&this.webkitExitFullscreen(),e.next()}),o.opts.autoFocus&&"html"===o.contentType&&(t=o.$content.find("input[autofocus]:enabled:visible:first"),t.length?t.trigger("focus"):e.focus(null,!0)),o.$slide.scrollTop(0).scrollLeft(0))},preload:function(t){var e,n,o=this;o.group.length<2||(n=o.slides[o.currPos+1],e=o.slides[o.currPos-1],e&&e.type===t&&o.loadSlide(e),n&&n.type===t&&o.loadSlide(n))},focus:function(t,o){var i,a,s=this,r=["a[href]","area[href]",'input:not([disabled]):not([type="hidden"]):not([aria-hidden])',"select:not([disabled]):not([aria-hidden])","textarea:not([disabled]):not([aria-hidden])","button:not([disabled]):not([aria-hidden])","iframe","object","embed","video","audio","[contenteditable]",'[tabindex]:not([tabindex^="-"])'].join(",");s.isClosing||(i=!t&&s.current&&s.current.isComplete?s.current.$slide.find("*:visible"+(o?":not(.fancybox-close-small)":"")):s.$refs.container.find("*:visible"),i=i.filter(r).filter(function(){return"hidden"!==n(this).css("visibility")&&!n(this).hasClass("disabled")}),i.length?(a=i.index(e.activeElement),t&&t.shiftKey?(a<0||0==a)&&(t.preventDefault(),i.eq(i.length-1).trigger("focus")):(a<0||a==i.length-1)&&(t&&t.preventDefault(),i.eq(0).trigger("focus"))):s.$refs.container.trigger("focus"))},activate:function(){var t=this;n(".fancybox-container").each(function(){var e=n(this).data("FancyBox");e&&e.id!==t.id&&!e.isClosing&&(e.trigger("onDeactivate"),e.removeEvents(),e.isVisible=!1)}),t.isVisible=!0,(t.current||t.isIdle)&&(t.update(),t.updateControls()),t.trigger("onActivate"),t.addEvents()},close:function(t,e){var o,i,a,s,r,c,l,u=this,f=u.current,h=function(){u.cleanUp(t)};return!u.isClosing&&(u.isClosing=!0,!1===u.trigger("beforeClose",t)?(u.isClosing=!1,d(function(){u.update()}),!1):(u.removeEvents(),a=f.$content,o=f.opts.animationEffect,i=n.isNumeric(e)?e:o?f.opts.animationDuration:0,f.$slide.removeClass("fancybox-slide--complete fancybox-slide--next fancybox-slide--previous fancybox-animated"),!0!==t?n.fancybox.stop(f.$slide):o=!1,f.$slide.siblings().trigger("onReset").remove(),i&&u.$refs.container.removeClass("fancybox-is-open").addClass("fancybox-is-closing").css("transition-duration",i+"ms"),u.hideLoading(f),u.hideControls(!0),u.updateCursor(),"zoom"!==o||a&&i&&"image"===f.type&&!u.isMoved()&&!f.hasError&&(l=u.getThumbPos(f))||(o="fade"),"zoom"===o?(n.fancybox.stop(a),s=n.fancybox.getTranslate(a),c={top:s.top,left:s.left,scaleX:s.width/l.width,scaleY:s.height/l.height,width:l.width,height:l.height},r=f.opts.zoomOpacity,
12
+ "auto"==r&&(r=Math.abs(f.width/f.height-l.width/l.height)>.1),r&&(l.opacity=0),n.fancybox.setTranslate(a,c),p(a),n.fancybox.animate(a,l,i,h),!0):(o&&i?n.fancybox.animate(f.$slide.addClass("fancybox-slide--previous").removeClass("fancybox-slide--current"),"fancybox-animated fancybox-fx-"+o,i,h):!0===t?setTimeout(h,i):h(),!0)))},cleanUp:function(e){var o,i,a,s=this,r=s.current.opts.$orig;s.current.$slide.trigger("onReset"),s.$refs.container.empty().remove(),s.trigger("afterClose",e),s.current.opts.backFocus&&(r&&r.length&&r.is(":visible")||(r=s.$trigger),r&&r.length&&(i=t.scrollX,a=t.scrollY,r.trigger("focus"),n("html, body").scrollTop(a).scrollLeft(i))),s.current=null,o=n.fancybox.getInstance(),o?o.activate():(n("body").removeClass("fancybox-active compensate-for-scrollbar"),n("#fancybox-style-noscroll").remove())},trigger:function(t,e){var o,i=Array.prototype.slice.call(arguments,1),a=this,s=e&&e.opts?e:a.current;if(s?i.unshift(s):s=a,i.unshift(a),n.isFunction(s.opts[t])&&(o=s.opts[t].apply(s,i)),!1===o)return o;"afterClose"!==t&&a.$refs?a.$refs.container.trigger(t+".fb",i):r.trigger(t+".fb",i)},updateControls:function(){var t=this,o=t.current,i=o.index,a=t.$refs.container,s=t.$refs.caption,r=o.opts.caption;o.$slide.trigger("refresh"),r&&r.length?(t.$caption=s,s.children().eq(0).html(r)):t.$caption=null,t.hasHiddenControls||t.isIdle||t.showControls(),a.find("[data-fancybox-count]").html(t.group.length),a.find("[data-fancybox-index]").html(i+1),a.find("[data-fancybox-prev]").prop("disabled",!o.opts.loop&&i<=0),a.find("[data-fancybox-next]").prop("disabled",!o.opts.loop&&i>=t.group.length-1),"image"===o.type?a.find("[data-fancybox-zoom]").show().end().find("[data-fancybox-download]").attr("href",o.opts.image.src||o.src).show():o.opts.toolbar&&a.find("[data-fancybox-download],[data-fancybox-zoom]").hide(),n(e.activeElement).is(":hidden,[disabled]")&&t.$refs.container.trigger("focus")},hideControls:function(t){var e=this,n=["infobar","toolbar","nav"];!t&&e.current.opts.preventCaptionOverlap||n.push("caption"),this.$refs.container.removeClass(n.map(function(t){return"fancybox-show-"+t}).join(" ")),this.hasHiddenControls=!0},showControls:function(){var t=this,e=t.current?t.current.opts:t.opts,n=t.$refs.container;t.hasHiddenControls=!1,t.idleSecondsCounter=0,n.toggleClass("fancybox-show-toolbar",!(!e.toolbar||!e.buttons)).toggleClass("fancybox-show-infobar",!!(e.infobar&&t.group.length>1)).toggleClass("fancybox-show-caption",!!t.$caption).toggleClass("fancybox-show-nav",!!(e.arrows&&t.group.length>1)).toggleClass("fancybox-is-modal",!!e.modal)},toggleControls:function(){this.hasHiddenControls?this.showControls():this.hideControls()}}),n.fancybox={version:"3.5.7",defaults:a,getInstance:function(t){var e=n('.fancybox-container:not(".fancybox-is-closing"):last').data("FancyBox"),o=Array.prototype.slice.call(arguments,1);return e instanceof b&&("string"===n.type(t)?e[t].apply(e,o):"function"===n.type(t)&&t.apply(e,o),e)},open:function(t,e,n){return new b(t,e,n)},close:function(t){var e=this.getInstance();e&&(e.close(),!0===t&&this.close(t))},destroy:function(){this.close(!0),r.add("body").off("click.fb-start","**")},isMobile:/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),use3d:function(){var n=e.createElement("div");return t.getComputedStyle&&t.getComputedStyle(n)&&t.getComputedStyle(n).getPropertyValue("transform")&&!(e.documentMode&&e.documentMode<11)}(),getTranslate:function(t){var e;return!(!t||!t.length)&&(e=t[0].getBoundingClientRect(),{top:e.top||0,left:e.left||0,width:e.width,height:e.height,opacity:parseFloat(t.css("opacity"))})},setTranslate:function(t,e){var n="",o={};if(t&&e)return void 0===e.left&&void 0===e.top||(n=(void 0===e.left?t.position().left:e.left)+"px, "+(void 0===e.top?t.position().top:e.top)+"px",n=this.use3d?"translate3d("+n+", 0px)":"translate("+n+")"),void 0!==e.scaleX&&void 0!==e.scaleY?n+=" scale("+e.scaleX+", "+e.scaleY+")":void 0!==e.scaleX&&(n+=" scaleX("+e.scaleX+")"),n.length&&(o.transform=n),void 0!==e.opacity&&(o.opacity=e.opacity),void 0!==e.width&&(o.width=e.width),void 0!==e.height&&(o.height=e.height),t.css(o)},animate:function(t,e,o,i,a){var s,r=this;n.isFunction(o)&&(i=o,o=null),r.stop(t),s=r.getTranslate(t),t.on(f,function(c){(!c||!c.originalEvent||t.is(c.originalEvent.target)&&"z-index"!=c.originalEvent.propertyName)&&(r.stop(t),n.isNumeric(o)&&t.css("transition-duration",""),n.isPlainObject(e)?void 0!==e.scaleX&&void 0!==e.scaleY&&r.setTranslate(t,{top:e.top,left:e.left,width:s.width*e.scaleX,height:s.height*e.scaleY,scaleX:1,scaleY:1}):!0!==a&&t.removeClass(e),n.isFunction(i)&&i(c))}),n.isNumeric(o)&&t.css("transition-duration",o+"ms"),n.isPlainObject(e)?(void 0!==e.scaleX&&void 0!==e.scaleY&&(delete e.width,delete e.height,t.parent().hasClass("fancybox-slide--image")&&t.parent().addClass("fancybox-is-scaling")),n.fancybox.setTranslate(t,e)):t.addClass(e),t.data("timer",setTimeout(function(){t.trigger(f)},o+33))},stop:function(t,e){t&&t.length&&(clearTimeout(t.data("timer")),e&&t.trigger(f),t.off(f).css("transition-duration",""),t.parent().removeClass("fancybox-is-scaling"))}},n.fn.fancybox=function(t){var e;return t=t||{},e=t.selector||!1,e?n("body").off("click.fb-start",e).on("click.fb-start",e,{options:t},i):this.off("click.fb-start").on("click.fb-start",{items:this,options:t},i),this},r.on("click.fb-start","[data-fancybox]",i),r.on("click.fb-start","[data-fancybox-trigger]",function(t){n('[data-fancybox="'+n(this).attr("data-fancybox-trigger")+'"]').eq(n(this).attr("data-fancybox-index")||0).trigger("click.fb-start",{$trigger:n(this)})}),function(){var t=null;r.on("mousedown mouseup focus blur",".fancybox-button",function(e){switch(e.type){case"mousedown":t=n(this);break;case"mouseup":t=null;break;case"focusin":n(".fancybox-button").removeClass("fancybox-focus"),n(this).is(t)||n(this).is("[disabled]")||n(this).addClass("fancybox-focus");break;case"focusout":n(".fancybox-button").removeClass("fancybox-focus")}})}()}}(window,document,jQuery),function(t){"use strict";var e={youtube:{matcher:/(youtube\.com|youtu\.be|youtube\-nocookie\.com)\/(watch\?(.*&)?v=|v\/|u\/|embed\/?)?(videoseries\?list=(.*)|[\w-]{11}|\?listType=(.*)&list=(.*))(.*)/i,params:{autoplay:1,autohide:1,fs:1,rel:0,hd:1,wmode:"transparent",enablejsapi:1,html5:1},paramPlace:8,type:"iframe",url:"https://www.youtube-nocookie.com/embed/$4",thumb:"https://img.youtube.com/vi/$4/hqdefault.jpg"},vimeo:{matcher:/^.+vimeo.com\/(.*\/)?([\d]+)(.*)?/,params:{autoplay:1,hd:1,show_title:1,show_byline:1,show_portrait:0,fullscreen:1},paramPlace:3,type:"iframe",url:"//player.vimeo.com/video/$2"},instagram:{matcher:/(instagr\.am|instagram\.com)\/p\/([a-zA-Z0-9_\-]+)\/?/i,type:"image",url:"//$1/p/$2/media/?size=l"},gmap_place:{matcher:/(maps\.)?google\.([a-z]{2,3}(\.[a-z]{2})?)\/(((maps\/(place\/(.*)\/)?\@(.*),(\d+.?\d+?)z))|(\?ll=))(.*)?/i,type:"iframe",url:function(t){return"//maps.google."+t[2]+"/?ll="+(t[9]?t[9]+"&z="+Math.floor(t[10])+(t[12]?t[12].replace(/^\//,"&"):""):t[12]+"").replace(/\?/,"&")+"&output="+(t[12]&&t[12].indexOf("layer=c")>0?"svembed":"embed")}},gmap_search:{matcher:/(maps\.)?google\.([a-z]{2,3}(\.[a-z]{2})?)\/(maps\/search\/)(.*)/i,type:"iframe",url:function(t){return"//maps.google."+t[2]+"/maps?q="+t[5].replace("query=","q=").replace("api=1","")+"&output=embed"}}},n=function(e,n,o){if(e)return o=o||"","object"===t.type(o)&&(o=t.param(o,!0)),t.each(n,function(t,n){e=e.replace("$"+t,n||"")}),o.length&&(e+=(e.indexOf("?")>0?"&":"?")+o),e};t(document).on("objectNeedsType.fb",function(o,i,a){var s,r,c,l,d,u,f,p=a.src||"",h=!1;s=t.extend(!0,{},e,a.opts.media),t.each(s,function(e,o){if(c=p.match(o.matcher)){if(h=o.type,f=e,u={},o.paramPlace&&c[o.paramPlace]){d=c[o.paramPlace],"?"==d[0]&&(d=d.substring(1)),d=d.split("&");for(var i=0;i<d.length;++i){var s=d[i].split("=",2);2==s.length&&(u[s[0]]=decodeURIComponent(s[1].replace(/\+/g," ")))}}return l=t.extend(!0,{},o.params,a.opts[e],u),p="function"===t.type(o.url)?o.url.call(this,c,l,a):n(o.url,c,l),r="function"===t.type(o.thumb)?o.thumb.call(this,c,l,a):n(o.thumb,c),"youtube"===e?p=p.replace(/&t=((\d+)m)?(\d+)s/,function(t,e,n,o){return"&start="+((n?60*parseInt(n,10):0)+parseInt(o,10))}):"vimeo"===e&&(p=p.replace("&%23","#")),!1}}),h?(a.opts.thumb||a.opts.$thumb&&a.opts.$thumb.length||(a.opts.thumb=r),"iframe"===h&&(a.opts=t.extend(!0,a.opts,{iframe:{preload:!1,attr:{scrolling:"no"}}})),t.extend(a,{type:h,src:p,origSrc:a.src,contentSource:f,contentType:"image"===h?"image":"gmap_place"==f||"gmap_search"==f?"map":"video"})):p&&(a.type=a.opts.defaultType)});var o={youtube:{src:"https://www.youtube.com/iframe_api",class:"YT",loading:!1,loaded:!1},vimeo:{src:"https://player.vimeo.com/api/player.js",class:"Vimeo",loading:!1,loaded:!1},load:function(t){var e,n=this;if(this[t].loaded)return void setTimeout(function(){n.done(t)});this[t].loading||(this[t].loading=!0,e=document.createElement("script"),e.type="text/javascript",e.src=this[t].src,"youtube"===t?window.onYouTubeIframeAPIReady=function(){n[t].loaded=!0,n.done(t)}:e.onload=function(){n[t].loaded=!0,n.done(t)},document.body.appendChild(e))},done:function(e){var n,o,i;"youtube"===e&&delete window.onYouTubeIframeAPIReady,(n=t.fancybox.getInstance())&&(o=n.current.$content.find("iframe"),"youtube"===e&&void 0!==YT&&YT?i=new YT.Player(o.attr("id"),{events:{onStateChange:function(t){0==t.data&&n.next()}}}):"vimeo"===e&&void 0!==Vimeo&&Vimeo&&(i=new Vimeo.Player(o),i.on("ended",function(){n.next()})))}};t(document).on({"afterShow.fb":function(t,e,n){e.group.length>1&&("youtube"===n.contentSource||"vimeo"===n.contentSource)&&o.load(n.contentSource)}})}(jQuery),function(t,e,n){"use strict";var o=function(){return t.requestAnimationFrame||t.webkitRequestAnimationFrame||t.mozRequestAnimationFrame||t.oRequestAnimationFrame||function(e){return t.setTimeout(e,1e3/60)}}(),i=function(){return t.cancelAnimationFrame||t.webkitCancelAnimationFrame||t.mozCancelAnimationFrame||t.oCancelAnimationFrame||function(e){t.clearTimeout(e)}}(),a=function(e){var n=[];e=e.originalEvent||e||t.e,e=e.touches&&e.touches.length?e.touches:e.changedTouches&&e.changedTouches.length?e.changedTouches:[e];for(var o in e)e[o].pageX?n.push({x:e[o].pageX,y:e[o].pageY}):e[o].clientX&&n.push({x:e[o].clientX,y:e[o].clientY});return n},s=function(t,e,n){return e&&t?"x"===n?t.x-e.x:"y"===n?t.y-e.y:Math.sqrt(Math.pow(t.x-e.x,2)+Math.pow(t.y-e.y,2)):0},r=function(t){if(t.is('a,area,button,[role="button"],input,label,select,summary,textarea,video,audio,iframe')||n.isFunction(t.get(0).onclick)||t.data("selectable"))return!0;for(var e=0,o=t[0].attributes,i=o.length;e<i;e++)if("data-fancybox-"===o[e].nodeName.substr(0,14))return!0;return!1},c=function(e){var n=t.getComputedStyle(e)["overflow-y"],o=t.getComputedStyle(e)["overflow-x"],i=("scroll"===n||"auto"===n)&&e.scrollHeight>e.clientHeight,a=("scroll"===o||"auto"===o)&&e.scrollWidth>e.clientWidth;return i||a},l=function(t){for(var e=!1;;){if(e=c(t.get(0)))break;if(t=t.parent(),!t.length||t.hasClass("fancybox-stage")||t.is("body"))break}return e},d=function(t){var e=this;e.instance=t,e.$bg=t.$refs.bg,e.$stage=t.$refs.stage,e.$container=t.$refs.container,e.destroy(),e.$container.on("touchstart.fb.touch mousedown.fb.touch",n.proxy(e,"ontouchstart"))};d.prototype.destroy=function(){var t=this;t.$container.off(".fb.touch"),n(e).off(".fb.touch"),t.requestId&&(i(t.requestId),t.requestId=null),t.tapped&&(clearTimeout(t.tapped),t.tapped=null)},d.prototype.ontouchstart=function(o){var i=this,c=n(o.target),d=i.instance,u=d.current,f=u.$slide,p=u.$content,h="touchstart"==o.type;if(h&&i.$container.off("mousedown.fb.touch"),(!o.originalEvent||2!=o.originalEvent.button)&&f.length&&c.length&&!r(c)&&!r(c.parent())&&(c.is("img")||!(o.originalEvent.clientX>c[0].clientWidth+c.offset().left))){if(!u||d.isAnimating||u.$slide.hasClass("fancybox-animated"))return o.stopPropagation(),void o.preventDefault();i.realPoints=i.startPoints=a(o),i.startPoints.length&&(u.touch&&o.stopPropagation(),i.startEvent=o,i.canTap=!0,i.$target=c,i.$content=p,i.opts=u.opts.touch,i.isPanning=!1,i.isSwiping=!1,i.isZooming=!1,i.isScrolling=!1,i.canPan=d.canPan(),i.startTime=(new Date).getTime(),i.distanceX=i.distanceY=i.distance=0,i.canvasWidth=Math.round(f[0].clientWidth),i.canvasHeight=Math.round(f[0].clientHeight),i.contentLastPos=null,i.contentStartPos=n.fancybox.getTranslate(i.$content)||{top:0,left:0},i.sliderStartPos=n.fancybox.getTranslate(f),i.stagePos=n.fancybox.getTranslate(d.$refs.stage),i.sliderStartPos.top-=i.stagePos.top,i.sliderStartPos.left-=i.stagePos.left,i.contentStartPos.top-=i.stagePos.top,i.contentStartPos.left-=i.stagePos.left,n(e).off(".fb.touch").on(h?"touchend.fb.touch touchcancel.fb.touch":"mouseup.fb.touch mouseleave.fb.touch",n.proxy(i,"ontouchend")).on(h?"touchmove.fb.touch":"mousemove.fb.touch",n.proxy(i,"ontouchmove")),n.fancybox.isMobile&&e.addEventListener("scroll",i.onscroll,!0),((i.opts||i.canPan)&&(c.is(i.$stage)||i.$stage.find(c).length)||(c.is(".fancybox-image")&&o.preventDefault(),n.fancybox.isMobile&&c.parents(".fancybox-caption").length))&&(i.isScrollable=l(c)||l(c.parent()),n.fancybox.isMobile&&i.isScrollable||o.preventDefault(),(1===i.startPoints.length||u.hasError)&&(i.canPan?(n.fancybox.stop(i.$content),i.isPanning=!0):i.isSwiping=!0,i.$container.addClass("fancybox-is-grabbing")),2===i.startPoints.length&&"image"===u.type&&(u.isLoaded||u.$ghost)&&(i.canTap=!1,i.isSwiping=!1,i.isPanning=!1,i.isZooming=!0,n.fancybox.stop(i.$content),i.centerPointStartX=.5*(i.startPoints[0].x+i.startPoints[1].x)-n(t).scrollLeft(),i.centerPointStartY=.5*(i.startPoints[0].y+i.startPoints[1].y)-n(t).scrollTop(),i.percentageOfImageAtPinchPointX=(i.centerPointStartX-i.contentStartPos.left)/i.contentStartPos.width,i.percentageOfImageAtPinchPointY=(i.centerPointStartY-i.contentStartPos.top)/i.contentStartPos.height,i.startDistanceBetweenFingers=s(i.startPoints[0],i.startPoints[1]))))}},d.prototype.onscroll=function(t){var n=this;n.isScrolling=!0,e.removeEventListener("scroll",n.onscroll,!0)},d.prototype.ontouchmove=function(t){var e=this;return void 0!==t.originalEvent.buttons&&0===t.originalEvent.buttons?void e.ontouchend(t):e.isScrolling?void(e.canTap=!1):(e.newPoints=a(t),void((e.opts||e.canPan)&&e.newPoints.length&&e.newPoints.length&&(e.isSwiping&&!0===e.isSwiping||t.preventDefault(),e.distanceX=s(e.newPoints[0],e.startPoints[0],"x"),e.distanceY=s(e.newPoints[0],e.startPoints[0],"y"),e.distance=s(e.newPoints[0],e.startPoints[0]),e.distance>0&&(e.isSwiping?e.onSwipe(t):e.isPanning?e.onPan():e.isZooming&&e.onZoom()))))},d.prototype.onSwipe=function(e){var a,s=this,r=s.instance,c=s.isSwiping,l=s.sliderStartPos.left||0;if(!0!==c)"x"==c&&(s.distanceX>0&&(s.instance.group.length<2||0===s.instance.current.index&&!s.instance.current.opts.loop)?l+=Math.pow(s.distanceX,.8):s.distanceX<0&&(s.instance.group.length<2||s.instance.current.index===s.instance.group.length-1&&!s.instance.current.opts.loop)?l-=Math.pow(-s.distanceX,.8):l+=s.distanceX),s.sliderLastPos={top:"x"==c?0:s.sliderStartPos.top+s.distanceY,left:l},s.requestId&&(i(s.requestId),s.requestId=null),s.requestId=o(function(){s.sliderLastPos&&(n.each(s.instance.slides,function(t,e){var o=e.pos-s.instance.currPos;n.fancybox.setTranslate(e.$slide,{top:s.sliderLastPos.top,left:s.sliderLastPos.left+o*s.canvasWidth+o*e.opts.gutter})}),s.$container.addClass("fancybox-is-sliding"))});else if(Math.abs(s.distance)>10){if(s.canTap=!1,r.group.length<2&&s.opts.vertical?s.isSwiping="y":r.isDragging||!1===s.opts.vertical||"auto"===s.opts.vertical&&n(t).width()>800?s.isSwiping="x":(a=Math.abs(180*Math.atan2(s.distanceY,s.distanceX)/Math.PI),s.isSwiping=a>45&&a<135?"y":"x"),"y"===s.isSwiping&&n.fancybox.isMobile&&s.isScrollable)return void(s.isScrolling=!0);r.isDragging=s.isSwiping,s.startPoints=s.newPoints,n.each(r.slides,function(t,e){var o,i;n.fancybox.stop(e.$slide),o=n.fancybox.getTranslate(e.$slide),i=n.fancybox.getTranslate(r.$refs.stage),e.$slide.css({transform:"",opacity:"","transition-duration":""}).removeClass("fancybox-animated").removeClass(function(t,e){return(e.match(/(^|\s)fancybox-fx-\S+/g)||[]).join(" ")}),e.pos===r.current.pos&&(s.sliderStartPos.top=o.top-i.top,s.sliderStartPos.left=o.left-i.left),n.fancybox.setTranslate(e.$slide,{top:o.top-i.top,left:o.left-i.left})}),r.SlideShow&&r.SlideShow.isActive&&r.SlideShow.stop()}},d.prototype.onPan=function(){var t=this;if(s(t.newPoints[0],t.realPoints[0])<(n.fancybox.isMobile?10:5))return void(t.startPoints=t.newPoints);t.canTap=!1,t.contentLastPos=t.limitMovement(),t.requestId&&i(t.requestId),t.requestId=o(function(){n.fancybox.setTranslate(t.$content,t.contentLastPos)})},d.prototype.limitMovement=function(){var t,e,n,o,i,a,s=this,r=s.canvasWidth,c=s.canvasHeight,l=s.distanceX,d=s.distanceY,u=s.contentStartPos,f=u.left,p=u.top,h=u.width,g=u.height;return i=h>r?f+l:f,a=p+d,t=Math.max(0,.5*r-.5*h),e=Math.max(0,.5*c-.5*g),n=Math.min(r-h,.5*r-.5*h),o=Math.min(c-g,.5*c-.5*g),l>0&&i>t&&(i=t-1+Math.pow(-t+f+l,.8)||0),l<0&&i<n&&(i=n+1-Math.pow(n-f-l,.8)||0),d>0&&a>e&&(a=e-1+Math.pow(-e+p+d,.8)||0),d<0&&a<o&&(a=o+1-Math.pow(o-p-d,.8)||0),{top:a,left:i}},d.prototype.limitPosition=function(t,e,n,o){var i=this,a=i.canvasWidth,s=i.canvasHeight;return n>a?(t=t>0?0:t,t=t<a-n?a-n:t):t=Math.max(0,a/2-n/2),o>s?(e=e>0?0:e,e=e<s-o?s-o:e):e=Math.max(0,s/2-o/2),{top:e,left:t}},d.prototype.onZoom=function(){var e=this,a=e.contentStartPos,r=a.width,c=a.height,l=a.left,d=a.top,u=s(e.newPoints[0],e.newPoints[1]),f=u/e.startDistanceBetweenFingers,p=Math.floor(r*f),h=Math.floor(c*f),g=(r-p)*e.percentageOfImageAtPinchPointX,b=(c-h)*e.percentageOfImageAtPinchPointY,m=(e.newPoints[0].x+e.newPoints[1].x)/2-n(t).scrollLeft(),v=(e.newPoints[0].y+e.newPoints[1].y)/2-n(t).scrollTop(),y=m-e.centerPointStartX,x=v-e.centerPointStartY,w=l+(g+y),$=d+(b+x),S={top:$,left:w,scaleX:f,scaleY:f};e.canTap=!1,e.newWidth=p,e.newHeight=h,e.contentLastPos=S,e.requestId&&i(e.requestId),e.requestId=o(function(){n.fancybox.setTranslate(e.$content,e.contentLastPos)})},d.prototype.ontouchend=function(t){var o=this,s=o.isSwiping,r=o.isPanning,c=o.isZooming,l=o.isScrolling;if(o.endPoints=a(t),o.dMs=Math.max((new Date).getTime()-o.startTime,1),o.$container.removeClass("fancybox-is-grabbing"),n(e).off(".fb.touch"),e.removeEventListener("scroll",o.onscroll,!0),o.requestId&&(i(o.requestId),o.requestId=null),o.isSwiping=!1,o.isPanning=!1,o.isZooming=!1,o.isScrolling=!1,o.instance.isDragging=!1,o.canTap)return o.onTap(t);o.speed=100,o.velocityX=o.distanceX/o.dMs*.5,o.velocityY=o.distanceY/o.dMs*.5,r?o.endPanning():c?o.endZooming():o.endSwiping(s,l)},d.prototype.endSwiping=function(t,e){var o=this,i=!1,a=o.instance.group.length,s=Math.abs(o.distanceX),r="x"==t&&a>1&&(o.dMs>130&&s>10||s>50);o.sliderLastPos=null,"y"==t&&!e&&Math.abs(o.distanceY)>50?(n.fancybox.animate(o.instance.current.$slide,{top:o.sliderStartPos.top+o.distanceY+150*o.velocityY,opacity:0},200),i=o.instance.close(!0,250)):r&&o.distanceX>0?i=o.instance.previous(300):r&&o.distanceX<0&&(i=o.instance.next(300)),!1!==i||"x"!=t&&"y"!=t||o.instance.centerSlide(200),o.$container.removeClass("fancybox-is-sliding")},d.prototype.endPanning=function(){var t,e,o,i=this;i.contentLastPos&&(!1===i.opts.momentum||i.dMs>350?(t=i.contentLastPos.left,e=i.contentLastPos.top):(t=i.contentLastPos.left+500*i.velocityX,e=i.contentLastPos.top+500*i.velocityY),o=i.limitPosition(t,e,i.contentStartPos.width,i.contentStartPos.height),o.width=i.contentStartPos.width,o.height=i.contentStartPos.height,n.fancybox.animate(i.$content,o,366))},d.prototype.endZooming=function(){var t,e,o,i,a=this,s=a.instance.current,r=a.newWidth,c=a.newHeight;a.contentLastPos&&(t=a.contentLastPos.left,e=a.contentLastPos.top,i={top:e,left:t,width:r,height:c,scaleX:1,scaleY:1},n.fancybox.setTranslate(a.$content,i),r<a.canvasWidth&&c<a.canvasHeight?a.instance.scaleToFit(150):r>s.width||c>s.height?a.instance.scaleToActual(a.centerPointStartX,a.centerPointStartY,150):(o=a.limitPosition(t,e,r,c),n.fancybox.animate(a.$content,o,150)))},d.prototype.onTap=function(e){var o,i=this,s=n(e.target),r=i.instance,c=r.current,l=e&&a(e)||i.startPoints,d=l[0]?l[0].x-n(t).scrollLeft()-i.stagePos.left:0,u=l[0]?l[0].y-n(t).scrollTop()-i.stagePos.top:0,f=function(t){var o=c.opts[t];if(n.isFunction(o)&&(o=o.apply(r,[c,e])),o)switch(o){case"close":r.close(i.startEvent);break;case"toggleControls":r.toggleControls();break;case"next":r.next();break;case"nextOrClose":r.group.length>1?r.next():r.close(i.startEvent);break;case"zoom":"image"==c.type&&(c.isLoaded||c.$ghost)&&(r.canPan()?r.scaleToFit():r.isScaledDown()?r.scaleToActual(d,u):r.group.length<2&&r.close(i.startEvent))}};if((!e.originalEvent||2!=e.originalEvent.button)&&(s.is("img")||!(d>s[0].clientWidth+s.offset().left))){if(s.is(".fancybox-bg,.fancybox-inner,.fancybox-outer,.fancybox-container"))o="Outside";else if(s.is(".fancybox-slide"))o="Slide";else{if(!r.current.$content||!r.current.$content.find(s).addBack().filter(s).length)return;o="Content"}if(i.tapped){if(clearTimeout(i.tapped),i.tapped=null,Math.abs(d-i.tapX)>50||Math.abs(u-i.tapY)>50)return this;f("dblclick"+o)}else i.tapX=d,i.tapY=u,c.opts["dblclick"+o]&&c.opts["dblclick"+o]!==c.opts["click"+o]?i.tapped=setTimeout(function(){i.tapped=null,r.isAnimating||f("click"+o)},500):f("click"+o);return this}},n(e).on("onActivate.fb",function(t,e){e&&!e.Guestures&&(e.Guestures=new d(e))}).on("beforeClose.fb",function(t,e){e&&e.Guestures&&e.Guestures.destroy()})}(window,document,jQuery),function(t,e){"use strict";e.extend(!0,e.fancybox.defaults,{btnTpl:{slideShow:'<button data-fancybox-play class="fancybox-button fancybox-button--play" title="{{PLAY_START}}"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M6.5 5.4v13.2l11-6.6z"/></svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M8.33 5.75h2.2v12.5h-2.2V5.75zm5.15 0h2.2v12.5h-2.2V5.75z"/></svg></button>'},slideShow:{autoStart:!1,speed:3e3,progress:!0}});var n=function(t){this.instance=t,this.init()};e.extend(n.prototype,{timer:null,isActive:!1,$button:null,init:function(){var t=this,n=t.instance,o=n.group[n.currIndex].opts.slideShow;t.$button=n.$refs.toolbar.find("[data-fancybox-play]").on("click",function(){t.toggle()}),n.group.length<2||!o?t.$button.hide():o.progress&&(t.$progress=e('<div class="fancybox-progress"></div>').appendTo(n.$refs.inner))},set:function(t){var n=this,o=n.instance,i=o.current;i&&(!0===t||i.opts.loop||o.currIndex<o.group.length-1)?n.isActive&&"video"!==i.contentType&&(n.$progress&&e.fancybox.animate(n.$progress.show(),{scaleX:1},i.opts.slideShow.speed),n.timer=setTimeout(function(){o.current.opts.loop||o.current.index!=o.group.length-1?o.next():o.jumpTo(0)},i.opts.slideShow.speed)):(n.stop(),o.idleSecondsCounter=0,o.showControls())},clear:function(){var t=this;clearTimeout(t.timer),t.timer=null,t.$progress&&t.$progress.removeAttr("style").hide()},start:function(){var t=this,e=t.instance.current;e&&(t.$button.attr("title",(e.opts.i18n[e.opts.lang]||e.opts.i18n.en).PLAY_STOP).removeClass("fancybox-button--play").addClass("fancybox-button--pause"),t.isActive=!0,e.isComplete&&t.set(!0),t.instance.trigger("onSlideShowChange",!0))},stop:function(){var t=this,e=t.instance.current;t.clear(),t.$button.attr("title",(e.opts.i18n[e.opts.lang]||e.opts.i18n.en).PLAY_START).removeClass("fancybox-button--pause").addClass("fancybox-button--play"),t.isActive=!1,t.instance.trigger("onSlideShowChange",!1),t.$progress&&t.$progress.removeAttr("style").hide()},toggle:function(){var t=this;t.isActive?t.stop():t.start()}}),e(t).on({"onInit.fb":function(t,e){e&&!e.SlideShow&&(e.SlideShow=new n(e))},"beforeShow.fb":function(t,e,n,o){var i=e&&e.SlideShow;o?i&&n.opts.slideShow.autoStart&&i.start():i&&i.isActive&&i.clear()},"afterShow.fb":function(t,e,n){var o=e&&e.SlideShow;o&&o.isActive&&o.set()},"afterKeydown.fb":function(n,o,i,a,s){var r=o&&o.SlideShow;!r||!i.opts.slideShow||80!==s&&32!==s||e(t.activeElement).is("button,a,input")||(a.preventDefault(),r.toggle())},"beforeClose.fb onDeactivate.fb":function(t,e){var n=e&&e.SlideShow;n&&n.stop()}}),e(t).on("visibilitychange",function(){var n=e.fancybox.getInstance(),o=n&&n.SlideShow;o&&o.isActive&&(t.hidden?o.clear():o.set())})}(document,jQuery),function(t,e){"use strict";var n=function(){for(var e=[["requestFullscreen","exitFullscreen","fullscreenElement","fullscreenEnabled","fullscreenchange","fullscreenerror"],["webkitRequestFullscreen","webkitExitFullscreen","webkitFullscreenElement","webkitFullscreenEnabled","webkitfullscreenchange","webkitfullscreenerror"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitCurrentFullScreenElement","webkitCancelFullScreen","webkitfullscreenchange","webkitfullscreenerror"],["mozRequestFullScreen","mozCancelFullScreen","mozFullScreenElement","mozFullScreenEnabled","mozfullscreenchange","mozfullscreenerror"],["msRequestFullscreen","msExitFullscreen","msFullscreenElement","msFullscreenEnabled","MSFullscreenChange","MSFullscreenError"]],n={},o=0;o<e.length;o++){var i=e[o];if(i&&i[1]in t){for(var a=0;a<i.length;a++)n[e[0][a]]=i[a];return n}}return!1}();if(n){var o={request:function(e){e=e||t.documentElement,e[n.requestFullscreen](e.ALLOW_KEYBOARD_INPUT)},exit:function(){t[n.exitFullscreen]()},toggle:function(e){e=e||t.documentElement,this.isFullscreen()?this.exit():this.request(e)},isFullscreen:function(){return Boolean(t[n.fullscreenElement])},enabled:function(){return Boolean(t[n.fullscreenEnabled])}};e.extend(!0,e.fancybox.defaults,{btnTpl:{fullScreen:'<button data-fancybox-fullscreen class="fancybox-button fancybox-button--fsenter" title="{{FULL_SCREEN}}"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"/></svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M5 16h3v3h2v-5H5zm3-8H5v2h5V5H8zm6 11h2v-3h3v-2h-5zm2-11V5h-2v5h5V8z"/></svg></button>'},fullScreen:{autoStart:!1}}),e(t).on(n.fullscreenchange,function(){var t=o.isFullscreen(),n=e.fancybox.getInstance();n&&(n.current&&"image"===n.current.type&&n.isAnimating&&(n.isAnimating=!1,n.update(!0,!0,0),n.isComplete||n.complete()),n.trigger("onFullscreenChange",t),n.$refs.container.toggleClass("fancybox-is-fullscreen",t),n.$refs.toolbar.find("[data-fancybox-fullscreen]").toggleClass("fancybox-button--fsenter",!t).toggleClass("fancybox-button--fsexit",t))})}e(t).on({"onInit.fb":function(t,e){var i;if(!n)return void e.$refs.toolbar.find("[data-fancybox-fullscreen]").remove();e&&e.group[e.currIndex].opts.fullScreen?(i=e.$refs.container,i.on("click.fb-fullscreen","[data-fancybox-fullscreen]",function(t){t.stopPropagation(),t.preventDefault(),o.toggle()}),e.opts.fullScreen&&!0===e.opts.fullScreen.autoStart&&o.request(),e.FullScreen=o):e&&e.$refs.toolbar.find("[data-fancybox-fullscreen]").hide()},"afterKeydown.fb":function(t,e,n,o,i){e&&e.FullScreen&&70===i&&(o.preventDefault(),e.FullScreen.toggle())},"beforeClose.fb":function(t,e){e&&e.FullScreen&&e.$refs.container.hasClass("fancybox-is-fullscreen")&&o.exit()}})}(document,jQuery),function(t,e){"use strict";var n="fancybox-thumbs";e.fancybox.defaults=e.extend(!0,{btnTpl:{thumbs:'<button data-fancybox-thumbs class="fancybox-button fancybox-button--thumbs" title="{{THUMBS}}"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M14.59 14.59h3.76v3.76h-3.76v-3.76zm-4.47 0h3.76v3.76h-3.76v-3.76zm-4.47 0h3.76v3.76H5.65v-3.76zm8.94-4.47h3.76v3.76h-3.76v-3.76zm-4.47 0h3.76v3.76h-3.76v-3.76zm-4.47 0h3.76v3.76H5.65v-3.76zm8.94-4.47h3.76v3.76h-3.76V5.65zm-4.47 0h3.76v3.76h-3.76V5.65zm-4.47 0h3.76v3.76H5.65V5.65z"/></svg></button>'},thumbs:{autoStart:!1,hideOnClose:!0,parentEl:".fancybox-container",axis:"y"}},e.fancybox.defaults);var o=function(t){this.init(t)};e.extend(o.prototype,{$button:null,$grid:null,$list:null,isVisible:!1,isActive:!1,init:function(t){var e=this,n=t.group,o=0;e.instance=t,e.opts=n[t.currIndex].opts.thumbs,t.Thumbs=e,e.$button=t.$refs.toolbar.find("[data-fancybox-thumbs]");for(var i=0,a=n.length;i<a&&(n[i].thumb&&o++,!(o>1));i++);o>1&&e.opts?(e.$button.removeAttr("style").on("click",function(){e.toggle()}),e.isActive=!0):e.$button.hide()},create:function(){var t,o=this,i=o.instance,a=o.opts.parentEl,s=[];o.$grid||(o.$grid=e('<div class="'+n+" "+n+"-"+o.opts.axis+'"></div>').appendTo(i.$refs.container.find(a).addBack().filter(a)),o.$grid.on("click","a",function(){i.jumpTo(e(this).attr("data-index"))})),o.$list||(o.$list=e('<div class="'+n+'__list">').appendTo(o.$grid)),e.each(i.group,function(e,n){t=n.thumb,t||"image"!==n.type||(t=n.src),s.push('<a href="javascript:;" tabindex="0" data-index="'+e+'"'+(t&&t.length?' style="background-image:url('+t+')"':'class="fancybox-thumbs-missing"')+"></a>")}),o.$list[0].innerHTML=s.join(""),"x"===o.opts.axis&&o.$list.width(parseInt(o.$grid.css("padding-right"),10)+i.group.length*o.$list.children().eq(0).outerWidth(!0))},focus:function(t){var e,n,o=this,i=o.$list,a=o.$grid;o.instance.current&&(e=i.children().removeClass("fancybox-thumbs-active").filter('[data-index="'+o.instance.current.index+'"]').addClass("fancybox-thumbs-active"),n=e.position(),"y"===o.opts.axis&&(n.top<0||n.top>i.height()-e.outerHeight())?i.stop().animate({scrollTop:i.scrollTop()+n.top},t):"x"===o.opts.axis&&(n.left<a.scrollLeft()||n.left>a.scrollLeft()+(a.width()-e.outerWidth()))&&i.parent().stop().animate({scrollLeft:n.left},t))},update:function(){var t=this;t.instance.$refs.container.toggleClass("fancybox-show-thumbs",this.isVisible),t.isVisible?(t.$grid||t.create(),t.instance.trigger("onThumbsShow"),t.focus(0)):t.$grid&&t.instance.trigger("onThumbsHide"),t.instance.update()},hide:function(){this.isVisible=!1,this.update()},show:function(){this.isVisible=!0,this.update()},toggle:function(){this.isVisible=!this.isVisible,this.update()}}),e(t).on({"onInit.fb":function(t,e){var n;e&&!e.Thumbs&&(n=new o(e),n.isActive&&!0===n.opts.autoStart&&n.show())},"beforeShow.fb":function(t,e,n,o){var i=e&&e.Thumbs;i&&i.isVisible&&i.focus(o?0:250)},"afterKeydown.fb":function(t,e,n,o,i){var a=e&&e.Thumbs;a&&a.isActive&&71===i&&(o.preventDefault(),a.toggle())},"beforeClose.fb":function(t,e){var n=e&&e.Thumbs;n&&n.isVisible&&!1!==n.opts.hideOnClose&&n.$grid.hide()}})}(document,jQuery),function(t,e){"use strict";function n(t){var e={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;","`":"&#x60;","=":"&#x3D;"};return String(t).replace(/[&<>"'`=\/]/g,function(t){return e[t]})}e.extend(!0,e.fancybox.defaults,{btnTpl:{share:'<button data-fancybox-share class="fancybox-button fancybox-button--share" title="{{SHARE}}"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M2.55 19c1.4-8.4 9.1-9.8 11.9-9.8V5l7 7-7 6.3v-3.5c-2.8 0-10.5 2.1-11.9 4.2z"/></svg></button>'},share:{url:function(t,e){return!t.currentHash&&"inline"!==e.type&&"html"!==e.type&&(e.origSrc||e.src)||window.location},
13
+ tpl:'<div class="fancybox-share"><h1>{{SHARE}}</h1><p><a class="fancybox-share__button fancybox-share__button--fb" href="https://www.facebook.com/sharer/sharer.php?u={{url}}"><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="m287 456v-299c0-21 6-35 35-35h38v-63c-7-1-29-3-55-3-54 0-91 33-91 94v306m143-254h-205v72h196" /></svg><span>Facebook</span></a><a class="fancybox-share__button fancybox-share__button--tw" href="https://twitter.com/intent/tweet?url={{url}}&text={{descr}}"><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="m456 133c-14 7-31 11-47 13 17-10 30-27 37-46-15 10-34 16-52 20-61-62-157-7-141 75-68-3-129-35-169-85-22 37-11 86 26 109-13 0-26-4-37-9 0 39 28 72 65 80-12 3-25 4-37 2 10 33 41 57 77 57-42 30-77 38-122 34 170 111 378-32 359-208 16-11 30-25 41-42z" /></svg><span>Twitter</span></a><a class="fancybox-share__button fancybox-share__button--pt" href="https://www.pinterest.com/pin/create/button/?url={{url}}&description={{descr}}&media={{media}}"><svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="m265 56c-109 0-164 78-164 144 0 39 15 74 47 87 5 2 10 0 12-5l4-19c2-6 1-8-3-13-9-11-15-25-15-45 0-58 43-110 113-110 62 0 96 38 96 88 0 67-30 122-73 122-24 0-42-19-36-44 6-29 20-60 20-81 0-19-10-35-31-35-25 0-44 26-44 60 0 21 7 36 7 36l-30 125c-8 37-1 83 0 87 0 3 4 4 5 2 2-3 32-39 42-75l16-64c8 16 31 29 56 29 74 0 124-67 124-157 0-69-58-132-146-132z" fill="#fff"/></svg><span>Pinterest</span></a></p><p><input class="fancybox-share__input" type="text" value="{{url_raw}}" onclick="select()" /></p></div>'}}),e(t).on("click","[data-fancybox-share]",function(){var t,o,i=e.fancybox.getInstance(),a=i.current||null;a&&("function"===e.type(a.opts.share.url)&&(t=a.opts.share.url.apply(a,[i,a])),o=a.opts.share.tpl.replace(/\{\{media\}\}/g,"image"===a.type?encodeURIComponent(a.src):"").replace(/\{\{url\}\}/g,encodeURIComponent(t)).replace(/\{\{url_raw\}\}/g,n(t)).replace(/\{\{descr\}\}/g,i.$caption?encodeURIComponent(i.$caption.text()):""),e.fancybox.open({src:i.translate(i,o),type:"html",opts:{touch:!1,animationEffect:!1,afterLoad:function(t,e){i.$refs.container.one("beforeClose.fb",function(){t.close(null,0)}),e.$content.find(".fancybox-share__button").click(function(){return window.open(this.href,"Share","width=550, height=450"),!1})},mobile:{autoFocus:!1}}}))})}(document,jQuery),function(t,e,n){"use strict";function o(){var e=t.location.hash.substr(1),n=e.split("-"),o=n.length>1&&/^\+?\d+$/.test(n[n.length-1])?parseInt(n.pop(-1),10)||1:1,i=n.join("-");return{hash:e,index:o<1?1:o,gallery:i}}function i(t){""!==t.gallery&&n("[data-fancybox='"+n.escapeSelector(t.gallery)+"']").eq(t.index-1).focus().trigger("click.fb-start")}function a(t){var e,n;return!!t&&(e=t.current?t.current.opts:t.opts,""!==(n=e.hash||(e.$orig?e.$orig.data("fancybox")||e.$orig.data("fancybox-trigger"):""))&&n)}n.escapeSelector||(n.escapeSelector=function(t){return(t+"").replace(/([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g,function(t,e){return e?"\0"===t?"�":t.slice(0,-1)+"\\"+t.charCodeAt(t.length-1).toString(16)+" ":"\\"+t})}),n(function(){!1!==n.fancybox.defaults.hash&&(n(e).on({"onInit.fb":function(t,e){var n,i;!1!==e.group[e.currIndex].opts.hash&&(n=o(),(i=a(e))&&n.gallery&&i==n.gallery&&(e.currIndex=n.index-1))},"beforeShow.fb":function(n,o,i,s){var r;i&&!1!==i.opts.hash&&(r=a(o))&&(o.currentHash=r+(o.group.length>1?"-"+(i.index+1):""),t.location.hash!=="#"+o.currentHash&&(s&&!o.origHash&&(o.origHash=t.location.hash),o.hashTimer&&clearTimeout(o.hashTimer),o.hashTimer=setTimeout(function(){"replaceState"in t.history?(t.history[s?"pushState":"replaceState"]({},e.title,t.location.pathname+t.location.search+"#"+o.currentHash),s&&(o.hasCreatedHistory=!0)):t.location.hash=o.currentHash,o.hashTimer=null},300)))},"beforeClose.fb":function(n,o,i){i&&!1!==i.opts.hash&&(clearTimeout(o.hashTimer),o.currentHash&&o.hasCreatedHistory?t.history.back():o.currentHash&&("replaceState"in t.history?t.history.replaceState({},e.title,t.location.pathname+t.location.search+(o.origHash||"")):t.location.hash=o.origHash),o.currentHash=null)}}),n(t).on("hashchange.fb",function(){var t=o(),e=null;n.each(n(".fancybox-container").get().reverse(),function(t,o){var i=n(o).data("FancyBox");if(i&&i.currentHash)return e=i,!1}),e?e.currentHash===t.gallery+"-"+t.index||1===t.index&&e.currentHash==t.gallery||(e.currentHash=null,e.close()):""!==t.gallery&&i(t)}),setTimeout(function(){n.fancybox.getInstance()||i(o())},50))})}(window,document,jQuery),function(t,e){"use strict";var n=(new Date).getTime();e(t).on({"onInit.fb":function(t,e,o){e.$refs.stage.on("mousewheel DOMMouseScroll wheel MozMousePixelScroll",function(t){var o=e.current,i=(new Date).getTime();e.group.length<2||!1===o.opts.wheel||"auto"===o.opts.wheel&&"image"!==o.type||(t.preventDefault(),t.stopPropagation(),o.$slide.hasClass("fancybox-animated")||(t=t.originalEvent||t,i-n<250||(n=i,e[(-t.deltaY||-t.deltaX||t.wheelDelta||-t.detail)<0?"next":"previous"]())))})}})}(document,jQuery);
resources/js/{jquery.fileDownload.js → jquery/fileDownload.js} RENAMED
File without changes
resources/js/{u2f-frontend.js → login/u2f.js} RENAMED
File without changes
resources/js/plugin.js CHANGED
@@ -332,7 +332,7 @@ jQuery.fn.icwpWpsfAjaxTable = function ( aOptions ) {
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='
332
  if ( typeof icwp_wpsf_vars_plugin !== 'undefined' ) {
333
 
334
  jQuery( document ).ready( function () {
335
+ jQuery( document ).on( 'click', 'a.shield_file_download, a.shield_file_download ', function ( evt ) {
336
  evt.preventDefault();
337
  /** Cache busting **/
338
  let url = jQuery( this ).attr( 'href' ) + '&rand='
resources/js/shield/antibot.js CHANGED
@@ -20,8 +20,21 @@ if ( typeof Shield_Antibot === typeof undefined && typeof shield_vars_antibotjs
20
  }
21
 
22
  this.initialise = function () {
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  domReady( function () {
24
- fire();
25
  } );
26
  };
27
 
@@ -58,5 +71,6 @@ if ( typeof Shield_Antibot === typeof undefined && typeof shield_vars_antibotjs
58
  if ( parts.length === 2 ) return parts.pop().split( ";" ).shift();
59
  };
60
  }();
 
61
  Shield_Antibot.initialise();
62
  }
20
  }
21
 
22
  this.initialise = function () {
23
+ /**
24
+ * @since 11.2 we no longer wait until DOM is ready.
25
+ * This is mainly AJAX so it's asynchronous and wont hold up any other part of the page load.
26
+ * Early execution also helps mitigate the case where login requests are
27
+ * sent quickly, before browser has fired NotBot request.
28
+ */
29
+ if ( shield_vars_antibotjs.flags.run ) {
30
+ sendReq();
31
+ }
32
+ /**
33
+ * @since 11.2 this script is only loaded if a not bot signal doesn't exist for this IP.
34
+ * This removes the need for cookies - as used by fire()
35
+ */
36
  domReady( function () {
37
+ // fire();
38
  } );
39
  };
40
 
71
  if ( parts.length === 2 ) return parts.pop().split( ";" ).shift();
72
  };
73
  }();
74
+
75
  Shield_Antibot.initialise();
76
  }
resources/js/shield/dialog.js ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ var Shield_Dialogs = new function () {
2
+
3
+ this.show = function ( $dialog, options ) {
4
+ $dialog.dialog( jQuery.extend( {
5
+ classes: {
6
+ 'ui-dialog': 'shield_dialog'
7
+ }
8
+ }, options ) );
9
+ };
10
+ }();
resources/js/shield/navigation.js CHANGED
@@ -43,7 +43,7 @@ jQuery.fn.icwpWpsfPluginNavigation = function ( options ) {
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() );
43
 
44
  jQuery( document ).ready( function () {
45
 
46
+ jQuery( document ).on( 'click', 'a.dynamic_body_load', function ( evt ) {
47
  evt.preventDefault();
48
  currentMenuClickTarget = evt.currentTarget;
49
  renderDynamicPageLoad( jQuery( currentMenuClickTarget ).data() );
resources/js/shield/tours.js CHANGED
@@ -8,16 +8,33 @@ jQuery.fn.icwpWpsfTours = function ( options ) {
8
  } );
9
  }
10
 
11
- var setupTour = function ( tour_key ) {
12
- introJs().setOptions( getTourSettings( tour_key ) )
13
  .onexit( function () {
14
- markTourFinished( tour_key );
15
  } )
16
  .start();
17
  }
18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  var getTourSettings = function ( tourKey ) {
20
  return {
 
21
  overlayOpacity: 0.7,
22
  highlightClass: "tour-" + tourKey,
23
  tooltipClass: "shield_tour_tooltip",
8
  } );
9
  }
10
 
11
+ var setupTour = function ( tourKey ) {
12
+ introJs().setOptions( getTourSettings( tourKey ) )
13
  .onexit( function () {
14
+ markTourFinished( tourKey );
15
  } )
16
  .start();
17
  }
18
 
19
+ var buildStepsForTour = function ( tourKey ) {
20
+ let steps = [];
21
+ let tourItems = document.querySelectorAll( '.tour-' + tourKey );
22
+ for ( var i = 0; i < tourItems.length; i++ ) {
23
+ let step = {
24
+ element: tourItems[ i ],
25
+ intro: tourItems[ i ].dataset.intro
26
+ };
27
+ if ( typeof tourItems[ i ].dataset.introtitle !== typeof undefined ) {
28
+ step.title = tourItems[ i ].dataset.introtitle;
29
+ }
30
+ steps.push(step);
31
+ }
32
+ return steps;
33
+ }
34
+
35
  var getTourSettings = function ( tourKey ) {
36
  return {
37
+ steps: buildStepsForTour( tourKey ),
38
  overlayOpacity: 0.7,
39
  highlightClass: "tour-" + tourKey,
40
  tooltipClass: "shield_tour_tooltip",
resources/js/shield/u2f-admin.js DELETED
@@ -1,64 +0,0 @@
1
- if ( typeof icwp_wpsf_vars_u2f !== 'undefined' ) {
2
- jQuery( document ).ready( function () {
3
-
4
- let $oBtnReg = jQuery( 'button#icwp_u2f_key_reg' );
5
- let $oU2fStatus = jQuery( '#icwp_u2f_section p.description' );
6
- let oLabelRegEx = new RegExp( "^[a-zA-Z0-9_-]{1,16}$" );
7
-
8
- u2fApi.isSupported()
9
- .then( function ( supported ) {
10
- if ( supported ) {
11
- $oBtnReg.prop( 'disabled', false );
12
- $oBtnReg.on( 'click', function () {
13
- let label = prompt( icwp_wpsf_vars_u2f.strings.prompt_dialog, "<Insert Label>" );
14
- if ( typeof label === 'undefined' || label === null ) {
15
- alert( icwp_wpsf_vars_u2f.strings.err_no_label )
16
- }
17
- else if ( !oLabelRegEx.test( label ) ) {
18
- alert( icwp_wpsf_vars_u2f.strings.err_invalid_label )
19
- }
20
- else {
21
- u2fApi.register( icwp_wpsf_vars_u2f.reg_request, icwp_wpsf_vars_u2f.signs )
22
- .then( function ( response ) {
23
- response.label = label;
24
- jQuery( '#icwp_wpsf_new_u2f_response' ).val( JSON.stringify( response ) )
25
- $oU2fStatus.text( icwp_wpsf_vars_u2f.strings.do_save );
26
- $oU2fStatus.css( 'font-weight', 'bolder' )
27
- .css( 'color', 'green' );
28
- } )
29
- .catch( function ( response ) {
30
- $oU2fStatus.text( icwp_wpsf_vars_u2f.strings.failed );
31
- $oU2fStatus.css( 'font-weight', 'bolder' )
32
- .css( 'color', 'red' );
33
- } );
34
- }
35
- } );
36
- }
37
- else {
38
- $oBtnReg.prop( 'disabled', true );
39
- $oU2fStatus.text( icwp_wpsf_vars_u2f.strings.not_supported );
40
- }
41
- } )
42
- .catch();
43
-
44
- } );
45
-
46
- jQuery.fn.icwpWpsfProfileU2f = function () {
47
-
48
- var initialise = function () {
49
- jQuery( document ).ready( function () {
50
- jQuery( 'a.icwpWpsf-U2FRemove' ).on( 'click', function ( evt ) {
51
- evt.preventDefault();
52
- icwp_wpsf_vars_u2f.ajax.u2f_remove.u2fid = jQuery( evt.currentTarget ).data( 'u2fid' );
53
- iCWP_WPSF_StandardAjax.send_ajax_req( icwp_wpsf_vars_u2f.ajax.u2f_remove );
54
- return false;
55
- } )
56
- } );
57
- };
58
-
59
- initialise();
60
- return this;
61
- };
62
-
63
- jQuery( document ).icwpWpsfProfileU2f();
64
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
resources/js/shield/userprofile.js CHANGED
@@ -1,21 +1,186 @@
1
- if ( typeof icwp_wpsf_vars_profileyubikey !== 'undefined' ) {
2
- jQuery.fn.icwpWpsfProfileYubikey = function () {
3
-
4
- var initialise = function () {
5
- jQuery( document ).ready( function () {
6
- jQuery( 'a.icwpWpsf-YubikeyRemove' ).on( 'click', function ( evt ) {
7
- evt.preventDefault();
8
- icwp_wpsf_vars_profileyubikey.yubikey_remove.yubikeyid =
9
- jQuery( evt.currentTarget ).data( 'yubikeyid' );
10
- iCWP_WPSF_StandardAjax.send_ajax_req( icwp_wpsf_vars_profileyubikey.yubikey_remove );
11
- return false;
12
- } )
 
 
 
 
 
 
 
 
 
13
  } );
14
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
- initialise();
17
- return this;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  };
19
 
20
- jQuery( document ).icwpWpsfProfileYubikey();
21
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /** @var object shield_vars_userprofile */
2
+ jQuery.fn.ShieldUserProfile = function ( options ) {
3
+
4
+ let $emailCheckbox = jQuery( 'input[type=checkbox]#shield_enable_mfaemail' );
5
+ let $dialog = jQuery( '#ShieldMfaDialog' );
6
+ let $emailStartState;
7
+
8
+ let initGA = function ( shield_vars ) {
9
+ let $gaCode = jQuery( 'input[type=text]#shield_gacode' );
10
+ if ( $gaCode.length > 0 ) {
11
+ jQuery( document ).on( 'change, keyup', $gaCode, function ( evt ) {
12
+ $gaCode.val( $gaCode.val()
13
+ .replace( /[^A-F0-9]/gi, '' )
14
+ .toUpperCase()
15
+ .substring( 0, 6 )
16
+ );
17
+ if ( $gaCode.val().length === 6 ) {
18
+ $gaCode.prop( 'disabled', 'disabled' );
19
+ shield_vars.ajax.user_ga_toggle.ga_otp = $gaCode.val();
20
+ sendReq( shield_vars.ajax.user_ga_toggle );
21
+ }
22
  } );
23
+ }
24
+
25
+ jQuery( document ).on( 'click', '#shield_ga_remove', function ( evt ) {
26
+ sendReq( shield_vars.ajax.user_ga_toggle );
27
+ } );
28
+ }
29
+
30
+ let initMfaRemoveAll = function () {
31
+ jQuery( document ).on( 'click', 'button#ShieldMfaRemoveAll', function ( evt ) {
32
+ if ( confirm( shield_vars_userprofile.strings.are_you_sure ) ) {
33
+ shield_vars_userprofile.ajax.mfa_remove_all.user_id = jQuery( evt.currentTarget ).data( 'user_id' );
34
+ sendReq( shield_vars_userprofile.ajax.mfa_remove_all );
35
+ }
36
+ } );
37
+ };
38
+
39
+ let initBackupcodes = function ( shield_vars ) {
40
+ jQuery( document ).on( 'click', '#IcwpWpsfGenBackupLoginCode', function ( evt ) {
41
+ sendReq( shield_vars.ajax.gen_backup_codes );
42
+ } );
43
+ jQuery( document ).on( 'click', '#IcwpWpsfDelBackupLoginCode', function ( evt ) {
44
+ sendReq( shield_vars.ajax.del_backup_codes );
45
+ } );
46
+ };
47
+
48
+ let initYubi = function ( shield_vars ) {
49
+ let $yubiText = jQuery( 'input[type=text]#shield_yubi' );
50
+ jQuery( document ).on( 'keyup', $yubiText, function ( evt ) {
51
+ if ( evt.key === 'Enter' || evt.keyCode === 13 ) {
52
+ shield_vars.ajax.user_yubikey_toggle.otp = $yubiText.val();
53
+ sendReq( shield_vars.ajax.user_yubikey_toggle );
54
+ }
55
+ } );
56
+
57
+ jQuery( 'a.shield_yubi_remove' ).on( 'click', function ( evt ) {
58
+ evt.preventDefault();
59
+ shield_vars.ajax.user_yubikey_toggle.otp = jQuery( evt.currentTarget ).data( 'yubikeyid' );
60
+ sendReq( shield_vars.ajax.user_yubikey_toggle );
61
+ return false;
62
+ } )
63
+ };
64
+
65
+ let initEmail = function ( shield_vars ) {
66
+ $emailStartState = $emailCheckbox.is( ':checked' );
67
+ jQuery( document ).on( 'change', $emailCheckbox, function ( evt ) {
68
+ if ( $emailStartState !== $emailCheckbox.is( ':checked' ) ) {
69
+ $emailCheckbox.prop( 'disabled', true );
70
+ shield_vars.ajax.user_email2fa_toggle.direction = $emailCheckbox.is( ':checked' ) ? 'on' : 'off';
71
+ sendReq( shield_vars.ajax.user_email2fa_toggle );
72
+ }
73
+ } );
74
+ }
75
+
76
+ let initU2f = function ( shield_vars ) {
77
 
78
+ let $registerButton = jQuery( 'button#icwp_u2f_key_reg' );
79
+ let $oU2fStatus = jQuery( '#icwp_u2f_section p.description' );
80
+ let oLabelRegEx = new RegExp( "^[a-zA-Z0-9_-]{1,16}$" );
81
+
82
+ u2fApi.isSupported()
83
+ .then( function ( supported ) {
84
+ if ( supported ) {
85
+ $registerButton.prop( 'disabled', false );
86
+ $registerButton.on( 'click', function () {
87
+ let label = prompt( shield_vars.strings.prompt_dialog, "<Insert Label>" );
88
+ if ( typeof label === 'undefined' || label === null ) {
89
+ alert( shield_vars.strings.err_no_label )
90
+ }
91
+ else if ( !oLabelRegEx.test( label ) ) {
92
+ alert( shield_vars.strings.err_invalid_label )
93
+ }
94
+ else {
95
+ u2fApi.register( shield_vars.reg_request, shield_vars.signs )
96
+ .then( function ( u2fResponse ) {
97
+ u2fResponse.label = label;
98
+ shield_vars.ajax.u2f_add.icwp_wpsf_new_u2f_response = u2fResponse;
99
+ sendReq( shield_vars.ajax.u2f_add );
100
+ } )
101
+ .catch( function ( response ) {
102
+ $oU2fStatus.text( shield_vars.strings.failed );
103
+ $oU2fStatus.css( 'font-weight', 'bolder' )
104
+ .css( 'color', 'red' );
105
+ } );
106
+ }
107
+ } );
108
+ }
109
+ else {
110
+ $registerButton.prop( 'disabled', true );
111
+ $oU2fStatus.text( shield_vars.strings.not_supported );
112
+ }
113
+ } )
114
+ .catch();
115
+
116
+ jQuery( 'a.icwpWpsf-U2FRemove' ).on( 'click', function ( evt ) {
117
+ evt.preventDefault();
118
+ shield_vars.ajax.u2f_remove.u2fid = jQuery( evt.currentTarget ).data( 'u2fid' );
119
+ sendReq( shield_vars.ajax.u2f_remove );
120
+ return false;
121
+ } );
122
+ };
123
+
124
+ var sendReq = function ( reqParams ) {
125
+ let ajaxurl = reqParams.ajaxurl;
126
+ delete reqParams.ajaxurl;
127
+
128
+ jQuery( 'body' ).css( 'cursor', 'progress' );
129
+ jQuery.post( ajaxurl, reqParams, function ( response ) {
130
+
131
+ let msg = 'Communications error with site.';
132
+ if ( response.data.message !== undefined ) {
133
+ msg = response.data.message;
134
+ }
135
+
136
+ showDialog( response.data.success, msg )
137
+ }
138
+ ).always( function () {
139
+ }
140
+ );
141
+ };
142
+
143
+ var showDialog = function ( success, msg ) {
144
+ jQuery( '.dialog-content', $dialog ).html( msg );
145
+ Shield_Dialogs.show($dialog, {
146
+ title: success ? 'Success' : 'Failure',
147
+ buttons: [
148
+ {
149
+ text: 'OK',
150
+ click: function () {
151
+ jQuery( this ).dialog( 'close' );
152
+ }
153
+ }
154
+ ],
155
+ close: function ( event, ui ) {
156
+ location.reload();
157
+ }
158
+ });
159
  };
160
 
161
+ var initialise = function () {
162
+ jQuery( document ).ready( function () {
163
+ if ( typeof shield_vars_userprofile.vars.providers.u2f !== typeof undefined ) {
164
+ initU2f( shield_vars_userprofile.vars.providers.u2f );
165
+ }
166
+ if ( typeof shield_vars_userprofile.vars.providers.ga !== typeof undefined ) {
167
+ initGA( shield_vars_userprofile.vars.providers.ga );
168
+ }
169
+ if ( typeof shield_vars_userprofile.vars.providers.email !== typeof undefined ) {
170
+ initEmail( shield_vars_userprofile.vars.providers.email );
171
+ }
172
+ if ( typeof shield_vars_userprofile.vars.providers.yubi !== typeof undefined ) {
173
+ initYubi( shield_vars_userprofile.vars.providers.yubi );
174
+ }
175
+ if ( typeof shield_vars_userprofile.vars.providers.backupcode !== typeof undefined ) {
176
+ initBackupcodes( shield_vars_userprofile.vars.providers.backupcode );
177
+ }
178
+ initMfaRemoveAll();
179
+ } );
180
+ };
181
+
182
+ initialise();
183
+
184
+ return this;
185
+ };
186
+ jQuery( document ).ShieldUserProfile();
resources/js/shield/wizard.js ADDED
File without changes
src/config/feature-autoupdates.php CHANGED
@@ -67,7 +67,7 @@
67
  "default": "N",
68
  "type": "checkbox",
69
  "link_info": "https://shsec.io/3v",
70
- "link_blog": "",
71
  "name": "Disable All",
72
  "summary": "Completely Disable WordPress Automatic Updates",
73
  "description": "When selected, regardless of any other settings, all WordPress automatic updates on this site will be completely disabled!"
@@ -91,7 +91,7 @@
91
  "text": "Major and Minor Versions"
92
  }
93
  ],
94
- "link_info": "https://shsec.io/3x",
95
  "link_blog": "",
96
  "name": "WordPress Core Updates",
97
  "summary": "Decide how the WordPress Core will automatically update, if at all",
67
  "default": "N",
68
  "type": "checkbox",
69
  "link_info": "https://shsec.io/3v",
70
+ "link_blog": "https://shsec.io/k6",
71
  "name": "Disable All",
72
  "summary": "Completely Disable WordPress Automatic Updates",
73
  "description": "When selected, regardless of any other settings, all WordPress automatic updates on this site will be completely disabled!"
91
  "text": "Major and Minor Versions"
92
  }
93
  ],
94
+ "link_info": "https://shsec.io/k5",
95
  "link_blog": "",
96
  "name": "WordPress Core Updates",
97
  "summary": "Decide how the WordPress Core will automatically update, if at all",
src/config/feature-comments_filter.php CHANGED
@@ -124,7 +124,7 @@
124
  "section": "section_bot_comment_spam_protection_filter",
125
  "default": "N",
126
  "type": "checkbox",
127
- "link_info": "https://shsec.io/jn",
128
  "link_blog": "https://shsec.io/jo",
129
  "name": "AntiBot Detection Engine",
130
  "summary": "Use Experimental AntiBot Detection Engine",
124
  "section": "section_bot_comment_spam_protection_filter",
125
  "default": "N",
126
  "type": "checkbox",
127
+ "link_info": "https://shsec.io/k1",
128
  "link_blog": "https://shsec.io/jo",
129
  "name": "AntiBot Detection Engine",
130
  "summary": "Use Experimental AntiBot Detection Engine",
src/config/feature-integrations.php CHANGED
@@ -5,6 +5,7 @@
5
  "storage_key": "integrations",
6
  "name": "Integrations",
7
  "menu_title": "Integrations",
 
8
  "show_module_options": true,
9
  "show_module_menu_item": false,
10
  "auto_enabled": true,
@@ -32,6 +33,11 @@
32
  "title": "SPAM Detection",
33
  "title_short": "SPAM Detection"
34
  },
 
 
 
 
 
35
  {
36
  "slug": "section_non_ui",
37
  "hidden": true
@@ -49,18 +55,6 @@
49
  "summary": "Enable The Built-In MainWP Extension",
50
  "description": "This option will enable Shield's built-in MainWP extension for both server and client."
51
  },
52
- {
53
- "key": "enable_spam_antibot",
54
- "section": "section_spam",
55
- "premium": true,
56
- "default": "N",
57
- "type": "checkbox",
58
- "link_info": "",
59
- "link_blog": "",
60
- "name": "AntiBot SPAM Detection",
61
- "summary": "Enable The AntiBot SPAM Detection",
62
- "description": "Use Shield's built-in AntiBot Detection Engine to identify contact form SPAM."
63
- },
64
  {
65
  "key": "form_spam_providers",
66
  "section": "section_spam",
@@ -93,6 +87,10 @@
93
  "value_key": "gravityforms",
94
  "text": "Gravity Forms"
95
  },
 
 
 
 
96
  {
97
  "value_key": "kaliforms",
98
  "text": "Kali Forms"
@@ -110,11 +108,70 @@
110
  "text": "WPForms"
111
  }
112
  ],
113
- "link_info": "",
114
- "link_blog": "",
115
  "name": "SPAM Form Checking",
116
  "summary": "Select The Form Providers That Should Be Checked For SPAM",
117
  "description": "Select The Form Providers That Should Be Checked For SPAM."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  }
119
  ],
120
  "definitions": {
@@ -128,6 +185,16 @@
128
  "stat": true,
129
  "audit": true,
130
  "offense": false
 
 
 
 
 
 
 
 
 
 
131
  }
132
  }
133
  }
5
  "storage_key": "integrations",
6
  "name": "Integrations",
7
  "menu_title": "Integrations",
8
+ "sidebar_name": "3rd Party Integrations",
9
  "show_module_options": true,
10
  "show_module_menu_item": false,
11
  "auto_enabled": true,
33
  "title": "SPAM Detection",
34
  "title_short": "SPAM Detection"
35
  },
36
+ {
37
+ "slug": "section_user_forms",
38
+ "title": "User Forms Bot Detection",
39
+ "title_short": "User Forms Bot Detection"
40
+ },
41
  {
42
  "slug": "section_non_ui",
43
  "hidden": true
55
  "summary": "Enable The Built-In MainWP Extension",
56
  "description": "This option will enable Shield's built-in MainWP extension for both server and client."
57
  },
 
 
 
 
 
 
 
 
 
 
 
 
58
  {
59
  "key": "form_spam_providers",
60
  "section": "section_spam",
87
  "value_key": "gravityforms",
88
  "text": "Gravity Forms"
89
  },
90
+ {
91
+ "value_key": "groundhogg",
92
+ "text": "Groundhogg"
93
+ },
94
  {
95
  "value_key": "kaliforms",
96
  "text": "Kali Forms"
108
  "text": "WPForms"
109
  }
110
  ],
111
+ "link_info": "https://shsec.io/k2",
112
+ "link_blog": "https://shsec.io/k3",
113
  "name": "SPAM Form Checking",
114
  "summary": "Select The Form Providers That Should Be Checked For SPAM",
115
  "description": "Select The Form Providers That Should Be Checked For SPAM."
116
+ },
117
+ {
118
+ "key": "user_form_providers",
119
+ "section": "section_user_forms",
120
+ "premium": true,
121
+ "advanced": true,
122
+ "type": "multiple_select",
123
+ "default": [ "wordpress" ],
124
+ "value_options": [
125
+ {
126
+ "value_key": "buddypress",
127
+ "text": "BuddyPress"
128
+ },
129
+ {
130
+ "value_key": "easydigitaldownloads",
131
+ "text": "Easy Digital Downloads"
132
+ },
133
+ {
134
+ "value_key": "learnpress",
135
+ "text": "LearnPress"
136
+ },
137
+ {
138
+ "value_key": "lifterlms",
139
+ "text": "LifterLMS"
140
+ },
141
+ {
142
+ "value_key": "memberpress",
143
+ "text": "MemberPress"
144
+ },
145
+ {
146
+ "value_key": "paidmembersubscriptions",
147
+ "text": "Paid Member Subscriptions"
148
+ },
149
+ {
150
+ "value_key": "profilebuilder",
151
+ "text": "Profile Builder"
152
+ },
153
+ {
154
+ "value_key": "ultimatemember",
155
+ "text": "Ultimate Member"
156
+ },
157
+ {
158
+ "value_key": "woocommerce",
159
+ "text": "WooCommerce"
160
+ },
161
+ {
162
+ "value_key": "wordpress",
163
+ "text": "WordPress"
164
+ },
165
+ {
166
+ "value_key": "wpmembers",
167
+ "text": "WP Members"
168
+ }
169
+ ],
170
+ "link_info": "https://shsec.io/k4",
171
+ "link_blog": "https://shsec.io/k3",
172
+ "name": "User Form Checking",
173
+ "summary": "Select The User Form Providers That Should Be Checked For SPAM Registrations and Logins",
174
+ "description": "Select The User Form Providers That Should Be Checked For SPAM Registrations and Logins"
175
  }
176
  ],
177
  "definitions": {
185
  "stat": true,
186
  "audit": true,
187
  "offense": false
188
+ },
189
+ "user_form_bot_pass": {
190
+ "stat": true,
191
+ "audit": true,
192
+ "offense": false
193
+ },
194
+ "user_form_bot_fail": {
195
+ "stat": true,
196
+ "audit": true,
197
+ "offense": true
198
  }
199
  }
200
  }
src/config/feature-ips.php CHANGED
@@ -18,7 +18,7 @@
18
  },
19
  "menu_items": [
20
  {
21
- "title": "IP Lists",
22
  "slug": "ips-redirect"
23
  }
24
  ],
@@ -149,8 +149,8 @@
149
  "type": "integer",
150
  "min": 1,
151
  "max": 99,
152
- "link_info": "",
153
- "link_blog": "",
154
  "name": "AntiBot Threshold",
155
  "summary": "AntiBot Testing Threshold (Percentage)",
156
  "description": "When using Shield's AntiBot system, this is the threshold used for testing (between 1 and 99)."
@@ -580,6 +580,7 @@
580
  "cols_timestamps": {
581
  "notbot_at": "NotBot",
582
  "frontpage_at": "Front Page Loaded",
 
583
  "bt404_at": "BotTrack 404",
584
  "btfake_at": "BotTrack FakeWebCrawler",
585
  "btcheese_at": "BotTrack LinkCheese",
18
  },
19
  "menu_items": [
20
  {
21
+ "title": "IP Manager",
22
  "slug": "ips-redirect"
23
  }
24
  ],
149
  "type": "integer",
150
  "min": 1,
151
  "max": 99,
152
+ "link_info": "https://shsec.io/jy",
153
+ "link_blog": "https://shsec.io/jz",
154
  "name": "AntiBot Threshold",
155
  "summary": "AntiBot Testing Threshold (Percentage)",
156
  "description": "When using Shield's AntiBot system, this is the threshold used for testing (between 1 and 99)."
580
  "cols_timestamps": {
581
  "notbot_at": "NotBot",
582
  "frontpage_at": "Front Page Loaded",
583
+ "loginpage_at": "Login Page Loaded",
584
  "bt404_at": "BotTrack 404",
585
  "btfake_at": "BotTrack FakeWebCrawler",
586
  "btcheese_at": "BotTrack LinkCheese",
src/config/feature-login_protect.php CHANGED
@@ -265,6 +265,17 @@
265
  "summary": "Allow Any User To Turn-On Two-Factor Authentication By Email",
266
  "description": "Allow Any User To Turn-On Two-Factor Authentication By Email."
267
  },
 
 
 
 
 
 
 
 
 
 
 
268
  {
269
  "key": "bot_protection_locations",
270
  "section": "section_brute_force_login_protection",
@@ -299,7 +310,7 @@
299
  {
300
  "key": "login_limit_interval",
301
  "section": "section_brute_force_login_protection",
302
- "default": "10",
303
  "min": 0,
304
  "type": "integer",
305
  "link_info": "https://shsec.io/3q",
@@ -308,17 +319,6 @@
308
  "summary": "Limit login attempts to every X seconds",
309
  "description": "WordPress will process only ONE login attempt for every number of seconds specified. Zero (0) turns this off."
310
  },
311
- {
312
- "key": "enable_antibot_check",
313
- "section": "section_brute_force_login_protection",
314
- "default": "N",
315
- "type": "checkbox",
316
- "link_info": "https://shsec.io/jn",
317
- "link_blog": "https://shsec.io/jo",
318
- "name": "AntiBot",
319
- "summary": "Use Experimental AntiBot Detection Engine",
320
- "description": "Use Shield's AntiBot Detection Engine In-Place of GASP/CAPTCHA Bot checking."
321
- },
322
  {
323
  "key": "enable_login_gasp_check",
324
  "section": "section_brute_force_login_protection",
265
  "summary": "Allow Any User To Turn-On Two-Factor Authentication By Email",
266
  "description": "Allow Any User To Turn-On Two-Factor Authentication By Email."
267
  },
268
+ {
269
+ "key": "enable_antibot_check",
270
+ "section": "section_brute_force_login_protection",
271
+ "default": "N",
272
+ "type": "checkbox",
273
+ "link_info": "https://shsec.io/k0",
274
+ "link_blog": "https://shsec.io/jo",
275
+ "name": "AntiBot",
276
+ "summary": "Use Experimental AntiBot Detection Engine",
277
+ "description": "Use Shield's AntiBot Detection Engine In-Place of GASP/CAPTCHA Bot checking."
278
+ },
279
  {
280
  "key": "bot_protection_locations",
281
  "section": "section_brute_force_login_protection",
310
  {
311
  "key": "login_limit_interval",
312
  "section": "section_brute_force_login_protection",
313
+ "default": "5",
314
  "min": 0,
315
  "type": "integer",
316
  "link_info": "https://shsec.io/3q",
319
  "summary": "Limit login attempts to every X seconds",
320
  "description": "WordPress will process only ONE login attempt for every number of seconds specified. Zero (0) turns this off."
321
  },
 
 
 
 
 
 
 
 
 
 
 
322
  {
323
  "key": "enable_login_gasp_check",
324
  "section": "section_brute_force_login_protection",
src/config/feature-plugin.php CHANGED
@@ -3,7 +3,7 @@
3
  "slug": "plugin",
4
  "name": "General Settings",
5
  "sidebar_name": "General",
6
- "menu_title": "Settings",
7
  "show_module_menu_item": true,
8
  "show_module_options": true,
9
  "storage_key": "plugin",
@@ -267,7 +267,7 @@
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
  {
@@ -529,32 +529,32 @@
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",
535
- "importexport_cron_name": "autoimport",
536
- "href_privacy_policy": "https://shsec.io/wpshieldprivacypolicy",
537
- "db_classes": {
538
  "geoip": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\GeoIp\\Handler",
539
  "notes": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\AdminNotes\\Handler"
540
  },
541
- "db_table_notes": {
542
- "slug": "notes",
543
- "has_updated_at": true,
544
- "cols_custom": {
545
  "wp_username": "varchar(255) NOT NULL DEFAULT 'unknown'",
546
  "note": "TEXT"
547
  }
548
  },
549
- "db_table_geoip": {
550
- "autoexpire": 30,
551
- "slug": "geoip",
552
- "cols_custom": {
553
  "ip": "varbinary(16) DEFAULT NULL COMMENT 'IP Address'",
554
  "meta": "TEXT"
555
  }
556
  },
557
- "active_plugin_features": [
558
  {
559
  "slug": "insights",
560
  "load_priority": 1,
@@ -635,7 +635,7 @@
635
  "slug": "email"
636
  }
637
  ],
638
- "events": {
639
  "test_cron_run": {
640
  "audit": false,
641
  "recent": true
@@ -681,9 +681,14 @@
681
  "offense": false,
682
  "stat": false,
683
  "audit": false
 
 
 
 
 
684
  }
685
  },
686
- "wizards": {
687
  "welcome": {
688
  "title": "Getting Started Setup Wizard",
689
  "desc": "An introduction to this security plugin, helping you get setup and started quickly with the core features.",
@@ -711,8 +716,14 @@
711
  "comments_filter": {
712
  "title": "Comment SPAM"
713
  },
714
- "how_shield_works": {
715
- "title": "How Shield Works"
 
 
 
 
 
 
716
  },
717
  "optin": {
718
  "title": "Join Us!"
3
  "slug": "plugin",
4
  "name": "General Settings",
5
  "sidebar_name": "General",
6
+ "menu_title": "Configuration",
7
  "show_module_menu_item": true,
8
  "show_module_options": true,
9
  "storage_key": "plugin",
267
  "link_info": "https://shsec.io/5v",
268
  "link_blog": "https://shsec.io/wpsf20",
269
  "name": "Show Plugin Badge",
270
+ "summary": "Display Plugin Security 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
  {
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",
535
+ "importexport_cron_name": "autoimport",
536
+ "href_privacy_policy": "https://shsec.io/wpshieldprivacypolicy",
537
+ "db_classes": {
538
  "geoip": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\GeoIp\\Handler",
539
  "notes": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\AdminNotes\\Handler"
540
  },
541
+ "db_table_notes": {
542
+ "slug": "notes",
543
+ "has_updated_at": true,
544
+ "cols_custom": {
545
  "wp_username": "varchar(255) NOT NULL DEFAULT 'unknown'",
546
  "note": "TEXT"
547
  }
548
  },
549
+ "db_table_geoip": {
550
+ "autoexpire": 30,
551
+ "slug": "geoip",
552
+ "cols_custom": {
553
  "ip": "varbinary(16) DEFAULT NULL COMMENT 'IP Address'",
554
  "meta": "TEXT"
555
  }
556
  },
557
+ "active_plugin_features": [
558
  {
559
  "slug": "insights",
560
  "load_priority": 1,
635
  "slug": "email"
636
  }
637
  ],
638
+ "events": {
639
  "test_cron_run": {
640
  "audit": false,
641
  "recent": true
681
  "offense": false,
682
  "stat": false,
683
  "audit": false
684
+ },
685
+ "loginpage_load": {
686
+ "offense": false,
687
+ "stat": false,
688
+ "audit": false
689
  }
690
  },
691
+ "wizards": {
692
  "welcome": {
693
  "title": "Getting Started Setup Wizard",
694
  "desc": "An introduction to this security plugin, helping you get setup and started quickly with the core features.",
716
  "comments_filter": {
717
  "title": "Comment SPAM"
718
  },
719
+ "plugin_badge": {
720
+ "title": "Security Badge"
721
+ },
722
+ "plugin_telemetry": {
723
+ "title": "Plugin Telemetry"
724
+ },
725
+ "free_trial": {
726
+ "title": "Free Trial"
727
  },
728
  "optin": {
729
  "title": "Join Us!"
src/lib/src/Controller/Admin/MainAdminMenu.php CHANGED
@@ -27,7 +27,6 @@ class MainAdminMenu {
27
 
28
  private function createAdminMenu() {
29
  $con = $this->getCon();
30
-
31
  $menu = $con->cfg->menu;
32
  if ( $menu[ 'top_level' ] ) {
33
 
@@ -51,23 +50,8 @@ class MainAdminMenu {
51
  );
52
 
53
  if ( $menu[ 'has_submenu' ] ) {
54
-
55
- $menuItems = apply_filters( $con->prefix( 'submenu_items' ), [] );
56
- if ( !empty( $menuItems ) ) {
57
- foreach ( $menuItems as $menuTitle => $menuItem ) {
58
- list( $sMenuItemText, $sMenuItemId, $aMenuCallBack, $bShowItem ) = $menuItem;
59
- add_submenu_page(
60
- $bShowItem ? $parentMenuID : null,
61
- $menuTitle,
62
- $sMenuItemText,
63
- $con->getBasePermissions(),
64
- $sMenuItemId,
65
- $aMenuCallBack
66
- );
67
- }
68
- }
69
  }
70
-
71
  if ( $menu[ 'do_submenu_fix' ] ) {
72
  $this->fixSubmenu();
73
  }
27
 
28
  private function createAdminMenu() {
29
  $con = $this->getCon();
 
30
  $menu = $con->cfg->menu;
31
  if ( $menu[ 'top_level' ] ) {
32
 
50
  );
51
 
52
  if ( $menu[ 'has_submenu' ] ) {
53
+ do_action( $con->prefix( 'admin_submenu' ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  }
 
55
  if ( $menu[ 'do_submenu_fix' ] ) {
56
  $this->fixSubmenu();
57
  }
src/lib/src/Controller/Ajax/Response.php CHANGED
@@ -7,7 +7,7 @@ use FernleafSystems\Wordpress\Services\Services;
7
  class Response {
8
 
9
  public function issue( array $response, $wrap = false ) {
10
- $wrap = $wrap || (bool)Services::Request()->request( 'apto_wrap_response' );
11
 
12
  if ( !headers_sent() ) {
13
  header( 'Content-Type: application/json; charset='.get_option( 'blog_charset' ) );
7
  class Response {
8
 
9
  public function issue( array $response, $wrap = false ) {
10
+ $wrap = $wrap || Services::Request()->request( 'apto_wrap_response' );
11
 
12
  if ( !headers_sent() ) {
13
  header( 'Content-Type: application/json; charset='.get_option( 'blog_charset' ) );
src/lib/src/Controller/Assets/Enqueue.php CHANGED
@@ -23,18 +23,43 @@ class Enqueue {
23
  }
24
 
25
  protected function run() {
 
26
  add_action( 'login_enqueue_scripts', function () {
27
  $this->enqueue();
 
 
 
28
  }, 1000 );
 
29
  add_action( 'wp_enqueue_scripts', function () {
30
  $this->enqueue();
 
 
 
31
  }, 1000 );
 
32
  add_action( 'admin_enqueue_scripts', function ( $hook_suffix ) {
33
  $this->adminHookSuffix = $hook_suffix;
34
  $this->enqueue();
 
 
 
35
  }, 1000 );
36
  }
37
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  protected function enqueue() {
39
 
40
  // Register all plugin assets
@@ -104,20 +129,26 @@ class Enqueue {
104
  foreach ( $incl[ $type ] as $key => $spec ) {
105
  if ( !in_array( $key, $assetKeys[ $type ] ) ) {
106
 
 
 
107
  $handle = $this->normaliseHandle( $key );
108
  if ( $type === self::CSS ) {
109
  $reg = wp_register_style(
110
  $handle,
111
  $con->urls->forCss( $key ),
112
- $this->prefixKeys( $spec[ 'deps' ] ?? [] ),
113
  $con->getVersion()
114
  );
115
  }
116
  else {
 
 
 
 
117
  $reg = wp_register_script(
118
  $handle,
119
  $con->urls->forJs( $key ),
120
- $this->prefixKeys( $spec[ 'deps' ] ?? [] ),
121
  $con->getVersion(),
122
  $spec[ 'footer' ] ?? false
123
  );
23
  }
24
 
25
  protected function run() {
26
+
27
  add_action( 'login_enqueue_scripts', function () {
28
  $this->enqueue();
29
+ add_action( 'login_footer', function () {
30
+ $this->dequeue();
31
+ }, -1000 );
32
  }, 1000 );
33
+
34
  add_action( 'wp_enqueue_scripts', function () {
35
  $this->enqueue();
36
+ add_action( 'wp_footer', function () {
37
+ $this->dequeue();
38
+ }, -1000 );
39
  }, 1000 );
40
+
41
  add_action( 'admin_enqueue_scripts', function ( $hook_suffix ) {
42
  $this->adminHookSuffix = $hook_suffix;
43
  $this->enqueue();
44
+ add_action( 'admin_footer', function () {
45
+ $this->dequeue();
46
+ }, -1000 );
47
  }, 1000 );
48
  }
49
 
50
+ protected function dequeue() {
51
+ $customDequeues = apply_filters( 'shield/custom_dequeues', [
52
+ self::CSS => [],
53
+ self::JS => [],
54
+ ] );
55
+ foreach ( $customDequeues as $type => $assets ) {
56
+ foreach ( $assets as $asset ) {
57
+ $handle = $this->normaliseHandle( $asset );
58
+ $type == self::CSS ? wp_dequeue_style( $handle ) : wp_dequeue_script( $handle );
59
+ }
60
+ }
61
+ }
62
+
63
  protected function enqueue() {
64
 
65
  // Register all plugin assets
129
  foreach ( $incl[ $type ] as $key => $spec ) {
130
  if ( !in_array( $key, $assetKeys[ $type ] ) ) {
131
 
132
+ $deps = $spec[ 'deps' ] ?? [];
133
+
134
  $handle = $this->normaliseHandle( $key );
135
  if ( $type === self::CSS ) {
136
  $reg = wp_register_style(
137
  $handle,
138
  $con->urls->forCss( $key ),
139
+ $this->prefixKeys( $deps ),
140
  $con->getVersion()
141
  );
142
  }
143
  else {
144
+ if ( strpos( $key, 'jquery/' ) ) {
145
+ array_unshift( $deps, 'wp-jquery' );
146
+ }
147
+
148
  $reg = wp_register_script(
149
  $handle,
150
  $con->urls->forJs( $key ),
151
+ $this->prefixKeys( $deps ),
152
  $con->getVersion(),
153
  $spec[ 'footer' ] ?? false
154
  );
src/lib/src/Controller/Assets/Svgs.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Controller\Assets;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\PluginControllerConsumer;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
+
8
+ class Svgs {
9
+
10
+ use PluginControllerConsumer;
11
+
12
+ public function raw( string $image ) :string {
13
+ return Services::WpFs()->getFileContent( $this->getCon()->paths->forImage( $image ) );
14
+ }
15
+
16
+ public function url( string $image ) :string {
17
+ return $this->getCon()->urls->forImage( $image );
18
+ }
19
+ }
src/lib/src/Controller/Controller.php CHANGED
@@ -13,6 +13,7 @@ use FernleafSystems\Wordpress\Services\Utilities\Options\Transient;
13
  * @property Config\ConfigVO $cfg
14
  * @property Shield\Controller\Assets\Urls $urls
15
  * @property Shield\Controller\Assets\Paths $paths
 
16
  * @property bool $is_activating
17
  * @property bool $is_debug
18
  * @property bool $modules_loaded
@@ -163,6 +164,12 @@ class Controller extends DynPropertiesClass {
163
  }
164
  break;
165
 
 
 
 
 
 
 
166
  case 'paths':
167
  if ( !$val instanceof Shield\Controller\Assets\Paths ) {
168
  $val = ( new Shield\Controller\Assets\Paths() )->setCon( $this );
@@ -530,12 +537,15 @@ class Controller extends DynPropertiesClass {
530
  ( new Shield\Controller\Assets\Enqueue() )
531
  ->setCon( $this )
532
  ->execute();
533
- ( new Admin\MainAdminMenu() )
534
- ->setCon( $this )
535
- ->execute();
536
  ( new Utilities\CaptureMyUpgrade() )
537
  ->setCon( $this )
538
  ->execute();
 
 
 
 
 
 
539
  }
540
 
541
  protected function initCrons() {
@@ -1372,6 +1382,10 @@ class Controller extends DynPropertiesClass {
1372
  return $this->getModule( 'events' );
1373
  }
1374
 
 
 
 
 
1375
  public function getModule_HackGuard() :Shield\Modules\HackGuard\ModCon {
1376
  return $this->getModule( 'hack_protect' );
1377
  }
@@ -1591,7 +1605,7 @@ class Controller extends DynPropertiesClass {
1591
  */
1592
  private function buildPrivacyPolicyContent() {
1593
  try {
1594
- if ( $this->getModule_SecAdmin()->isEnabledWhitelabel() ) {
1595
  $name = $this->getHumanName();
1596
  $href = $this->getLabels()[ 'PluginURI' ];
1597
  }
13
  * @property Config\ConfigVO $cfg
14
  * @property Shield\Controller\Assets\Urls $urls
15
  * @property Shield\Controller\Assets\Paths $paths
16
+ * @property Shield\Controller\Assets\Svgs $svgs
17
  * @property bool $is_activating
18
  * @property bool $is_debug
19
  * @property bool $modules_loaded
164
  }
165
  break;
166
 
167
+ case 'svgs':
168
+ if ( !$val instanceof Shield\Controller\Assets\Svgs ) {
169
+ $val = ( new Shield\Controller\Assets\Svgs() )->setCon( $this );
170
+ }
171
+ break;
172
+
173
  case 'paths':
174
  if ( !$val instanceof Shield\Controller\Assets\Paths ) {
175
  $val = ( new Shield\Controller\Assets\Paths() )->setCon( $this );
537
  ( new Shield\Controller\Assets\Enqueue() )
538
  ->setCon( $this )
539
  ->execute();
 
 
 
540
  ( new Utilities\CaptureMyUpgrade() )
541
  ->setCon( $this )
542
  ->execute();
543
+
544
+ if ( is_admin() || is_network_admin() ) {
545
+ ( new Admin\MainAdminMenu() )
546
+ ->setCon( $this )
547
+ ->execute();
548
+ }
549
  }
550
 
551
  protected function initCrons() {
1382
  return $this->getModule( 'events' );
1383
  }
1384
 
1385
+ public function getModule_Firewall() :Shield\Modules\Firewall\ModCon {
1386
+ return $this->getModule( 'firewall' );
1387
+ }
1388
+
1389
  public function getModule_HackGuard() :Shield\Modules\HackGuard\ModCon {
1390
  return $this->getModule( 'hack_protect' );
1391
  }
1605
  */
1606
  private function buildPrivacyPolicyContent() {
1607
  try {
1608
+ if ( $this->getModule_SecAdmin()->getWhiteLabelController()->isEnabled() ) {
1609
  $name = $this->getHumanName();
1610
  $href = $this->getLabels()[ 'PluginURI' ];
1611
  }
src/lib/src/Databases/AuditTrail/Handler.php CHANGED
@@ -13,12 +13,4 @@ class Handler extends Base\Handler {
13
  $this->tableCleanExpired( $opts->getAutoCleanDays() );
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
  }
13
  $this->tableCleanExpired( $opts->getAutoCleanDays() );
14
  $this->tableTrimExcess( $opts->getMaxEntries() );
15
  }
 
 
 
 
 
 
 
 
16
  }
src/lib/src/Databases/Base/BaseQuery.php CHANGED
@@ -18,9 +18,11 @@ abstract class BaseQuery {
18
  protected $aWheres;
19
 
20
  /**
21
- * @var bool
22
  */
23
- protected $bExcludeDeleted;
 
 
24
 
25
  /**
26
  * @var int
@@ -54,83 +56,86 @@ abstract class BaseQuery {
54
 
55
  /**
56
  * @param string $column
57
- * @param string|array $mValue
58
  * @param string $operator
59
  * @return $this
60
  */
61
- public function addWhere( $column, $mValue, $operator = '=' ) {
62
  if ( !$this->isValidComparisonOperator( $operator ) ) {
63
  return $this; // Exception?
64
  }
65
 
66
- if ( is_array( $mValue ) ) {
67
- $mValue = array_map( 'esc_sql', $mValue );
68
- $mValue = "('".implode( "','", $mValue )."')";
69
  }
70
  else {
71
- $mValue = esc_sql( $mValue );
72
-
73
- if ( strcasecmp( $operator, 'LIKE' ) === 0 ) {
74
- $mValue = sprintf( '%%%s%%', $mValue );
75
  }
76
- if ( is_string( $mValue ) ) {
77
- $mValue = sprintf( "'%s'", $mValue );
78
  }
79
  }
80
 
81
- $where = $this->getWheres();
82
- $where[] = sprintf( '`%s` %s %s', esc_sql( $column ), $operator, $mValue );
83
- return $this->setWheres( $where );
 
 
 
 
 
84
  }
85
 
86
  /**
87
- * @param string $sColumn
88
  * @param mixed $mValue
89
  * @return $this
90
  */
91
- public function addWhereEquals( $sColumn, $mValue ) {
92
- return $this->addWhere( $sColumn, $mValue, '=' );
93
  }
94
 
95
  /**
96
- * @param string $sColumn
97
- * @param array $aValues
98
  * @return $this
99
  */
100
- public function addWhereIn( $sColumn, $aValues ) {
101
- if ( !empty( $aValues ) && is_array( $aValues ) ) {
102
- $this->addWhere( $sColumn, $aValues, 'IN' );
103
  }
104
  return $this;
105
  }
106
 
107
  /**
108
- * @param string $sColumn
109
- * @param string $sLike
110
- * @param string $sLeft
111
- * @param string $sRight
112
  * @return $this
113
  */
114
- public function addWhereLike( $sColumn, $sLike, $sLeft = '%', $sRight = '%' ) {
115
- return $this->addWhere( $sColumn, $sLeft.$sLike.$sRight, 'LIKE' );
116
  }
117
 
118
  /**
119
  * @param int $nNewerThanTimeStamp
120
- * @param string $sColumn
121
  * @return $this
122
  */
123
- public function addWhereNewerThan( $nNewerThanTimeStamp, $sColumn = 'created_at' ) {
124
- return $this->addWhere( $sColumn, $nNewerThanTimeStamp, '>' );
125
  }
126
 
127
  /**
128
  * @param int $nOlderThanTimeStamp
129
- * @param string $sColumn
130
  * @return $this
131
  */
132
- public function addWhereOlderThan( $nOlderThanTimeStamp, $sColumn = 'created_at' ) {
133
- return $this->addWhere( $sColumn, $nOlderThanTimeStamp, '<' );
134
  }
135
 
136
  /**
@@ -175,7 +180,7 @@ abstract class BaseQuery {
175
  * @return $this
176
  */
177
  public function clearWheres() {
178
- return $this->setWheres( [] );
179
  }
180
 
181
  /**
@@ -190,12 +195,23 @@ abstract class BaseQuery {
190
  */
191
  public function buildWhere() {
192
 
193
- $aParts = $this->getWheres();
194
- if ( $this->isExcludeDeleted() ) {
195
- $aParts[] = '`deleted_at`=0';
 
 
 
 
 
 
 
 
 
 
 
196
  }
197
 
198
- return implode( ' AND ', $aParts );
199
  }
200
 
201
  /**
@@ -312,10 +328,11 @@ abstract class BaseQuery {
312
  }
313
 
314
  public function getWheres() :array {
315
- if ( !is_array( $this->aWheres ) ) {
316
- $this->aWheres = [];
317
- }
318
- return $this->aWheres;
 
319
  }
320
 
321
  /**
@@ -358,18 +375,16 @@ abstract class BaseQuery {
358
  return $this->getLimit() > 0;
359
  }
360
 
361
- /**
362
- * @return bool
363
- */
364
- public function hasWheres() {
365
  return count( $this->getWheres() ) > 0;
366
  }
367
 
368
- /**
369
- * @return bool
370
- */
371
- public function isExcludeDeleted() {
372
- return isset( $this->bExcludeDeleted ) ? (bool)$this->bExcludeDeleted : true;
 
373
  }
374
 
375
  /**
@@ -377,17 +392,17 @@ abstract class BaseQuery {
377
  */
378
  public function reset() {
379
  return $this->setLimit( 0 )
380
- ->setWheres( [] )
381
  ->setPage( 1 )
382
  ->setOrderBy( null );
383
  }
384
 
385
  /**
386
- * @param mixed $bExcludeDeleted
387
  * @return $this
388
  */
389
- public function setIsExcludeDeleted( $bExcludeDeleted ) {
390
- $this->bExcludeDeleted = $bExcludeDeleted;
391
  return $this;
392
  }
393
 
@@ -443,11 +458,24 @@ abstract class BaseQuery {
443
  }
444
 
445
  /**
446
- * @param array $where
 
 
 
 
 
 
 
 
 
 
 
 
 
447
  * @return $this
448
  */
449
- public function setWheres( $where ) {
450
- $this->aWheres = $where;
451
  return $this;
452
  }
453
 
18
  protected $aWheres;
19
 
20
  /**
21
+ * @var array
22
  */
23
+ protected $rawWheres;
24
+
25
+ protected $includeSoftDeleted;
26
 
27
  /**
28
  * @var int
56
 
57
  /**
58
  * @param string $column
59
+ * @param string|array $value
60
  * @param string $operator
61
  * @return $this
62
  */
63
+ public function addWhere( $column, $value, $operator = '=' ) {
64
  if ( !$this->isValidComparisonOperator( $operator ) ) {
65
  return $this; // Exception?
66
  }
67
 
68
+ if ( is_array( $value ) ) {
69
+ $value = array_map( 'esc_sql', $value );
70
+ $value = "('".implode( "','", $value )."')";
71
  }
72
  else {
73
+ if ( strtoupper( $operator ) === 'LIKE' ) {
74
+ $value = sprintf( '%%%s%%', $value );
 
 
75
  }
76
+ if ( !is_int( $value ) ) {
77
+ $value = sprintf( '"%s"', esc_sql( $value ) );
78
  }
79
  }
80
 
81
+ $rawWheres = $this->getRawWheres();
82
+ $rawWheres[] = [
83
+ esc_sql( $column ),
84
+ $operator,
85
+ $value
86
+ ];
87
+
88
+ return $this->setRawWheres( $rawWheres );
89
  }
90
 
91
  /**
92
+ * @param string $column
93
  * @param mixed $mValue
94
  * @return $this
95
  */
96
+ public function addWhereEquals( string $column, $mValue ) {
97
+ return $this->addWhere( $column, $mValue, '=' );
98
  }
99
 
100
  /**
101
+ * @param string $column
102
+ * @param array $values
103
  * @return $this
104
  */
105
+ public function addWhereIn( string $column, $values ) {
106
+ if ( !empty( $values ) && is_array( $values ) ) {
107
+ $this->addWhere( $column, $values, 'IN' );
108
  }
109
  return $this;
110
  }
111
 
112
  /**
113
+ * @param string $column
114
+ * @param string $like
115
+ * @param string $left
116
+ * @param string $right
117
  * @return $this
118
  */
119
+ public function addWhereLike( string $column, $like, $left = '%', $right = '%' ) {
120
+ return $this->addWhere( $column, $left.$like.$right, 'LIKE' );
121
  }
122
 
123
  /**
124
  * @param int $nNewerThanTimeStamp
125
+ * @param string $column
126
  * @return $this
127
  */
128
+ public function addWhereNewerThan( $nNewerThanTimeStamp, $column = 'created_at' ) {
129
+ return $this->addWhere( $column, $nNewerThanTimeStamp, '>' );
130
  }
131
 
132
  /**
133
  * @param int $nOlderThanTimeStamp
134
+ * @param string $column
135
  * @return $this
136
  */
137
+ public function addWhereOlderThan( $nOlderThanTimeStamp, $column = 'created_at' ) {
138
+ return $this->addWhere( $column, $nOlderThanTimeStamp, '<' );
139
  }
140
 
141
  /**
180
  * @return $this
181
  */
182
  public function clearWheres() {
183
+ return $this->setRawWheres( [] );
184
  }
185
 
186
  /**
195
  */
196
  public function buildWhere() {
197
 
198
+ if ( method_exists( $this, 'getRawWheres' ) ) {
199
+ $wheres = $this->getRawWheres();
200
+ if ( !$this->isIncludeSoftDeletedRows() ) {
201
+ $wheres[] = [ 'deleted_at', '=', 0 ];
202
+ }
203
+ $wheres = array_map( function ( array $where ) {
204
+ return $this->rawWhereToString( $where );
205
+ }, $wheres );
206
+ }
207
+ else { // TODO: @deprecated 11.2
208
+ $wheres = $this->getWheres();
209
+ if ( !$this->isIncludeSoftDeletedRows() ) {
210
+ $wheres[] = '`deleted_at`=0';
211
+ }
212
  }
213
 
214
+ return implode( ' AND ', $wheres );
215
  }
216
 
217
  /**
328
  }
329
 
330
  public function getWheres() :array {
331
+ return is_array( $this->aWheres ) ? $this->aWheres : [];
332
+ }
333
+
334
+ public function getRawWheres() :array {
335
+ return is_array( $this->rawWheres ) ? $this->rawWheres : [];
336
  }
337
 
338
  /**
375
  return $this->getLimit() > 0;
376
  }
377
 
378
+ public function hasWheres() :bool {
 
 
 
379
  return count( $this->getWheres() ) > 0;
380
  }
381
 
382
+ public function isIncludeSoftDeletedRows() :bool {
383
+ return $this->includeSoftDeleted ?? false;
384
+ }
385
+
386
+ protected function rawWhereToString( array $rawWhere ) :string {
387
+ return vsprintf( '`%s` %s %s', $rawWhere );
388
  }
389
 
390
  /**
392
  */
393
  public function reset() {
394
  return $this->setLimit( 0 )
395
+ ->setRawWheres( [] )
396
  ->setPage( 1 )
397
  ->setOrderBy( null );
398
  }
399
 
400
  /**
401
+ * @param bool $includeSoftDeleted
402
  * @return $this
403
  */
404
+ public function setIncludeSoftDeleted( bool $includeSoftDeleted ) {
405
+ $this->includeSoftDeleted = $includeSoftDeleted;
406
  return $this;
407
  }
408
 
458
  }
459
 
460
  /**
461
+ * @param array[] $wheres
462
+ * @return $this
463
+ */
464
+ public function setRawWheres( array $wheres ) {
465
+ $this->rawWheres = $wheres;
466
+ return $this->setWheres(
467
+ array_map( function ( array $where ) {
468
+ return $this->rawWhereToString( $where );
469
+ }, $this->rawWheres )
470
+ );
471
+ }
472
+
473
+ /**
474
+ * @param array $wheres
475
  * @return $this
476
  */
477
+ public function setWheres( array $wheres ) {
478
+ $this->aWheres = $wheres;
479
  return $this;
480
  }
481
 
src/lib/src/Databases/Base/Delete.php CHANGED
@@ -2,8 +2,35 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
4
 
 
 
5
  class Delete extends BaseQuery {
6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  /**
8
  * @return bool
9
  */
@@ -12,13 +39,12 @@ class Delete extends BaseQuery {
12
  }
13
 
14
  /**
15
- * @param int $nId
16
  * @return bool
17
  */
18
- public function deleteById( $nId ) {
19
  return $this->reset()
20
- ->addWhereEquals( 'id', (int)$nId )
21
- ->setLimit( 1 )//perhaps an unnecessary precaution
22
  ->query();
23
  }
24
 
@@ -48,7 +74,7 @@ class Delete extends BaseQuery {
48
  // The same WHEREs should apply
49
  $nTotal = $this->getDbH()
50
  ->getQuerySelector()
51
- ->setWheres( $this->getWheres() )
52
  ->count();
53
  $nToDelete = $nTotal - $maxEntries;
54
 
@@ -72,4 +98,14 @@ class Delete extends BaseQuery {
72
  protected function buildOffsetPhrase() {
73
  return '';
74
  }
 
 
 
 
 
 
 
 
 
 
75
  }
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
4
 
5
+ use FernleafSystems\Wordpress\Services\Services;
6
+
7
  class Delete extends BaseQuery {
8
 
9
+ private $isSoftDelete = false;
10
+
11
+ /**
12
+ * @return bool
13
+ */
14
+ public function query() {
15
+ if ( $this->isSoftDelete && $this->getDbH()->getTableSchema()->hasColumn( 'deleted_at' ) ) {
16
+
17
+ $updateWheres = [];
18
+ foreach ( $this->getRawWheres() as $where ) {
19
+ $updateWheres[ $where[ 0 ] ] = $where[ 2 ];
20
+ }
21
+
22
+ $success = $this->getDbH()
23
+ ->getQueryUpdater()
24
+ ->setUpdateWheres( $updateWheres )
25
+ ->setUpdateData( [ 'deleted_at' => Services::Request()->ts(), ] )
26
+ ->query();
27
+ }
28
+ else {
29
+ $success = parent::query();
30
+ }
31
+ return $success;
32
+ }
33
+
34
  /**
35
  * @return bool
36
  */
39
  }
40
 
41
  /**
42
+ * @param int $id
43
  * @return bool
44
  */
45
+ public function deleteById( $id ) {
46
  return $this->reset()
47
+ ->addWhereEquals( 'id', (int)$id )
 
48
  ->query();
49
  }
50
 
74
  // The same WHEREs should apply
75
  $nTotal = $this->getDbH()
76
  ->getQuerySelector()
77
+ ->setRawWheres( $this->getRawWheres() )
78
  ->count();
79
  $nToDelete = $nTotal - $maxEntries;
80
 
98
  protected function buildOffsetPhrase() {
99
  return '';
100
  }
101
+
102
+ public function setIsHardDelete() {
103
+ $this->isSoftDelete = false;
104
+ return $this;
105
+ }
106
+
107
+ public function setIsSoftDelete() {
108
+ $this->isSoftDelete = true;
109
+ return $this;
110
+ }
111
  }
src/lib/src/Databases/Base/EntryVO.php CHANGED
@@ -45,7 +45,7 @@ class EntryVO extends DynPropertiesClass {
45
  break;
46
  }
47
 
48
- if ( preg_match( '#^.*_at$#i', $key ) ) {
49
  $value = (int)$value;
50
  }
51
 
45
  break;
46
  }
47
 
48
+ if ( $key === 'id' || preg_match( '#^.*_at$#i', $key ) ) {
49
  $value = (int)$value;
50
  }
51
 
src/lib/src/Databases/Base/Handler.php CHANGED
@@ -2,20 +2,12 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
4
 
5
- use FernleafSystems\Utilities\Logic\ExecOnce;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Common\AlignTableWithSchema;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Common\TableSchema;
8
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
9
  use FernleafSystems\Wordpress\Services\Services;
10
 
11
- /**
12
- * Class Handler
13
- * @package FernleafSystems\Wordpress\Plugin\Shield\Databases\Base
14
- */
15
- abstract class Handler {
16
-
17
- use ModConsumer;
18
- use ExecOnce;
19
 
20
  /**
21
  * @var string
@@ -234,14 +226,6 @@ abstract class Handler {
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
  }
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
4
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Common\AlignTableWithSchema;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Common\TableSchema;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
8
  use FernleafSystems\Wordpress\Services\Services;
9
 
10
+ abstract class Handler extends ExecOnceModConsumer {
 
 
 
 
 
 
 
11
 
12
  /**
13
  * @var string
226
  return $this->bIsReady;
227
  }
228
 
 
 
 
 
 
 
 
 
229
  public function getTableSchema() :TableSchema {
230
  return $this->schema;
231
  }
src/lib/src/Databases/Base/Update.php CHANGED
@@ -95,16 +95,13 @@ class Update extends Insert {
95
  if ( !empty( $updateData ) ) {
96
  $success = $this->setUpdateId( $id )
97
  ->setUpdateData( $updateData )
98
- ->query() === 1;
99
  }
100
  return $success;
101
  }
102
 
103
- /**
104
- * @return int|false
105
- */
106
  public function query() {
107
- return Services::WpDb()
108
  ->updateRowsFromTableWhere(
109
  $this->getDbH()->getTable(),
110
  $this->getUpdateData(),
95
  if ( !empty( $updateData ) ) {
96
  $success = $this->setUpdateId( $id )
97
  ->setUpdateData( $updateData )
98
+ ->query();
99
  }
100
  return $success;
101
  }
102
 
 
 
 
103
  public function query() {
104
+ return (bool)Services::WpDb()
105
  ->updateRowsFromTableWhere(
106
  $this->getDbH()->getTable(),
107
  $this->getUpdateData(),
src/lib/src/Databases/BotSignals/EntryVO.php CHANGED
@@ -7,6 +7,7 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\BotSignals;
7
  * @property string $ip
8
  * @property int $notbot_at
9
  * @property int $frontpage_at
 
10
  * @property int $bt404_at
11
  * @property int $btcheese_at
12
  * @property int $btfake_at
7
  * @property string $ip
8
  * @property int $notbot_at
9
  * @property int $frontpage_at
10
+ * @property int $loginpage_at
11
  * @property int $bt404_at
12
  * @property int $btcheese_at
13
  * @property int $btfake_at
src/lib/src/Databases/Events/Handler.php CHANGED
@@ -36,12 +36,4 @@ class Handler extends Base\Handler {
36
  $QI = $this->getQueryInserter();
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
- }
47
  }
36
  $QI = $this->getQueryInserter();
37
  return $QI->insert( $oEvt );
38
  }
 
 
 
 
 
 
 
 
39
  }
src/lib/src/Databases/Events/Select.php CHANGED
@@ -40,16 +40,15 @@ class Select extends Base\Select {
40
  * @return int[]
41
  */
42
  public function sumAllEvents() {
43
- $aSums = [];
44
 
45
- $oNewMe = clone $this;
46
- $aAllEvents = $oNewMe->reset()->getAllEvents();
47
 
48
- natsort( $aAllEvents );
49
- foreach ( $aAllEvents as $sEvent ) {
50
- $aSums[ $sEvent ] = $this->clearWheres()->sumEvent( $sEvent );
51
  }
52
- return $aSums;
53
  }
54
 
55
  /**
40
  * @return int[]
41
  */
42
  public function sumAllEvents() {
43
+ $sums = [];
44
 
45
+ $allEvents = ( clone $this )->reset()->getAllEvents();
 
46
 
47
+ natsort( $allEvents );
48
+ foreach ( $allEvents as $event ) {
49
+ $sums[ $event ] = $this->clearWheres()->sumEvent( $event );
50
  }
51
+ return $sums;
52
  }
53
 
54
  /**
src/lib/src/Databases/FileLocker/Handler.php CHANGED
@@ -6,11 +6,4 @@ use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
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
- }
16
  }
6
 
7
  class Handler extends Base\Handler {
8
 
 
 
 
 
 
 
 
9
  }
src/lib/src/Databases/IPs/Handler.php CHANGED
@@ -29,12 +29,4 @@ class Handler extends Base\Handler {
29
  ->addWhere( 'list', ModCon::LIST_MANUAL_WHITE, '!=' )
30
  ->query();
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
  }
29
  ->addWhere( 'list', ModCon::LIST_MANUAL_WHITE, '!=' )
30
  ->query();
31
  }
 
 
 
 
 
 
 
 
32
  }
src/lib/src/Databases/ScanQueue/Common.php CHANGED
@@ -48,12 +48,12 @@ trait Common {
48
  }
49
 
50
  /**
51
- * @param string $sScan
52
  * @return bool
53
  */
54
- public function forScan( $sScan ) {
55
  $this->reset();
56
- return $this->filterByScan( $sScan )
57
  ->query();
58
  }
59
  }
48
  }
49
 
50
  /**
51
+ * @param string $scan
52
  * @return bool
53
  */
54
+ public function forScan( $scan ) {
55
  $this->reset();
56
+ return $this->filterByScan( $scan )
57
  ->query();
58
  }
59
  }
src/lib/src/Databases/Scanner/Update.php CHANGED
@@ -8,40 +8,36 @@ use FernleafSystems\Wordpress\Services\Services;
8
  class Update extends Base\Update {
9
 
10
  /**
11
- * @param string $sScan
12
  * @return bool
13
  */
14
- public function clearIgnoredAtForScan( $sScan ) {
15
- return $this->setUpdateWheres( [ 'scan' => $sScan ] )
16
  ->setUpdateData( [ 'ignored_at' => 0 ] )
17
  ->query() !== false;
18
  }
19
 
20
  /**
21
- * @param string $sScan
22
  * @return bool
23
  */
24
- public function clearNotifiedAtForScan( $sScan ) {
25
- return $this->setUpdateWheres( [ 'scan' => $sScan ] )
26
  ->setUpdateData( [ 'notified_at' => 0 ] )
27
  ->query() !== false;
28
  }
29
 
30
  /**
31
- * @param string $sScan
32
  * @return bool
33
  */
34
- public function setAllNotifiedForScan( $sScan ) {
35
  return $this
36
- ->setUpdateWheres(
37
- [
38
- 'scan' => $sScan,
39
- 'ignored_at' => 0,
40
- ]
41
- )
42
- ->setUpdateData(
43
- [ 'notified_at' => Services::Request()->ts() ]
44
- )
45
  ->query() !== false;
46
  }
47
 
8
  class Update extends Base\Update {
9
 
10
  /**
11
+ * @param string $scan
12
  * @return bool
13
  */
14
+ public function clearIgnoredAtForScan( $scan ) {
15
+ return $this->setUpdateWheres( [ 'scan' => $scan ] )
16
  ->setUpdateData( [ 'ignored_at' => 0 ] )
17
  ->query() !== false;
18
  }
19
 
20
  /**
21
+ * @param string $scan
22
  * @return bool
23
  */
24
+ public function clearNotifiedAtForScan( $scan ) {
25
+ return $this->setUpdateWheres( [ 'scan' => $scan ] )
26
  ->setUpdateData( [ 'notified_at' => 0 ] )
27
  ->query() !== false;
28
  }
29
 
30
  /**
31
+ * @param string $scan
32
  * @return bool
33
  */
34
+ public function setAllNotifiedForScan( $scan ) {
35
  return $this
36
+ ->setUpdateWheres( [
37
+ 'scan' => $scan,
38
+ 'ignored_at' => 0,
39
+ ] )
40
+ ->setUpdateData( [ 'notified_at' => Services::Request()->ts() ] )
 
 
 
 
41
  ->query() !== false;
42
  }
43
 
src/lib/src/Databases/Session/Handler.php CHANGED
@@ -3,18 +3,16 @@
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\Session;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
 
6
 
7
  class Handler extends Base\Handler {
8
 
9
  public function autoCleanDb() {
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
  }
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\Session;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
 
8
  class Handler extends Base\Handler {
9
 
10
  public function autoCleanDb() {
11
  $this->tableCleanExpired( 30 );
12
+ // Remove soft-deleted sessions after 3 days
13
+ $this->getQueryDeleter()
14
+ ->addWhereNewerThan( 0, 'deleted_at' )
15
+ ->addWhereOlderThan( Services::Request()->carbon()->subDays( 5 )->timestamp, 'deleted_at' )
16
+ ->query();
 
 
 
17
  }
18
  }
src/lib/src/Databases/Traffic/Handler.php CHANGED
@@ -13,12 +13,4 @@ class Handler extends Base\Handler {
13
  $this->tableCleanExpired( $opts->getAutoCleanDays() );
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
  }
13
  $this->tableCleanExpired( $opts->getAutoCleanDays() );
14
  $this->tableTrimExcess( $opts->getMaxEntries() );
15
  }
 
 
 
 
 
 
 
 
16
  }
src/lib/src/License/EddLicenseVO.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\License;
4
 
1
+ <?php declare( strict_types=1 );
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\License;
4
 
src/lib/src/Modules/AuditTrail/Insights/OverviewCards.php CHANGED
@@ -7,24 +7,15 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail;
7
 
8
  class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
9
 
10
- public function build() :array {
11
  /** @var AuditTrail\ModCon $mod */
12
  $mod = $this->getMod();
13
  /** @var AuditTrail\Options $opts */
14
  $opts = $this->getOptions();
15
 
16
- $cardSection = [
17
- 'title' => __( 'Activity Audit Log', 'wp-simple-firewall' ),
18
- 'subtitle' => $mod->getStrings()->getModTagLine(),
19
- 'href_options' => $mod->getUrl_AdminPage(),
20
- ];
21
-
22
  $cards = [];
23
 
24
- if ( !$mod->isModOptEnabled() ) {
25
- $data[ 'key_opts' ][ 'mod' ] = $this->getModDisabledCard();
26
- }
27
- else {
28
  $cards[ 'audit' ] = [
29
  'name' => __( 'Audit Areas', 'wp-simple-firewall' ),
30
  'state' => 1,
@@ -40,7 +31,10 @@ class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
40
  ];
41
  }
42
 
43
- $cardSection[ 'cards' ] = $cards;
44
- return [ 'audit_trail' => $cardSection ];
 
 
 
45
  }
46
  }
7
 
8
  class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
9
 
10
+ protected function buildModCards() :array {
11
  /** @var AuditTrail\ModCon $mod */
12
  $mod = $this->getMod();
13
  /** @var AuditTrail\Options $opts */
14
  $opts = $this->getOptions();
15
 
 
 
 
 
 
 
16
  $cards = [];
17
 
18
+ if ( $mod->isModOptEnabled() ) {
 
 
 
19
  $cards[ 'audit' ] = [
20
  'name' => __( 'Audit Areas', 'wp-simple-firewall' ),
21
  'state' => 1,
31
  ];
32
  }
33
 
34
+ return $cards;
35
+ }
36
+
37
+ protected function getSectionTitle() :string {
38
+ return __( 'Activity Audit Log', 'wp-simple-firewall' );
39
  }
40
  }
src/lib/src/Modules/AuditTrail/Lib/AuditWriter.php CHANGED
@@ -23,7 +23,7 @@ class AuditWriter extends EventsListener {
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
23
  */
24
  protected function captureEvent( string $evt, $meta = [], $def = [] ) {
25
  $con = $this->getCon();
26
+ if ( empty( $def ) ) { // TODO: @deprecated 11.2 - 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
src/lib/src/Modules/Autoupdates/Insights/OverviewCards.php CHANGED
@@ -8,51 +8,42 @@ use FernleafSystems\Wordpress\Services\Services;
8
 
9
  class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
10
 
11
- public function build() :array {
12
  /** @var Autoupdates\ModCon $mod */
13
  $mod = $this->getMod();
14
  /** @var Autoupdates\Options $opts */
15
  $opts = $this->getOptions();
16
  $WP = Services::WpGeneral();
17
 
18
- $cardSection = [
19
- 'title' => __( 'Automatic Updates', 'wp-simple-firewall' ),
20
- 'subtitle' => __( 'Controlling WordPress Automatic Updates', 'wp-simple-firewall' ),
21
- 'href_options' => $mod->getUrl_AdminPage()
22
- ];
23
-
24
  $cards = [];
25
 
26
- if ( !$mod->isModOptEnabled() ) {
27
- $cards[ 'mod' ] = $this->getModDisabledCard();
28
- }
29
- else {
30
- $bHasUpdate = $WP->hasCoreUpdate();
31
  $cards[ 'core_update' ] = [
32
  'name' => __( 'Core Update', 'wp-simple-firewall' ),
33
- 'state' => $bHasUpdate ? -1 : 1,
34
- 'summary' => $bHasUpdate ?
35
  __( 'WordPress Core is up-to-date', 'wp-simple-firewall' )
36
  : __( "No WordPress Core upgrades waiting to be applied", 'wp-simple-firewall' ),
37
  'href' => $WP->getAdminUrl_Updates( true ),
38
  'help' => __( 'Core upgrades should be applied as early as possible.', 'wp-simple-firewall' )
39
  ];
40
 
41
- $bCanCore = Services::WpGeneral()->canCoreUpdateAutomatically();
42
  $cards[ 'core_minor' ] = [
43
  'name' => __( 'Auto Core Updates', 'wp-simple-firewall' ),
44
- 'state' => $bCanCore ? 1 : -1,
45
- 'summary' => $bCanCore ?
46
  __( 'Minor WP Core updates will be installed automatically', 'wp-simple-firewall' )
47
  : __( 'Minor WP Core updates will not be installed automatically', 'wp-simple-firewall' ),
48
  'href' => $mod->getUrl_DirectLinkToOption( 'autoupdate_core' ),
49
  ];
50
 
51
- $bHasDelay = $mod->isModOptEnabled() && $opts->getDelayUpdatesPeriod();
52
  $cards[ 'delay' ] = [
53
  'name' => __( 'Update Delay', 'wp-simple-firewall' ),
54
- 'state' => $bHasDelay ? 1 : -1,
55
- 'summary' => $bHasDelay ?
56
  __( 'Automatic updates are applied after a short delay', 'wp-simple-firewall' )
57
  : __( 'Automatic updates are applied immediately', 'wp-simple-firewall' ),
58
  'href' => $mod->getUrl_DirectLinkToOption( 'update_delay' ),
@@ -74,7 +65,7 @@ class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
74
  //really disabled?
75
  if ( $mod->isModOptEnabled()
76
  && $opts->isDisableAllAutoUpdates() && !$WP->getWpAutomaticUpdater()->is_disabled() ) {
77
- $notices[ 'messages' ][ 'disabled_auto' ] = [
78
  'name' => 'Auto Updates Not Really Disabled',
79
  'summary' => __( 'Automatic Updates Are Not Disabled As Expected.', 'wp-simple-firewall' ),
80
  'href' => $mod->getUrl_DirectLinkToOption( 'enable_autoupdate_disable_all' ),
@@ -85,21 +76,26 @@ class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
85
  ];
86
  }
87
 
88
- $cards = array_merge(
89
  $cards,
90
  $this->getCardsForPlugins(),
91
  $this->getCardsForThemes()
92
  );
 
 
 
 
 
93
 
94
- $cardSection[ 'cards' ] = $cards;
95
- return [ 'auto_updates' => $cardSection ];
96
  }
97
 
98
  private function getCardsForPlugins() :array {
99
  $cards = [];
100
 
101
- $oWpPlugins = Services::WpPlugins();
102
- $nCount = count( $oWpPlugins->getPlugins() ) - count( $oWpPlugins->getActivePlugins() );
103
  $cards[ 'plugins_inactive' ] = [
104
  'name' => __( 'Inactive Plugins', 'wp-simple-firewall' ),
105
  'state' => $nCount > 0 ? -1 : 1,
@@ -110,7 +106,7 @@ class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
110
  'help' => __( 'Unused plugins should be removed.', 'wp-simple-firewall' )
111
  ];
112
 
113
- $nCount = count( $oWpPlugins->getUpdates() );
114
  $cards[ 'plugin_updates' ] = [
115
  'name' => __( 'Plugin Updates', 'wp-simple-firewall' ),
116
  'state' => $nCount > 0 ? -1 : 1,
8
 
9
  class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
10
 
11
+ protected function buildModCards() :array {
12
  /** @var Autoupdates\ModCon $mod */
13
  $mod = $this->getMod();
14
  /** @var Autoupdates\Options $opts */
15
  $opts = $this->getOptions();
16
  $WP = Services::WpGeneral();
17
 
 
 
 
 
 
 
18
  $cards = [];
19
 
20
+ if ( $mod->isModOptEnabled() ) {
21
+ $hasUpdate = $WP->hasCoreUpdate();
 
 
 
22
  $cards[ 'core_update' ] = [
23
  'name' => __( 'Core Update', 'wp-simple-firewall' ),
24
+ 'state' => $hasUpdate ? -1 : 1,
25
+ 'summary' => $hasUpdate ?
26
  __( 'WordPress Core is up-to-date', 'wp-simple-firewall' )
27
  : __( "No WordPress Core upgrades waiting to be applied", 'wp-simple-firewall' ),
28
  'href' => $WP->getAdminUrl_Updates( true ),
29
  'help' => __( 'Core upgrades should be applied as early as possible.', 'wp-simple-firewall' )
30
  ];
31
 
32
+ $canCore = Services::WpGeneral()->canCoreUpdateAutomatically();
33
  $cards[ 'core_minor' ] = [
34
  'name' => __( 'Auto Core Updates', 'wp-simple-firewall' ),
35
+ 'state' => $canCore ? 1 : -1,
36
+ 'summary' => $canCore ?
37
  __( 'Minor WP Core updates will be installed automatically', 'wp-simple-firewall' )
38
  : __( 'Minor WP Core updates will not be installed automatically', 'wp-simple-firewall' ),
39
  'href' => $mod->getUrl_DirectLinkToOption( 'autoupdate_core' ),
40
  ];
41
 
42
+ $hasDelay = $mod->isModOptEnabled() && $opts->getDelayUpdatesPeriod();
43
  $cards[ 'delay' ] = [
44
  'name' => __( 'Update Delay', 'wp-simple-firewall' ),
45
+ 'state' => $hasDelay ? 1 : -1,
46
+ 'summary' => $hasDelay ?
47
  __( 'Automatic updates are applied after a short delay', 'wp-simple-firewall' )
48
  : __( 'Automatic updates are applied immediately', 'wp-simple-firewall' ),
49
  'href' => $mod->getUrl_DirectLinkToOption( 'update_delay' ),
65
  //really disabled?
66
  if ( $mod->isModOptEnabled()
67
  && $opts->isDisableAllAutoUpdates() && !$WP->getWpAutomaticUpdater()->is_disabled() ) {
68
+ $cards[ 'messages' ][ 'disabled_auto' ] = [
69
  'name' => 'Auto Updates Not Really Disabled',
70
  'summary' => __( 'Automatic Updates Are Not Disabled As Expected.', 'wp-simple-firewall' ),
71
  'href' => $mod->getUrl_DirectLinkToOption( 'enable_autoupdate_disable_all' ),
76
  ];
77
  }
78
 
79
+ return array_merge(
80
  $cards,
81
  $this->getCardsForPlugins(),
82
  $this->getCardsForThemes()
83
  );
84
+ }
85
+
86
+ protected function getSectionTitle() :string {
87
+ return __( 'Automatic Updates', 'wp-simple-firewall' );
88
+ }
89
 
90
+ protected function getSectionSubTitle() :string {
91
+ return __( 'Controlling WordPress Automatic Updates', 'wp-simple-firewall' );
92
  }
93
 
94
  private function getCardsForPlugins() :array {
95
  $cards = [];
96
 
97
+ $WPP = Services::WpPlugins();
98
+ $nCount = count( $WPP->getPlugins() ) - count( $WPP->getActivePlugins() );
99
  $cards[ 'plugins_inactive' ] = [
100
  'name' => __( 'Inactive Plugins', 'wp-simple-firewall' ),
101
  'state' => $nCount > 0 ? -1 : 1,
106
  'help' => __( 'Unused plugins should be removed.', 'wp-simple-firewall' )
107
  ];
108
 
109
+ $nCount = count( $WPP->getUpdates() );
110
  $cards[ 'plugin_updates' ] = [
111
  'name' => __( 'Plugin Updates', 'wp-simple-firewall' ),
112
  'state' => $nCount > 0 ? -1 : 1,
src/lib/src/Modules/Base/AdminPage.php ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
+
8
+ class AdminPage extends ExecOnceModConsumer {
9
+
10
+ protected $screenID;
11
+
12
+ protected function canRun() :bool {
13
+ return !Services::WpGeneral()->isAjax() && ( is_admin() || is_network_admin() );
14
+ }
15
+
16
+ protected function run() {
17
+ $con = $this->getCon();
18
+ add_action( $con->prefix( 'admin_submenu' ), function () {
19
+ $this->addSubMenuItem();
20
+ }, $this->getMenuPriority() );
21
+ }
22
+
23
+ protected function addSubMenuItem() {
24
+ $this->screenID = add_submenu_page(
25
+ $this->isShowMenu() ? $this->getCon()->prefix() : null,
26
+ $this->getPageTitle(),
27
+ $this->getMenuTitle(),
28
+ $this->getCap(),
29
+ $this->getMod()->getModSlug(),
30
+ [ $this, 'displayModuleAdminPage' ]
31
+ );
32
+
33
+ foreach ( $this->getAdditionalMenuItems() as $additionalMenuItem ) {
34
+ list( $itemText, $itemID, $itemCallback, $showItem ) = $additionalMenuItem;
35
+ add_submenu_page(
36
+ $showItem ? $this->getCon()->prefix() : null,
37
+ $itemText,
38
+ $itemText,
39
+ $this->getCap(),
40
+ $itemID,
41
+ $itemCallback
42
+ );
43
+ }
44
+ }
45
+
46
+ /**
47
+ * @uses echo()
48
+ */
49
+ public function displayModuleAdminPage() {
50
+ echo $this->renderModulePage();
51
+ }
52
+
53
+ public function getScreenID() :string {
54
+ return (string)$this->screenID;
55
+ }
56
+
57
+ /**
58
+ * Override this to customize anything with the display of the page
59
+ * @param array $data
60
+ * @return string
61
+ */
62
+ protected function renderModulePage( array $data = [] ) :string {
63
+ return $this->getMod()->renderTemplate(
64
+ 'index.php',
65
+ Services::DataManipulation()->mergeArraysRecursive( $this->getMod()->getUIHandler()
66
+ ->getBaseDisplayData(), $data )
67
+ );
68
+ }
69
+
70
+ protected function getMenuPriority() :int {
71
+ $pri = $this->getOptions()->getFeatureProperty( 'menu_priority' );
72
+ return is_null( $pri ) ? 100 : (int)$pri;
73
+ }
74
+
75
+ public function getCap() :string {
76
+ return $this->getCon()->getBasePermissions();
77
+ }
78
+
79
+ public function isShowMenu() :bool {
80
+ return (bool)$this->getOptions()->getFeatureProperty( 'show_module_menu_item' );
81
+ }
82
+
83
+ public function getMenuTitle( bool $markup = true ) :string {
84
+ $mod = $this->getMod();
85
+ $title = $this->getOptions()->getFeatureProperty( 'menu_title' );
86
+ $title = empty( $title ) ? $mod->getMainFeatureName() : __( $title, 'wp-simple-firewall' );
87
+ if ( $markup && $this->getOptions()->getFeatureProperty( 'highlight_menu_item' ) ) {
88
+ $title = sprintf( '<span class="shield_highlighted_menu">%s</span>', $title );
89
+ }
90
+ return $title;
91
+ }
92
+
93
+ public function getPageTitle() :string {
94
+ return sprintf( '%s - %s', $this->getMenuTitle( false ), $this->getCon()->getHumanName() );
95
+ }
96
+
97
+ public function getAdditionalMenuItems() :array {
98
+ $items = [];
99
+
100
+ $con = $this->getCon();
101
+ $mod = $this->getMod();
102
+ foreach ( $this->getOptions()->getAdditionalMenuItems() as $menuItem ) {
103
+
104
+ // special case: don't show go pro if you're pro.
105
+ if ( $menuItem[ 'slug' ] !== 'pro-redirect' || !$mod->isPremium() ) {
106
+
107
+ $title = __( $menuItem[ 'title' ], 'wp-simple-firewall' );
108
+ $menuPageTitle = $con->getHumanName().' - '.$title;
109
+ $isHighlighted = $menuItem[ 'highlight' ] ?? false;
110
+ $items[ $menuPageTitle ] = [
111
+ $isHighlighted ? sprintf( '<span class="shield_highlighted_menu">%s</span>', $title ) : $title,
112
+ $mod->prefix( $menuItem[ 'slug' ] ),
113
+ [ $this, $menuItem[ 'callback' ] ?? '' ],
114
+ true
115
+ ];
116
+ }
117
+ }
118
+ return $items;
119
+ }
120
+ }
src/lib/src/Modules/Base/Common/ExecOnceModConsumer.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common;
4
+
5
+ use FernleafSystems\Utilities\Logic\ExecOnce;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
+
8
+ class ExecOnceModConsumer {
9
+
10
+ use ModConsumer;
11
+ use ExecOnce;
12
+ }
src/lib/src/Modules/Base/Insights/OverviewCards.php CHANGED
@@ -9,16 +9,51 @@ class OverviewCards {
9
  use Shield\Modules\ModConsumer;
10
 
11
  public function build() :array {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  return [];
13
  }
14
 
15
- protected function getModDisabledCard() :array {
16
- $mod = $this->getMod();
17
  return [
18
- 'name' => __( 'Module Disabled', 'wp-simple-firewall' ),
19
- 'summary' => __( 'All features of this module are completely disabled', 'wp-simple-firewall' ),
20
- 'state' => -2,
21
- 'href' => $mod->getUrl_DirectLinkToOption( $mod->getEnableModOptKey() ),
22
  ];
23
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  }
9
  use Shield\Modules\ModConsumer;
10
 
11
  public function build() :array {
12
+ $mod = $this->getMod();
13
+ return [
14
+ $this->getMod()->getModSlug( false ) => [
15
+ 'title' => $this->getSectionTitle(),
16
+ 'subtitle' => $mod->getStrings()->getModTagLine(),
17
+ 'href_options' => $mod->getUrl_AdminPage(),
18
+ 'cards' => $this->buildCards()
19
+ ]
20
+ ];
21
+ }
22
+
23
+ protected function buildCards() :array {
24
+ return array_filter( array_merge( $this->buildCommonCards(), $this->buildModCards() ) );
25
+ }
26
+
27
+ protected function buildModCards() :array {
28
  return [];
29
  }
30
 
31
+ protected function buildCommonCards() :array {
 
32
  return [
33
+ 'mod' => $this->getModDisabledCard()
 
 
 
34
  ];
35
  }
36
+
37
+ protected function getSectionTitle() :string {
38
+ return $this->getMod()->getMainFeatureName();
39
+ }
40
+
41
+ protected function getSectionSubTitle() :string {
42
+ return $this->getMod()->getStrings()->getModTagLine();
43
+ }
44
+
45
+ protected function getModDisabledCard() :array {
46
+ $mod = $this->getMod();
47
+ $card = [];
48
+ if ( $mod->getOptions()->optExists( $mod->getEnableModOptKey() ) && !$mod->isModOptEnabled() ) {
49
+ $card = [
50
+ 'name' => sprintf( '%s: %s',
51
+ $this->getMod()->getMainFeatureName(), __( 'Disabled', 'wp-simple-firewall' ) ),
52
+ 'summary' => __( 'All features of this module are completely disabled', 'wp-simple-firewall' ),
53
+ 'state' => -2,
54
+ 'href' => $mod->getUrl_DirectLinkToOption( $mod->getEnableModOptKey() ),
55
+ ];
56
+ }
57
+ return $card;
58
+ }
59
  }
src/lib/src/Modules/Base/Lib/Rest/Request/Process.php ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Rest\Request;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Rest;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
8
+ use FernleafSystems\Wordpress\Services\Services;
9
+ use FernleafSystems\Wordpress\Services\Utilities\File\Cache;
10
+
11
+ abstract class Process {
12
+
13
+ use ModConsumer;
14
+ use Rest\Route\RestRouteConsumer;
15
+
16
+ /**
17
+ * @var RequestVO
18
+ */
19
+ private $reqVO;
20
+
21
+ /**
22
+ * @var \WP_REST_Request
23
+ */
24
+ protected $wpRestRequest;
25
+
26
+ /**
27
+ * Process constructor.
28
+ * @param Rest\Route\RouteBase|mixed $route
29
+ * @param \WP_REST_Request $restRequest
30
+ */
31
+ public function __construct( $route, \WP_REST_Request $restRequest ) {
32
+ $this->setRestRoute( $route );
33
+ $this->wpRestRequest = $restRequest;
34
+ }
35
+
36
+ /**
37
+ * @return array
38
+ */
39
+ public function run() :array {
40
+ $route = $this->getRestRoute();
41
+
42
+ $apiResponse = [
43
+ 'meta' => [
44
+ 'ts' => Services::Request()->ts(),
45
+ 'api_version' => $this->getCon()->getVersion(),
46
+ 'from_cache' => false
47
+ ],
48
+ ];
49
+
50
+ $locked = false;
51
+ try {
52
+ if ( $route->bypass_lock !== true ) {
53
+ $locker = ( new Base\Lib\Rest\Utility\RestLocker() )->setRestRoute( $route );
54
+ $locked = $locker->start();
55
+ }
56
+
57
+ // Ensure only valid parameters are supplied
58
+ $permittedParams = array_keys( $this->wpRestRequest->get_attributes()[ 'args' ] );
59
+ if ( count( array_diff_key(
60
+ $this->wpRestRequest->get_params(),
61
+ array_flip( $permittedParams )
62
+ ) ) > 0 ) {
63
+ throw new \Exception(
64
+ sprintf( 'Please only supply parameters that are permitted: %s',
65
+ implode( ', ', $permittedParams ) ), 500 );
66
+ }
67
+
68
+ // Is the site ready?
69
+ ( new Base\Lib\Rest\Utility\PreChecks() )
70
+ ->setMod( $this->getMod() )
71
+ ->run();
72
+
73
+ // Begin processing.
74
+
75
+ $cacher = $route->getCacheHandler();
76
+ $cacher->request_file = $this->getCacheFileFragment();
77
+ $cacheDef = $cacher->getCacheDefinition();
78
+ if ( $cacher->can_cache ) {
79
+ ( new Cache\LoadFromCache() )
80
+ ->setCacheDef( $cacheDef )
81
+ ->load();
82
+ if ( is_array( $cacheDef->data ) ) {
83
+ $apiResponse[ 'meta' ][ 'from_cache' ] = true;
84
+ }
85
+ }
86
+
87
+ if ( !is_array( $cacheDef->data ) ) {
88
+ $cacheDef->data = $this->process();
89
+ if ( $cacher->can_cache ) {
90
+ ( new Cache\StoreToCache() )
91
+ ->setCacheDef( $cacheDef )
92
+ ->store();
93
+ }
94
+ }
95
+
96
+ $apiResponse[ 'error' ] = false;
97
+ $apiResponse[ $this->getResponseResultsDataKey() ] = $cacheDef->data;
98
+ }
99
+ catch ( \Exception $e ) {
100
+ $apiResponse[ 'error' ] = true;
101
+ $apiResponse[ 'code' ] = $e->getCode();
102
+ $apiResponse[ 'message' ] = $e->getMessage();
103
+ $apiResponse[ $this->getResponseResultsDataKey() ] = [];
104
+ }
105
+
106
+ if ( $locked && !empty( $locker ) ) {
107
+ $locker->end();
108
+ }
109
+
110
+ return $apiResponse;
111
+ }
112
+
113
+ /**
114
+ * @return array
115
+ * @throws \Exception
116
+ */
117
+ abstract protected function process() :array;
118
+
119
+ protected function getResponseResultsDataKey() :string {
120
+ return $this->getMod()->getModSlug( false );
121
+ }
122
+
123
+ protected function getWpRestRequest() :\WP_REST_Request {
124
+ return $this->wpRestRequest;
125
+ }
126
+
127
+ /**
128
+ * @return RequestVO|mixed
129
+ */
130
+ protected function getRequestVO() {
131
+ if ( !isset( $this->reqVO ) ) {
132
+ $this->reqVO = $this->getRestRoute()
133
+ ->getNewReqVO()
134
+ ->applyFromArray( $this->wpRestRequest->get_params() );
135
+ }
136
+ return $this->reqVO;
137
+ }
138
+
139
+ protected function getCacheFileFragment() :string {
140
+ $d = $this->getWpRestRequest()->get_params();
141
+ ksort( $d );
142
+ return md5( serialize( $d ) );
143
+ }
144
+ }
src/lib/src/Modules/Base/Lib/Rest/Request/RequestVO.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Rest\Request;
4
+
5
+ /**
6
+ * Class RequestVO
7
+ * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Rest\Request
8
+ * @property string $action
9
+ * @property string $type
10
+ */
11
+ class RequestVO extends \FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass {
12
+
13
+ public function getCacheFileSlug() :string {
14
+ $aD = $this->getRawData();
15
+ ksort( $aD );
16
+ return md5( serialize( $aD ) );
17
+ }
18
+ }
src/lib/src/Modules/Base/Lib/Rest/RequestVoConsumer.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Rest;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Rest\Request\RequestVO;
6
+
7
+ trait RequestVoConsumer {
8
+
9
+ /**
10
+ * @var RequestVO
11
+ */
12
+ private $requestVO;
13
+
14
+ /**
15
+ * @return RequestVO|mixed
16
+ */
17
+ public function getRequestVO() {
18
+ return $this->requestVO;
19
+ }
20
+
21
+ /**
22
+ * @param RequestVO|mixed $reqVO
23
+ * @return $this
24
+ */
25
+ public function setRequestVO( $reqVO ) {
26
+ $this->requestVO = $reqVO;
27
+ return $this;
28
+ }
29
+ }
src/lib/src/Modules/Base/Lib/Rest/Route/RestRouteConsumer.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Rest\Route;
4
+
5
+ trait RestRouteConsumer {
6
+
7
+ /**
8
+ * @var RouteBase|mixed
9
+ */
10
+ private $restRoute;
11
+
12
+ /**
13
+ * @return RouteBase|mixed
14
+ */
15
+ public function getRestRoute() {
16
+ return $this->restRoute;
17
+ }
18
+
19
+ /**
20
+ * @param RouteBase|mixed $route
21
+ * @return $this
22
+ */
23
+ public function setRestRoute( $route ) {
24
+ $this->restRoute = $route;
25
+ return $this;
26
+ }
27
+ }
src/lib/src/Modules/Base/Lib/Rest/Route/RouteBase.php ADDED
@@ -0,0 +1,256 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Rest\Route;
4
+
5
+ use FernleafSystems\Utilities\Data\Adapter\DynProperties;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
8
+ use FernleafSystems\Wordpress\Services\Services;
9
+
10
+ /**
11
+ * Class RouteBase
12
+ * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Rest\Route
13
+ * @property bool $bypass_lock
14
+ */
15
+ abstract class RouteBase extends \WP_REST_Controller {
16
+
17
+ use ModConsumer;
18
+ use DynProperties;
19
+
20
+ /**
21
+ * @var bool
22
+ */
23
+ private $registered;
24
+
25
+ /**
26
+ * https://developer.wordpress.org/rest-api/extending-the-rest-api/adding-custom-endpoints/#examples
27
+ */
28
+ public function register_routes() {
29
+ if ( empty( $this->registered ) ) {
30
+ $this->registered = true;
31
+ if ( $this->isReady() ) {
32
+ register_rest_route( $this->getNamespace(),
33
+ $this->getRoutePath(),
34
+ [ $this->buildRouteDefs() ]
35
+ );
36
+ }
37
+ }
38
+ }
39
+
40
+ /**
41
+ * @return Base\Lib\Rest\Request\RequestVO
42
+ */
43
+ public function getNewReqVO() {
44
+ return new Base\Lib\Rest\Request\RequestVO();
45
+ }
46
+
47
+ /**
48
+ * @param array[] $aArgs
49
+ * @return array[]
50
+ */
51
+ protected function applyArgsDefaults( $aArgs ) {
52
+ return array_map(
53
+ function ( $args ) {
54
+
55
+ $args[ 'validate_callback' ] = function ( $value, $wpRequest, $reqArgKey ) {
56
+ return $this->validateRequestArg( $value, $wpRequest, $reqArgKey );
57
+ };
58
+
59
+ $args[ 'sanitize_callback' ] = function ( $value, $wpRequest, $reqArgKey ) {
60
+ return $this->sanitizeRequestArg( $value, $wpRequest, $reqArgKey );
61
+ };
62
+
63
+ return $args;
64
+ },
65
+ $aArgs
66
+ );
67
+ }
68
+
69
+ public function buildRouteDefs() :array {
70
+ return [
71
+ 'methods' => $this->getArgMethods(),
72
+ 'callback' => function ( \WP_REST_Request $req ) {
73
+ return $this->executeApiRequest( $req );
74
+ },
75
+ 'permission_callback' => function ( \WP_REST_Request $req ) {
76
+ return $this->verifyPermission( $req );
77
+ },
78
+ 'args' => $this->applyArgsDefaults( $this->getRouteArgs() ),
79
+ ];
80
+ }
81
+
82
+ public function getCacheHandler() :RouteCache {
83
+ return new RouteCache( $this );
84
+ }
85
+
86
+ protected function getNamespace() :string {
87
+ $version = $this->getMod()
88
+ ->getOptions()
89
+ ->getDef( 'rest_version' );
90
+ return sprintf( '%s/v%s',
91
+ $this->getCon()->prefix(),
92
+ is_numeric( $version ) ? $version : '1'
93
+ );
94
+ }
95
+
96
+ abstract public function getRoutePath() :string;
97
+
98
+ /**
99
+ * @return array[]
100
+ */
101
+ protected function getRouteArgs() :array {
102
+ return array_merge( $this->getRouteArgsDefaults(), $this->getRouteArgsCustom() );
103
+ }
104
+
105
+ /**
106
+ * @return array[]
107
+ */
108
+ protected function getRouteArgsCustom() :array {
109
+ return [];
110
+ }
111
+
112
+ /**
113
+ * @return array[][]
114
+ */
115
+ protected function getRouteArgsDefaults() :array {
116
+ return [];
117
+ }
118
+
119
+ protected function getRouteSlug() :string {
120
+ try {
121
+ return strtolower( ( new \ReflectionClass( $this ) )->getShortName() );
122
+ }
123
+ catch ( \ReflectionException $e ) {
124
+ return substr( md5( get_class( $this ) ), 0, 6 );
125
+ }
126
+ }
127
+
128
+ public function getArgMethods() :array {
129
+ return [ \WP_REST_Server::READABLE ];
130
+ }
131
+
132
+ /**
133
+ * @return string
134
+ * @throws \Exception
135
+ */
136
+ public function getWorkingDir() :string {
137
+ $base = $this->getMod()->getRestHandler()->getWorkingDir();
138
+ if ( !empty( $base ) ) {
139
+ $dir = path_join( $base, 'r-'.$this->getRouteSlug() );
140
+ Services::WpFs()->mkdir( $dir );
141
+ if ( !empty( realpath( $dir ) ) ) {
142
+ return $dir;
143
+ }
144
+ }
145
+ throw new \Exception( 'Working directory not available' );
146
+ }
147
+
148
+ protected function isReady() :bool {
149
+ try {
150
+ $ready = $this->getWorkingDir() !== false;
151
+ }
152
+ catch ( \Exception $e ) {
153
+ $ready = false;
154
+ }
155
+ return $ready;
156
+ }
157
+
158
+ /**
159
+ * @param \WP_REST_Request $wpReq
160
+ * @return \WP_REST_Response
161
+ */
162
+ protected function executeApiRequest( \WP_REST_Request $wpReq ) :\WP_REST_Response {
163
+
164
+ $apiResponse = $this->processRequest( $wpReq );
165
+ $apiResponse[ 'meta' ][ 'params' ] = $wpReq->get_params();
166
+ $apiResponse = $this->adjustApiResponse( $apiResponse, $wpReq );
167
+
168
+ $response = new \WP_REST_Response();
169
+ $response->set_data( $apiResponse );
170
+
171
+ if ( $apiResponse[ 'error' ] ) {
172
+ $response->set_status( empty( $apiResponse[ 'code' ] ) ? 500 : $apiResponse[ 'code' ] );
173
+ $response->header( 'Cache-Control', 'no-cache, must-revalidate' );
174
+ }
175
+ else {
176
+ $response->header( 'Cache-Control', 'public, max-age='.$this->getCacheHandler()->expiration );
177
+ $response->set_status( 200 );
178
+ }
179
+
180
+ return $response;
181
+ }
182
+
183
+ protected function adjustApiResponse( array $response, \WP_REST_Request $wpReq ) :array {
184
+ return $response;
185
+ }
186
+
187
+ abstract protected function processRequest( \WP_REST_Request $wpReq ) :array;
188
+
189
+ /**
190
+ * @param string|mixed $value
191
+ * @param \WP_REST_Request $wpRequest
192
+ * @param string $reqArgKey
193
+ * @return \WP_Error|mixed
194
+ */
195
+ public function sanitizeRequestArg( $value, \WP_REST_Request $wpRequest, string $reqArgKey ) {
196
+ try {
197
+ $value = rest_sanitize_request_arg( $value, $wpRequest, $reqArgKey );
198
+ if ( !is_wp_error( $value ) ) {
199
+ $value = $this->customSanitizeRequestArg( $value, $wpRequest, $reqArgKey );
200
+ }
201
+ }
202
+ catch ( \Exception $e ) {
203
+ $value = new \WP_Error( 400, $e->getMessage() );
204
+ }
205
+ return $value;
206
+ }
207
+
208
+ /**
209
+ * @param string|mixed $value
210
+ * @param \WP_REST_Request $wpRequest
211
+ * @param string $reqArgKey
212
+ * @return \WP_Error|bool
213
+ */
214
+ public function validateRequestArg( $value, \WP_REST_Request $wpRequest, string $reqArgKey ) {
215
+ try {
216
+ $valid = rest_validate_request_arg( $value, $wpRequest, $reqArgKey );
217
+ if ( $valid === true ) { // retain WP_ERROR info
218
+ $valid = $this->customValidateRequestArg( $value, $wpRequest, $reqArgKey );
219
+ }
220
+ }
221
+ catch ( \Exception $e ) {
222
+ $valid = new \WP_Error( 400, $e->getMessage() );
223
+ }
224
+ return $valid;
225
+ }
226
+
227
+ /**
228
+ * @param mixed $value
229
+ * @param \WP_REST_Request $wpRequest
230
+ * @param string $reqArgKey
231
+ * @return \WP_Error|mixed
232
+ * @throws \Exception
233
+ */
234
+ protected function customSanitizeRequestArg( $value, \WP_REST_Request $wpRequest, string $reqArgKey ) {
235
+ return $value;
236
+ }
237
+
238
+ /**
239
+ * @param string|mixed $value
240
+ * @param \WP_REST_Request $wpRequest
241
+ * @param string $reqArgKey
242
+ * @return true
243
+ * @throws \Exception
244
+ */
245
+ protected function customValidateRequestArg( $value, $wpRequest, $reqArgKey ) :bool {
246
+ return true;
247
+ }
248
+
249
+ /**
250
+ * @param \WP_REST_Request $req
251
+ * @return \WP_Error|true
252
+ */
253
+ protected function verifyPermission( \WP_REST_Request $req ) {
254
+ return true;
255
+ }
256
+ }
src/lib/src/Modules/Base/Lib/Rest/Route/RouteCache.php ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Rest\Route;
4
+
5
+ use FernleafSystems\Utilities\Data\Adapter\DynProperties;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
+ use FernleafSystems\Wordpress\Services\Utilities\File\Cache\CacheDefVO;
8
+
9
+ /**
10
+ * Class RouteCache
11
+ * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Rest\Route
12
+ * @property bool $can_cache
13
+ * @property string $request_file
14
+ * @property bool $is_touch
15
+ * @property int $expiration
16
+ * @property RouteBase|mixed $oRoute
17
+ */
18
+ class RouteCache {
19
+
20
+ use DynProperties;
21
+ use RestRouteConsumer;
22
+
23
+ /**
24
+ * RouteCache constructor.
25
+ * @param RouteBase|mixed $route
26
+ */
27
+ public function __construct( $route ) {
28
+ $this->setRestRoute( $route );
29
+ }
30
+
31
+ public function getCacheDefinition() :CacheDefVO {
32
+ $def = new CacheDefVO();
33
+ try {
34
+ $def->dir = path_join( $this->oRoute->getWorkingDir(), 'cache' );
35
+ $def->expiration = (int)$this->expiration;
36
+ $def->touch_on_load = (bool)$this->is_touch;
37
+ if ( !empty( $this->request_file ) ) {
38
+ $def->file_fragment = Services::Data()->addExtensionToFilePath(
39
+ $this->request_file, 'json'
40
+ );
41
+ }
42
+ }
43
+ catch ( \Exception $e ) {
44
+ }
45
+ return $def;
46
+ }
47
+ }
src/lib/src/Modules/Base/Lib/Rest/Utility/PreChecks.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Rest\Utility;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
+
7
+ class PreChecks {
8
+
9
+ use ModConsumer;
10
+
11
+ /**
12
+ * @throws \Exception
13
+ */
14
+ public function run() {
15
+ try {
16
+ $this->testFileSystem();
17
+ }
18
+ catch ( \Exception $e ) {
19
+ throw new \Exception( 'Service is temporarily unavailable. Report Code: '.$e->getCode() );
20
+ }
21
+ }
22
+
23
+ /**
24
+ * @throws \Exception
25
+ */
26
+ private function testFileSystem() {
27
+ $dir = $this->getMod()->getWorkingDir();
28
+ $space = disk_free_space( $dir );
29
+ if ( $space === false || $space < 2000000 ) {
30
+ throw new \Exception( 'Not enough disk space: '.$space, 402 );
31
+ }
32
+ }
33
+ }
src/lib/src/Modules/Base/Lib/Rest/Utility/RestLocker.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Lib\Rest\Utility;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
+
8
+ class RestLocker {
9
+
10
+ use Modules\Base\Lib\Rest\Route\RestRouteConsumer;
11
+
12
+ /**
13
+ * @return bool
14
+ * @throws \Exception
15
+ */
16
+ public function start() :bool {
17
+ $count = 0;
18
+ $max = 20;
19
+ while ( $this->isLocked() ) {
20
+ if ( $count++ > $max ) {
21
+ throw new \Exception( 'Could not get a lock - there are too many requests processing. Please try again a bit later.', 403 );
22
+ }
23
+ usleep( 50000 );
24
+ }
25
+ return $this->writeLock();
26
+ }
27
+
28
+ /**
29
+ * @return bool
30
+ * @throws \Exception
31
+ */
32
+ private function isLocked() :bool {
33
+ clearstatcache();
34
+ $FS = Services::WpFs();
35
+ $file = $this->getLockFile();
36
+ return !empty( $file ) &&
37
+ $FS->exists( $file ) && ( Services::Request()->ts() - (int)$FS->getModifiedTime( $file ) < 10 );
38
+ }
39
+
40
+ private function writeLock() :bool {
41
+ return (bool)Services::WpFs()->touch( $this->getLockFile() );
42
+ }
43
+
44
+ public function end() {
45
+ $FS = Services::WpFs();
46
+ $file = $this->getLockFile();
47
+ if ( $FS->exists( $file ) ) {
48
+ Services::WpFs()->deleteFile( $file );
49
+ }
50
+ }
51
+
52
+ /**
53
+ * @return string|bool
54
+ */
55
+ private function getLockFile() {
56
+ try {
57
+ $sBase = $this->getRestRoute()->getWorkingDir();
58
+ $file = path_join( $sBase, 'rest_process.lock' );
59
+ }
60
+ catch ( \Exception $e ) {
61
+ $file = false;
62
+ }
63
+ return $file;
64
+ }
65
+ }
src/lib/src/Modules/Base/ModCon.php CHANGED
@@ -51,6 +51,11 @@ abstract class ModCon {
51
  */
52
  private $oUI;
53
 
 
 
 
 
 
54
  /**
55
  * @var Shield\Modules\Base\Options
56
  */
@@ -61,6 +66,11 @@ abstract class ModCon {
61
  */
62
  private $oWpCli;
63
 
 
 
 
 
 
64
  /**
65
  * @var Shield\Databases\Base\Handler[]
66
  */
@@ -93,18 +103,18 @@ abstract class ModCon {
93
  }
94
  }
95
 
96
- protected function setupHooks( array $aModProps ) {
97
  $con = $this->getCon();
98
- $nRunPriority = isset( $aModProps[ 'load_priority' ] ) ? $aModProps[ 'load_priority' ] : 100;
99
 
100
  add_action( $con->prefix( 'modules_loaded' ), function () {
101
  $this->onModulesLoaded();
102
  }, $nRunPriority );
103
  add_action( $con->prefix( 'run_processors' ), [ $this, 'onRunProcessors' ], $nRunPriority );
 
104
  add_action( 'init', [ $this, 'onWpInit' ], 1 );
 
105
 
106
- $nMenuPri = isset( $aModProps[ 'menu_priority' ] ) ? $aModProps[ 'menu_priority' ] : 100;
107
- add_filter( $con->prefix( 'submenu_items' ), [ $this, 'supplySubMenuItem' ], $nMenuPri );
108
  add_action( $con->prefix( 'plugin_shutdown' ), [ $this, 'onPluginShutdown' ] );
109
  add_action( $con->prefix( 'deactivate_plugin' ), [ $this, 'onPluginDeactivate' ] );
110
  add_action( $con->prefix( 'delete_plugin' ), [ $this, 'onPluginDelete' ] );
@@ -116,6 +126,16 @@ abstract class ModCon {
116
  $this->loadAdminNotices();
117
  }
118
 
 
 
 
 
 
 
 
 
 
 
119
  // if ( $this->isAdminOptionsPage() ) {
120
  // add_action( 'current_screen', array( $this, 'onSetCurrentScreen' ) );
121
  // }
@@ -271,6 +291,12 @@ abstract class ModCon {
271
  $this->getProcessor()->execute();
272
  }
273
 
 
 
 
 
 
 
274
  public function onWpInit() {
275
 
276
  $shieldAction = $this->getCon()->getShieldAction();
@@ -542,6 +568,7 @@ abstract class ModCon {
542
  /**
543
  * @param array $items
544
  * @return array
 
545
  */
546
  public function supplySubMenuItem( $items ) {
547
 
@@ -549,7 +576,7 @@ abstract class ModCon {
549
  $title = empty( $title ) ? $this->getMainFeatureName() : __( $title, 'wp-simple-firewall' );
550
 
551
  if ( !empty( $title ) ) {
552
- $highlightedTemplate = '<span class="icwp_highlighted">%s</span>';
553
  $humanName = $this->getCon()->getHumanName();
554
 
555
  if ( $this->getOptions()->getFeatureProperty( 'highlight_menu_item' ) ) {
@@ -796,11 +823,11 @@ abstract class ModCon {
796
  */
797
  public function getWizardHandler() {
798
  if ( !isset( $this->oWizard ) ) {
799
- $sClassName = $this->getWizardClassName();
800
- if ( !class_exists( $sClassName ) ) {
801
  return null;
802
  }
803
- $this->oWizard = new $sClassName();
804
  $this->oWizard->setMod( $this );
805
  }
806
  return $this->oWizard;
@@ -948,14 +975,6 @@ abstract class ModCon {
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 {
960
  return $this->getCon()->isPremiumActive();
961
  }
@@ -1136,7 +1155,8 @@ abstract class ModCon {
1136
 
1137
  return add_query_arg(
1138
  [
1139
- 'page' => $this->getModSlug(),
 
1140
  'shield_action' => 'wizard',
1141
  'wizard' => $wizardSlug,
1142
  'nonwizard' => wp_create_nonce( 'wizard'.$wizardSlug )
@@ -1343,15 +1363,35 @@ abstract class ModCon {
1343
  * @return null|Shield\Modules\Base\Options|mixed
1344
  */
1345
  public function getOptions() {
1346
- if ( !isset( $this->oOpts ) ) {
 
1347
  $con = $this->getCon();
1348
- $this->oOpts = $this->loadModElement( 'Options' );
1349
- $this->oOpts->setPathToConfig( $con->getPath_ConfigFile( $this->getSlug() ) )
1350
- ->setRebuildFromFile( $con->cfg->rebuilt )
1351
- ->setOptionsStorageKey( $this->getOptionsStorageKey() )
1352
- ->setIfLoadOptionsFromStorage( !$con->getIsResetPlugin() );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1353
  }
1354
- return $this->oOpts;
1355
  }
1356
 
1357
  /**
@@ -1415,7 +1455,7 @@ abstract class ModCon {
1415
  if ( $req->query( 'debug' ) && $req->query( 'mod' ) == $this->getModSlug()
1416
  && $this->getCon()->isPluginAdmin() ) {
1417
  /** @var Shield\Modules\Base\Debug $debug */
1418
- $debug = $this->loadModElement( 'Debug', true );
1419
  $debug->run();
1420
  }
1421
  }
@@ -1424,21 +1464,20 @@ abstract class ModCon {
1424
  * @return Shield\Modules\Base\Strings|mixed
1425
  */
1426
  protected function loadStrings() {
1427
- return $this->loadModElement( 'Strings', true );
1428
  }
1429
 
1430
  /**
1431
  * @param string $class
1432
- * @param false $injectMod
1433
  * @return false|Shield\Modules\ModConsumer
1434
  */
1435
- private function loadModElement( string $class, $injectMod = true ) {
1436
  $element = false;
1437
  try {
1438
  $C = $this->findElementClass( $class, true );
1439
  /** @var Shield\Modules\ModConsumer $element */
1440
  $element = @class_exists( $C ) ? new $C() : false;
1441
- if ( $injectMod && method_exists( $element, 'setMod' ) ) {
1442
  $element->setMod( $this );
1443
  }
1444
  }
51
  */
52
  private $oUI;
53
 
54
+ /**
55
+ * @var Shield\Modules\Base\Options
56
+ */
57
+ private $opts;
58
+
59
  /**
60
  * @var Shield\Modules\Base\Options
61
  */
66
  */
67
  private $oWpCli;
68
 
69
+ /**
70
+ * @var Shield\Modules\Base\AdminPage
71
+ */
72
+ private $adminPage;
73
+
74
  /**
75
  * @var Shield\Databases\Base\Handler[]
76
  */
103
  }
104
  }
105
 
106
+ protected function setupHooks( array $modProps ) {
107
  $con = $this->getCon();
108
+ $nRunPriority = $modProps[ 'load_priority' ] ?? 100;
109
 
110
  add_action( $con->prefix( 'modules_loaded' ), function () {
111
  $this->onModulesLoaded();
112
  }, $nRunPriority );
113
  add_action( $con->prefix( 'run_processors' ), [ $this, 'onRunProcessors' ], $nRunPriority );
114
+
115
  add_action( 'init', [ $this, 'onWpInit' ], 1 );
116
+ add_action( 'init', [ $this, 'onWpLoaded' ], 1 );
117
 
 
 
118
  add_action( $con->prefix( 'plugin_shutdown' ), [ $this, 'onPluginShutdown' ] );
119
  add_action( $con->prefix( 'deactivate_plugin' ), [ $this, 'onPluginDeactivate' ] );
120
  add_action( $con->prefix( 'delete_plugin' ), [ $this, 'onPluginDelete' ] );
126
  $this->loadAdminNotices();
127
  }
128
 
129
+ if ( $this->getOptions()->getDef( 'rest_api' ) ) {
130
+ add_action( 'rest_api_init', function () {
131
+ try {
132
+ $this->getRestHandler()->init();
133
+ }
134
+ catch ( \Exception $e ) {
135
+ }
136
+ } );
137
+ }
138
+
139
  // if ( $this->isAdminOptionsPage() ) {
140
  // add_action( 'current_screen', array( $this, 'onSetCurrentScreen' ) );
141
  // }
291
  $this->getProcessor()->execute();
292
  }
293
 
294
+ public function onWpLoaded() {
295
+ if ( is_admin() || is_network_admin() ) {
296
+ $this->getAdminPage()->execute();
297
+ }
298
+ }
299
+
300
  public function onWpInit() {
301
 
302
  $shieldAction = $this->getCon()->getShieldAction();
568
  /**
569
  * @param array $items
570
  * @return array
571
+ * @deprecated 11.2
572
  */
573
  public function supplySubMenuItem( $items ) {
574
 
576
  $title = empty( $title ) ? $this->getMainFeatureName() : __( $title, 'wp-simple-firewall' );
577
 
578
  if ( !empty( $title ) ) {
579
+ $highlightedTemplate = '<span class="shield_highlighted_menu">%s</span>';
580
  $humanName = $this->getCon()->getHumanName();
581
 
582
  if ( $this->getOptions()->getFeatureProperty( 'highlight_menu_item' ) ) {
823
  */
824
  public function getWizardHandler() {
825
  if ( !isset( $this->oWizard ) ) {
826
+ $class = $this->getWizardClassName();
827
+ if ( !class_exists( $class ) ) {
828
  return null;
829
  }
830
+ $this->oWizard = new $class();
831
  $this->oWizard->setMod( $this );
832
  }
833
  return $this->oWizard;
975
  && Services::Request()->isGet() && $this->isThisModulePage();
976
  }
977
 
 
 
 
 
 
 
 
 
978
  public function isPremium() :bool {
979
  return $this->getCon()->isPremiumActive();
980
  }
1155
 
1156
  return add_query_arg(
1157
  [
1158
+ 'page' => $this->getCon()->getModule_Insights()->getModSlug(),
1159
+ 'inav' => 'wizard',
1160
  'shield_action' => 'wizard',
1161
  'wizard' => $wizardSlug,
1162
  'nonwizard' => wp_create_nonce( 'wizard'.$wizardSlug )
1363
  * @return null|Shield\Modules\Base\Options|mixed
1364
  */
1365
  public function getOptions() {
1366
+ $opts = $this->opts ?? $this->oOpts;
1367
+ if ( !$opts instanceof Options ) {
1368
  $con = $this->getCon();
1369
+ $this->opts = $this->loadModElement( 'Options' );
1370
+ $this->opts->setPathToConfig( $con->getPath_ConfigFile( $this->getSlug() ) )
1371
+ ->setRebuildFromFile( $con->cfg->rebuilt )
1372
+ ->setOptionsStorageKey( $this->getOptionsStorageKey() )
1373
+ ->setIfLoadOptionsFromStorage( !$con->getIsResetPlugin() );
1374
+ $opts = $this->opts;
1375
+ /** @deprecated 11.2 */
1376
+ }
1377
+ return $opts;
1378
+ }
1379
+
1380
+ /**
1381
+ * @return RestHandler|mixed
1382
+ */
1383
+ public function getRestHandler() {
1384
+ return $this->loadModElement( 'RestHandler' );
1385
+ }
1386
+
1387
+ /**
1388
+ * @return AdminPage
1389
+ */
1390
+ public function getAdminPage() {
1391
+ if ( !isset( $this->adminPage ) ) {
1392
+ $this->adminPage = $this->loadModElement( 'AdminPage' );
1393
  }
1394
+ return $this->adminPage;
1395
  }
1396
 
1397
  /**
1455
  if ( $req->query( 'debug' ) && $req->query( 'mod' ) == $this->getModSlug()
1456
  && $this->getCon()->isPluginAdmin() ) {
1457
  /** @var Shield\Modules\Base\Debug $debug */
1458
+ $debug = $this->loadModElement( 'Debug' );
1459
  $debug->run();
1460
  }
1461
  }
1464
  * @return Shield\Modules\Base\Strings|mixed
1465
  */
1466
  protected function loadStrings() {
1467
+ return $this->loadModElement( 'Strings' );
1468
  }
1469
 
1470
  /**
1471
  * @param string $class
 
1472
  * @return false|Shield\Modules\ModConsumer
1473
  */
1474
+ private function loadModElement( string $class ) {
1475
  $element = false;
1476
  try {
1477
  $C = $this->findElementClass( $class, true );
1478
  /** @var Shield\Modules\ModConsumer $element */
1479
  $element = @class_exists( $C ) ? new $C() : false;
1480
+ if ( method_exists( $element, 'setMod' ) ) {
1481
  $element->setMod( $this );
1482
  }
1483
  }
src/lib/src/Modules/Base/Options.php CHANGED
@@ -171,12 +171,12 @@ class Options {
171
  }
172
 
173
  /**
174
- * @param $sProperty
175
  * @return null|mixed
176
  */
177
- public function getFeatureProperty( $sProperty ) {
178
  $raw = $this->getRawData_FullFeatureConfig();
179
- return ( isset( $raw[ 'properties' ] ) && isset( $raw[ 'properties' ][ $sProperty ] ) ) ? $raw[ 'properties' ][ $sProperty ] : null;
180
  }
181
 
182
  public function getWpCliCfg() :array {
@@ -648,6 +648,10 @@ class Options {
648
  return (bool)$this->getOptProperty( $key, 'premium' );
649
  }
650
 
 
 
 
 
651
  public function resetOptToDefault( string $key ) :self {
652
  return $this->setOpt( $key, $this->getOptDefault( $key ) );
653
  }
171
  }
172
 
173
  /**
174
+ * @param $property
175
  * @return null|mixed
176
  */
177
+ public function getFeatureProperty( $property ) {
178
  $raw = $this->getRawData_FullFeatureConfig();
179
+ return ( isset( $raw[ 'properties' ] ) && isset( $raw[ 'properties' ][ $property ] ) ) ? $raw[ 'properties' ][ $property ] : null;
180
  }
181
 
182
  public function getWpCliCfg() :array {
648
  return (bool)$this->getOptProperty( $key, 'premium' );
649
  }
650
 
651
+ public function optExists( string $key ) :bool {
652
+ return !empty( $this->getRawData_SingleOption( $key ) );
653
+ }
654
+
655
  public function resetOptToDefault( string $key ) :self {
656
  return $this->setOpt( $key, $this->getOptDefault( $key ) );
657
  }
src/lib/src/Modules/Base/RestHandler.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
+
8
+ abstract class RestHandler {
9
+
10
+ use ModConsumer;
11
+
12
+ /**
13
+ * @var Lib\Rest\Route\RouteBase[]
14
+ */
15
+ private $routes;
16
+
17
+ public function init() {
18
+ if ( $this->getIfPublishRoutes() ) {
19
+ foreach ( $this->getRoutes() as $route ) {
20
+ $route->register_routes();
21
+ }
22
+ }
23
+ }
24
+
25
+ /**
26
+ * @return Lib\Rest\Route\RouteBase[]
27
+ */
28
+ protected function enumRoutes() :array {
29
+ return [];
30
+ }
31
+
32
+ protected function getIfPublishRoutes() :bool {
33
+ return true;
34
+ }
35
+
36
+ /**
37
+ * @return Lib\Rest\Route\RouteBase[]
38
+ */
39
+ public function getRoutes() :array {
40
+ if ( !isset( $this->routes ) ) {
41
+ $this->routes = array_map(
42
+ function ( $route ) {
43
+ return $route->setMod( $this->getMod() );
44
+ },
45
+ $this->enumRoutes()
46
+ );
47
+ }
48
+ return $this->routes;
49
+ }
50
+
51
+ /**
52
+ * @return string
53
+ * @throws \Exception
54
+ */
55
+ public function getWorkingDir() :string {
56
+ $base = $this->getMod()->getWorkingDir();
57
+ if ( !empty( $base ) ) {
58
+ $dir = path_join( $base, 'api' );
59
+ Services::WpFs()->mkdir( $dir );
60
+ if ( !empty( realpath( $dir ) ) ) {
61
+ return $dir;
62
+ }
63
+ }
64
+ throw new \Exception( 'Working directory not available' );
65
+ }
66
+ }
src/lib/src/Modules/Base/Strings.php CHANGED
@@ -10,7 +10,7 @@ class Strings {
10
  use ModConsumer;
11
 
12
  public function getModTagLine() :string {
13
- return __( $this->getOptions()->getFeatureProperty( 'tagline' ), 'wp-simple-firewall' );
14
  }
15
 
16
  /**
@@ -42,7 +42,7 @@ class Strings {
42
  'btn_options' => __( 'Options' ),
43
  'btn_help' => __( 'Help' ),
44
  'btn_wizards' => $this->getMod()->hasWizard() ? __( 'Wizards' ) : __( 'No Wizards' ),
45
- 'go_to_settings' => __( 'Settings', 'wp-simple-firewall' ),
46
  'on' => __( 'On', 'wp-simple-firewall' ),
47
  'off' => __( 'Off', 'wp-simple-firewall' ),
48
  'yes' => __( 'Yes' ),
10
  use ModConsumer;
11
 
12
  public function getModTagLine() :string {
13
+ return (string)__( $this->getOptions()->getFeatureProperty( 'tagline' ), 'wp-simple-firewall' );
14
  }
15
 
16
  /**
42
  'btn_options' => __( 'Options' ),
43
  'btn_help' => __( 'Help' ),
44
  'btn_wizards' => $this->getMod()->hasWizard() ? __( 'Wizards' ) : __( 'No Wizards' ),
45
+ 'go_to_settings' => __( 'Configuration', 'wp-simple-firewall' ),
46
  'on' => __( 'On', 'wp-simple-firewall' ),
47
  'off' => __( 'Off', 'wp-simple-firewall' ),
48
  'yes' => __( 'Yes' ),
src/lib/src/Modules/Base/UI.php CHANGED
@@ -247,7 +247,7 @@ class UI {
247
  'js_bootstrap' => $urlBuilder->forJs( 'bootstrap' ),
248
  'js_fancybox' => $urlBuilder->forJs( 'jquery.fancybox.min' ),
249
  'js_globalplugin' => $urlBuilder->forJs( 'global-plugin' ),
250
- 'js_steps' => $urlBuilder->forJs( 'jquery.steps.min' ),
251
  ],
252
  'imgs' => [
253
  'favicon' => $urlBuilder->forImage( 'pluginlogo_24x24.png' ),
247
  'js_bootstrap' => $urlBuilder->forJs( 'bootstrap' ),
248
  'js_fancybox' => $urlBuilder->forJs( 'jquery.fancybox.min' ),
249
  'js_globalplugin' => $urlBuilder->forJs( 'global-plugin' ),
250
+ 'js_steps' => 'https://cdnjs.cloudflare.com/ajax/libs/jquery-steps/1.1.0/jquery.steps.min.js',
251
  ],
252
  'imgs' => [
253
  'favicon' => $urlBuilder->forImage( 'pluginlogo_24x24.png' ),
src/lib/src/Modules/Base/Upgrade.php CHANGED
@@ -1,14 +1,10 @@
1
- <?php
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
4
 
5
- use FernleafSystems\Utilities\Logic\ExecOnce;
6
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
 
8
- class Upgrade {
9
-
10
- use ModConsumer;
11
- use ExecOnce;
12
 
13
  protected function run() {
14
  $this->upgradeModule();
1
+ <?php declare( strict_types=1 );
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
 
6
 
7
+ class Upgrade extends ExecOnceModConsumer {
 
 
 
8
 
9
  protected function run() {
10
  $this->upgradeModule();
src/lib/src/Modules/Base/WpCli.php CHANGED
@@ -1,20 +1,16 @@
1
- <?php
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
4
 
5
- use FernleafSystems\Utilities\Logic\ExecOnce;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\WpCli\ModuleStandard;
7
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
8
 
9
- class WpCli {
10
-
11
- use ModConsumer;
12
- use ExecOnce;
13
 
14
  protected function run() {
15
  try {
16
  foreach ( $this->getAllCmdHandlers() as $handler ) {
17
- $handler->setMod( $this->getMod() )->execute();
18
  }
19
  }
20
  catch ( \Exception $e ) {
@@ -25,9 +21,14 @@ class WpCli {
25
  * @return WpCli[]
26
  */
27
  protected function getAllCmdHandlers() :array {
28
- return array_merge(
29
- [ new ModuleStandard() ],
30
- $this->getCmdHandlers()
 
 
 
 
 
31
  );
32
  }
33
 
1
+ <?php declare( strict_types=1 );
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\WpCli\ModuleStandard;
 
7
 
8
+ class WpCli extends ExecOnceModConsumer {
 
 
 
9
 
10
  protected function run() {
11
  try {
12
  foreach ( $this->getAllCmdHandlers() as $handler ) {
13
+ $handler->execute();
14
  }
15
  }
16
  catch ( \Exception $e ) {
21
  * @return WpCli[]
22
  */
23
  protected function getAllCmdHandlers() :array {
24
+ return array_map(
25
+ function ( $handler ) {
26
+ $handler->setMod( $this->getMod() );
27
+ },
28
+ array_merge(
29
+ [ new ModuleStandard() ],
30
+ $this->getCmdHandlers()
31
+ )
32
  );
33
  }
34
 
src/lib/src/Modules/BaseShield/AdminPage.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
4
+
5
+ class AdminPage extends \FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\AdminPage {
6
+
7
+ /**
8
+ * @uses echo()
9
+ */
10
+ public function displayModuleAdminPage() {
11
+ if ( $this->getMod()->canDisplayOptionsForm() ) {
12
+ parent::displayModuleAdminPage();
13
+ }
14
+ else {
15
+ echo $this->getMod()->renderRestrictedPage();
16
+ }
17
+ }
18
+ }
src/lib/src/Modules/BaseShield/ModCon.php CHANGED
@@ -87,27 +87,6 @@ class ModCon extends Base\ModCon {
87
  return $cfg;
88
  }
89
 
90
- /**
91
- * @deprecated 11.0
92
- */
93
- public function getSecAdminLoginAjaxData() :array {
94
- // We set a custom mod_slug so that this module handles the ajax request
95
- $data = $this->getAjaxActionData( 'sec_admin_login' );
96
- $data[ 'mod_slug' ] = $this->prefix( 'admin_access_restriction' );
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' );
107
- $dat[ 'mod_slug' ] = $this->prefix( 'admin_access_restriction' );
108
- return $dat;
109
- }
110
-
111
  public function getPluginReportEmail() :string {
112
  return $this->getCon()
113
  ->getModule_Plugin()
@@ -126,11 +105,12 @@ class ModCon extends Base\ModCon {
126
  }
127
  }
128
 
129
- protected function renderRestrictedPage() :string {
130
  /** @var Shield\Modules\SecurityAdmin\Options $secOpts */
131
  $secOpts = $this->getCon()
132
  ->getModule_SecAdmin()
133
  ->getOptions();
 
134
  return $this->renderTemplate(
135
  '/wpadmin_pages/security_admin/index.twig',
136
  Services::DataManipulation()
@@ -217,12 +197,6 @@ class ModCon extends Base\ModCon {
217
  return self::$bIsVerifiedBot;
218
  }
219
 
220
- public function isEnabledWhitelabel() :bool {
221
- /** @var SecurityAdmin\Options $opts */
222
- $opts = $this->getCon()->getModule_SecAdmin()->getOptions();
223
- return $opts->isEnabledWhitelabel();
224
- }
225
-
226
  public function isXmlrpcBypass() :bool {
227
  return $this->getCon()
228
  ->getModule_Plugin()
@@ -257,4 +231,14 @@ class ModCon extends Base\ModCon {
257
  $this->getBaseNamespace(),
258
  ];
259
  }
 
 
 
 
 
 
 
 
 
 
260
  }
87
  return $cfg;
88
  }
89
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  public function getPluginReportEmail() :string {
91
  return $this->getCon()
92
  ->getModule_Plugin()
105
  }
106
  }
107
 
108
+ public function renderRestrictedPage() :string {
109
  /** @var Shield\Modules\SecurityAdmin\Options $secOpts */
110
  $secOpts = $this->getCon()
111
  ->getModule_SecAdmin()
112
  ->getOptions();
113
+
114
  return $this->renderTemplate(
115
  '/wpadmin_pages/security_admin/index.twig',
116
  Services::DataManipulation()
197
  return self::$bIsVerifiedBot;
198
  }
199
 
 
 
 
 
 
 
200
  public function isXmlrpcBypass() :bool {
201
  return $this->getCon()
202
  ->getModule_Plugin()
231
  $this->getBaseNamespace(),
232
  ];
233
  }
234
+
235
+ /**
236
+ * @return bool
237
+ * @deprecated 11.2
238
+ */
239
+ public function isEnabledWhitelabel() :bool {
240
+ /** @var SecurityAdmin\Options $opts */
241
+ $opts = $this->getCon()->getModule_SecAdmin()->getOptions();
242
+ return $opts->isEnabledWhitelabel();
243
+ }
244
  }
src/lib/src/Modules/BaseShield/UI.php CHANGED
@@ -13,6 +13,9 @@ class UI extends Base\UI {
13
  /** @var ModCon $mod */
14
  $mod = $this->getMod();
15
 
 
 
 
16
  return Services::DataManipulation()->mergeArraysRecursive(
17
  parent::getBaseDisplayData(),
18
  [
@@ -39,15 +42,20 @@ class UI extends Base\UI {
39
  'sec_admin_login' => $con->getModule_SecAdmin()->getSecAdminLoginAjaxData(),
40
  ],
41
  'flags' => [
42
- 'has_session' => $con->getModule_Sessions()
43
- ->getSessionCon()
44
- ->hasSession(),
45
- 'display_freshdesk_widget' => !$mod->isEnabledWhitelabel()
46
  ],
47
  'hrefs' => [
48
- 'aar_forget_key' => $con->getModule_SecAdmin()->isEnabledWhitelabel() ?
49
  $this->getCon()->getLabels()[ 'AuthorURI' ] : 'https://shsec.io/gc'
50
  ],
 
 
 
 
 
51
  'classes' => [
52
  'top_container' => implode( ' ', array_filter( [
53
  'odp-outercontainer',
13
  /** @var ModCon $mod */
14
  $mod = $this->getMod();
15
 
16
+ $isWhitelabelled = $con->getModule_SecAdmin()->getWhiteLabelController()->isEnabled();
17
+ $isPremium = $this->getCon()->isPremiumActive();
18
+
19
  return Services::DataManipulation()->mergeArraysRecursive(
20
  parent::getBaseDisplayData(),
21
  [
42
  'sec_admin_login' => $con->getModule_SecAdmin()->getSecAdminLoginAjaxData(),
43
  ],
44
  'flags' => [
45
+ 'has_session' => $con->getModule_Sessions()
46
+ ->getSessionCon()
47
+ ->hasSession(),
48
+ 'display_helpdesk_widget' => !$isWhitelabelled
49
  ],
50
  'hrefs' => [
51
+ 'aar_forget_key' => $isWhitelabelled ?
52
  $this->getCon()->getLabels()[ 'AuthorURI' ] : 'https://shsec.io/gc'
53
  ],
54
+ 'vars' => [
55
+ 'helpscout_beacon_id' => $isPremium ?
56
+ 'db2ff886-2329-4029-9452-44587df92c8c'
57
+ : 'aded6929-af83-452d-993f-a60c03b46568'
58
+ ],
59
  'classes' => [
60
  'top_container' => implode( ' ', array_filter( [
61
  'odp-outercontainer',
src/lib/src/Modules/CommentsFilter/Forms/Gasp.php CHANGED
@@ -2,16 +2,12 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter\Forms;
4
 
5
- use FernleafSystems\Utilities\Logic\ExecOnce;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Controller\Assets\Enqueue;
 
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter;
8
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
9
  use FernleafSystems\Wordpress\Services\Services;
10
 
11
- class Gasp {
12
-
13
- use ModConsumer;
14
- use ExecOnce;
15
 
16
  /**
17
  * The unique comment token assigned to this page
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter\Forms;
4
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Controller\Assets\Enqueue;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter;
 
8
  use FernleafSystems\Wordpress\Services\Services;
9
 
10
+ class Gasp extends ExecOnceModConsumer {
 
 
 
11
 
12
  /**
13
  * The unique comment token assigned to this page
src/lib/src/Modules/CommentsFilter/Forms/GoogleRecaptcha.php CHANGED
@@ -2,15 +2,11 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter\Forms;
4
 
5
- use FernleafSystems\Utilities\Logic\ExecOnce;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter;
7
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
8
  use FernleafSystems\Wordpress\Services\Services;
9
 
10
- class GoogleRecaptcha {
11
-
12
- use ModConsumer;
13
- use ExecOnce;
14
 
15
  protected function canRun() :bool {
16
  /** @var CommentsFilter\ModCon $mod */
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter\Forms;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter;
 
7
  use FernleafSystems\Wordpress\Services\Services;
8
 
9
+ class GoogleRecaptcha extends ExecOnceModConsumer {
 
 
 
10
 
11
  protected function canRun() :bool {
12
  /** @var CommentsFilter\ModCon $mod */
src/lib/src/Modules/CommentsFilter/Insights/OverviewCards.php CHANGED
@@ -7,24 +7,15 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter;
7
 
8
  class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
9
 
10
- public function build() :array {
11
  /** @var CommentsFilter\ModCon $mod */
12
  $mod = $this->getMod();
13
  /** @var CommentsFilter\Options $opts */
14
  $opts = $this->getOptions();
15
 
16
- $cardSection = [
17
- 'title' => __( 'SPAM Blocking', 'wp-simple-firewall' ),
18
- 'subtitle' => __( 'Block Bot & Human Comment SPAM', 'wp-simple-firewall' ),
19
- 'href_options' => $mod->getUrl_AdminPage()
20
- ];
21
-
22
  $cards = [];
23
 
24
- if ( !$mod->isModOptEnabled() ) {
25
- $cards[ 'mod' ] = $this->getModDisabledCard();
26
- }
27
- else {
28
  $botSpamOn = $opts->isEnabledAntiBot() || $opts->isEnabledGaspCheck() || $mod->isEnabledCaptcha();
29
  $cards[ 'bot' ] = [
30
  'name' => __( 'Bot SPAM', 'wp-simple-firewall' ),
@@ -44,7 +35,14 @@ class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
44
  ];
45
  }
46
 
47
- $cardSection[ 'cards' ] = $cards;
48
- return [ 'comments_filter' => $cardSection ];
 
 
 
 
 
 
 
49
  }
50
  }
7
 
8
  class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
9
 
10
+ protected function buildModCards() :array {
11
  /** @var CommentsFilter\ModCon $mod */
12
  $mod = $this->getMod();
13
  /** @var CommentsFilter\Options $opts */
14
  $opts = $this->getOptions();
15
 
 
 
 
 
 
 
16
  $cards = [];
17
 
18
+ if ( $mod->isModOptEnabled() ) {
 
 
 
19
  $botSpamOn = $opts->isEnabledAntiBot() || $opts->isEnabledGaspCheck() || $mod->isEnabledCaptcha();
20
  $cards[ 'bot' ] = [
21
  'name' => __( 'Bot SPAM', 'wp-simple-firewall' ),
35
  ];
36
  }
37
 
38
+ return $cards;
39
+ }
40
+
41
+ protected function getSectionTitle() :string {
42
+ return __( 'SPAM Blocking', 'wp-simple-firewall' );
43
+ }
44
+
45
+ protected function getSectionSubTitle() :string {
46
+ return __( 'Block Bot & Human Comment SPAM', 'wp-simple-firewall' );
47
  }
48
  }
src/lib/src/Modules/CommentsFilter/ModCon.php CHANGED
@@ -87,8 +87,8 @@ class ModCon extends BaseShield\ModCon {
87
  && $this->getCaptchaCfg()->ready;
88
  }
89
 
90
- public function setEnabledGasp( bool $enabled = true ) {
91
- $this->getOptions()->setOpt( 'enable_comments_gasp_protection', $enabled ? 'Y' : 'N' );
92
  }
93
 
94
  /**
87
  && $this->getCaptchaCfg()->ready;
88
  }
89
 
90
+ public function setEnabledAntiBot( bool $enabled = true ) {
91
+ $this->getOptions()->setOpt( 'enable_antibot_check', $enabled ? 'Y' : 'N' );
92
  }
93
 
94
  /**
src/lib/src/Modules/CommentsFilter/Scan/CommentAdditiveCleaner.php CHANGED
@@ -2,14 +2,10 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter\Scan;
4
 
5
- use FernleafSystems\Utilities\Logic\ExecOnce;
6
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Utilities;
8
 
9
- class CommentAdditiveCleaner {
10
-
11
- use ModConsumer;
12
- use ExecOnce;
13
 
14
  protected function run() {
15
  add_action( 'wp_set_comment_status', function ( $commentID, $newStatus ) {
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter\Scan;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
 
6
  use FernleafSystems\Wordpress\Plugin\Shield\Utilities;
7
 
8
+ class CommentAdditiveCleaner extends ExecOnceModConsumer {
 
 
 
9
 
10
  protected function run() {
11
  add_action( 'wp_set_comment_status', function ( $commentID, $newStatus ) {
src/lib/src/Modules/CommentsFilter/Scan/Scanner.php CHANGED
@@ -2,16 +2,12 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter\Scan;
4
 
5
- use FernleafSystems\Utilities\Logic\ExecOnce;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter;
7
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Utilities;
9
  use FernleafSystems\Wordpress\Services\Services;
10
 
11
- class Scanner {
12
-
13
- use ModConsumer;
14
- use ExecOnce;
15
 
16
  /**
17
  * @var string|int|null
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter\Scan;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter;
 
7
  use FernleafSystems\Wordpress\Plugin\Shield\Utilities;
8
  use FernleafSystems\Wordpress\Services\Services;
9
 
10
+ class Scanner extends ExecOnceModConsumer {
 
 
 
11
 
12
  /**
13
  * @var string|int|null
src/lib/src/Modules/CommentsFilter/Strings.php CHANGED
@@ -118,8 +118,8 @@ class Strings extends Base\Strings {
118
  break;
119
 
120
  case 'enable_antibot_check' :
121
- $name = __( 'AntiBot Detection Engine', 'wp-simple-firewall' );
122
- $summary = __( "Use AntiBot Detection Engine To Detect SPAM Bots", 'wp-simple-firewall' );
123
  $desc = [
124
  sprintf( __( "AntiBot Detection Engine is %s's exclusive bot-detection technology that removes the needs for CAPTCHA and other challenges.", 'wp-simple-firewall' ),
125
  $this->getCon()->getHumanName() ),
@@ -146,7 +146,10 @@ class Strings extends Base\Strings {
146
 
147
  case 'enable_comments_gasp_protection' :
148
  $name = __( 'SPAM Bot Protection', 'wp-simple-firewall' );
149
- $summary = __( 'Block 100% Comment SPAM From Automated Bots', 'wp-simple-firewall' );
 
 
 
150
  $desc = [
151
  sprintf( '%s - %s', __( 'Recommendation', 'wp-simple-firewall' ),
152
  __( "Use the newer AntiBot Detection Engine to detect SPAM instead of CAPTCHAs.", 'wp-simple-firewall' ) ),
@@ -172,7 +175,10 @@ class Strings extends Base\Strings {
172
 
173
  case 'google_recaptcha_style_comments' :
174
  $name = __( 'CAPTCHA', 'wp-simple-firewall' );
175
- $summary = __( 'Enable CAPTCHA To Protect Against SPAM Comments', 'wp-simple-firewall' );
 
 
 
176
  $desc = [
177
  sprintf( '%s - %s', __( 'Recommendation', 'wp-simple-firewall' ),
178
  __( "Use the newer AntiBot Detection Engine to detect SPAM instead of CAPTCHAs.", 'wp-simple-firewall' ) ),
118
  break;
119
 
120
  case 'enable_antibot_check' :
121
+ $name = __( 'AntiBot Detection Engine (ADE)', 'wp-simple-firewall' );
122
+ $summary = __( "Use ADE To Detect SPAM Bots And Block Comment SPAM", 'wp-simple-firewall' );
123
  $desc = [
124
  sprintf( __( "AntiBot Detection Engine is %s's exclusive bot-detection technology that removes the needs for CAPTCHA and other challenges.", 'wp-simple-firewall' ),
125
  $this->getCon()->getHumanName() ),
146
 
147
  case 'enable_comments_gasp_protection' :
148
  $name = __( 'SPAM Bot Protection', 'wp-simple-firewall' );
149
+ $summary = sprintf( '[DEPRECATED - %s] %s',
150
+ 'Please use the newer AntiBot setting above',
151
+ __( 'Block 100% Comment SPAM From Automated Bots', 'wp-simple-firewall' )
152
+ );
153
  $desc = [
154
  sprintf( '%s - %s', __( 'Recommendation', 'wp-simple-firewall' ),
155
  __( "Use the newer AntiBot Detection Engine to detect SPAM instead of CAPTCHAs.", 'wp-simple-firewall' ) ),
175
 
176
  case 'google_recaptcha_style_comments' :
177
  $name = __( 'CAPTCHA', 'wp-simple-firewall' );
178
+ $summary = sprintf( '[DEPRECATED - %s] %s',
179
+ 'Please use the newer AntiBot setting above',
180
+ __( 'Enable CAPTCHA To Protect Against SPAM Comments', 'wp-simple-firewall' )
181
+ );
182
  $desc = [
183
  sprintf( '%s - %s', __( 'Recommendation', 'wp-simple-firewall' ),
184
  __( "Use the newer AntiBot Detection Engine to detect SPAM instead of CAPTCHAs.", 'wp-simple-firewall' ) ),
src/lib/src/Modules/Email/Processor.php CHANGED
@@ -40,8 +40,7 @@ class Processor extends BaseShield\Processor {
40
  shuffle( $benefits );
41
  }
42
 
43
- /** @var \FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Options $secAdminOpts */
44
- $secAdminOpts = $con->getModule_SecAdmin()->getOptions();
45
  $footer = [
46
  $this->getMod()
47
  ->renderTemplate( '/email/footer.twig', [
@@ -63,7 +62,7 @@ class Processor extends BaseShield\Processor {
63
  ],
64
  'flags' => [
65
  'is_pro' => $con->isPremiumActive(),
66
- 'is_whitelabelled' => $secAdminOpts->isEnabledWhitelabel()
67
  ]
68
  ] ),
69
  ];
40
  shuffle( $benefits );
41
  }
42
 
43
+ $isWhitelabelled = $con->getModule_SecAdmin()->getWhiteLabelController()->isEnabled();
 
44
  $footer = [
45
  $this->getMod()
46
  ->renderTemplate( '/email/footer.twig', [
62
  ],
63
  'flags' => [
64
  'is_pro' => $con->isPremiumActive(),
65
+ 'is_whitelabelled' => $isWhitelabelled
66
  ]
67
  ] ),
68
  ];
src/lib/src/Modules/Events/Lib/EventsListener.php CHANGED
@@ -23,9 +23,8 @@ abstract class EventsListener {
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 () {
31
  $this->onShutdown();
23
 
24
  add_action( $con->prefix( 'event' ),
25
  function ( $event, $meta = [], $def = [] ) use ( $con ) {
26
+ $this->captureEvent( $event, $meta, $def );
27
+ }, 10, 3 );
 
28
 
29
  add_action( $con->prefix( 'plugin_shutdown' ), function () {
30
  $this->onShutdown();
src/lib/src/Modules/Events/Lib/StatsWriter.php CHANGED
@@ -21,7 +21,7 @@ class StatsWriter extends EventsListener {
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' ] ) ) {
21
  * @param array $def
22
  */
23
  protected function captureEvent( string $evt, $meta = [], $def = [] ) {
24
+ if ( empty( $def ) ) { // TODO: @deprecated 11.2 - remove this if
25
  $def = $this->getCon()->loadEventsService()->getEventDef( $evt );
26
  }
27
  if ( !empty( $def[ 'stat' ] ) ) {
src/lib/src/Modules/Firewall/Insights/OverviewCards.php CHANGED
@@ -4,50 +4,53 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Firewall\Insights;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Firewall\ModCon;
 
7
 
8
  class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
9
 
10
- public function build() :array {
11
  /** @var ModCon $mod */
12
  $mod = $this->getMod();
13
- /** @var \FernleafSystems\Wordpress\Plugin\Shield\Modules\Firewall\Options $opts */
14
  $opts = $this->getOptions();
15
 
16
- $cardSection = [
17
- 'title' => __( 'Firewall', 'wp-simple-firewall' ),
18
- 'subtitle' => __( 'Block Malicious Requests', 'wp-simple-firewall' ),
19
- 'href_options' => $mod->getUrl_AdminPage()
20
- ];
21
-
22
  $cards = [];
23
 
24
- $modEnabled = $this->getMod()->isModuleEnabled();
25
-
26
- $cards[ 'mod' ] = [
27
- 'name' => __( 'Firewall', 'wp-simple-firewall' ),
28
- 'state' => $modEnabled ? 1 : 0,
29
- 'summary' => $modEnabled ?
30
- __( 'Your site is protected against malicious requests', 'wp-simple-firewall' )
31
- : __( 'Your site is not protected against malicious requests', 'wp-simple-firewall' ),
32
- 'href' => $mod->getUrl_DirectLinkToOption( $mod->getEnableModOptKey() ),
33
- ];
34
-
35
- if ( $modEnabled ) {
36
  //ignoring admin isn't a good idea
37
- $bAdminIncluded = !$opts->isIgnoreAdmin();
38
  $cards[ 'admin' ] = [
39
- 'name' => $bAdminIncluded ?
40
  __( "Include Admins", 'wp-simple-firewall' )
41
  : __( "Ignore Admins", 'wp-simple-firewall' ),
42
- 'state' => $bAdminIncluded ? 1 : 0,
43
- 'summary' => $bAdminIncluded ?
44
  __( "Firewall rules are also applied to admins", 'wp-simple-firewall' )
45
  : __( "Firewall rules aren't applied to admins", 'wp-simple-firewall' ),
46
  'href' => $mod->getUrl_DirectLinkToOption( 'whitelist_admins' ),
47
  ];
48
  }
49
 
50
- $cardSection[ 'cards' ] = $cards;
51
- return [ 'firewall' => $cardSection ];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  }
53
  }
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Firewall\ModCon;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Firewall\Options;
8
 
9
  class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
10
 
11
+ protected function buildModCards() :array {
12
  /** @var ModCon $mod */
13
  $mod = $this->getMod();
14
+ /** @var Options $opts */
15
  $opts = $this->getOptions();
16
 
 
 
 
 
 
 
17
  $cards = [];
18
 
19
+ if ( $mod->isModOptEnabled() ) {
 
 
 
 
 
 
 
 
 
 
 
20
  //ignoring admin isn't a good idea
21
+ $includeAdmin = !$opts->isIgnoreAdmin();
22
  $cards[ 'admin' ] = [
23
+ 'name' => $includeAdmin ?
24
  __( "Include Admins", 'wp-simple-firewall' )
25
  : __( "Ignore Admins", 'wp-simple-firewall' ),
26
+ 'state' => $includeAdmin ? 1 : 0,
27
+ 'summary' => $includeAdmin ?
28
  __( "Firewall rules are also applied to admins", 'wp-simple-firewall' )
29
  : __( "Firewall rules aren't applied to admins", 'wp-simple-firewall' ),
30
  'href' => $mod->getUrl_DirectLinkToOption( 'whitelist_admins' ),
31
  ];
32
  }
33
 
34
+ return $cards;
35
+ }
36
+
37
+ protected function getSectionTitle() :string {
38
+ return __( 'Firewall', 'wp-simple-firewall' );
39
+ }
40
+
41
+ protected function getSectionSubTitle() :string {
42
+ return __( 'Block Malicious Requests', 'wp-simple-firewall' );
43
+ }
44
+
45
+ protected function getModDisabledCard() :array {
46
+ $mod = $this->getMod();
47
+ return [
48
+ 'name' => __( 'Firewall', 'wp-simple-firewall' ),
49
+ 'state' => $mod->isModOptEnabled() ? 1 : -2,
50
+ 'summary' => $mod->isModOptEnabled() ?
51
+ __( "The Firewall is protecting your site against malicious requests", 'wp-simple-firewall' )
52
+ : __( "The Firewall is disabled so your site isn't protected against malicious requests", 'wp-simple-firewall' ),
53
+ 'href' => $mod->getUrl_DirectLinkToOption( $mod->getEnableModOptKey() ),
54
+ ];
55
  }
56
  }
src/lib/src/Modules/Firewall/Lib/Scan/PerformScan.php CHANGED
@@ -3,12 +3,10 @@
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
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Firewall\Lib\Scan;
4
 
5
  use FernleafSystems\Utilities\Logic\ExecOnce;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
8
 
9
+ class PerformScan extends ExecOnceModConsumer {
 
 
 
10
 
11
  /**
12
  * @var false|\WP_Error
src/lib/src/Modules/HackGuard/AjaxHandler.php CHANGED
@@ -413,7 +413,7 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
413
  foreach ( $selected as $slug ) {
414
  try {
415
  $thisScanCon = $mod->getScanCon( $slug );
416
- if ( $thisScanCon->isScanningAvailable() ) {
417
 
418
  $toScan[] = $slug;
419
 
413
  foreach ( $selected as $slug ) {
414
  try {
415
  $thisScanCon = $mod->getScanCon( $slug );
416
+ if ( $thisScanCon->isReady() ) {
417
 
418
  $toScan[] = $slug;
419
 
src/lib/src/Modules/HackGuard/Insights/OverviewCards.php CHANGED
@@ -7,29 +7,20 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard;
7
 
8
  class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
9
 
10
- public function build() :array {
11
  /** @var HackGuard\ModCon $mod */
12
  $mod = $this->getMod();
13
  /** @var HackGuard\Options $opts */
14
  $opts = $this->getOptions();
15
 
16
- $cardSection = [
17
- 'title' => __( 'Hack Guard', 'wp-simple-firewall' ),
18
- 'subtitle' => __( 'Threats/Intrusions Detection & Repair', 'wp-simple-firewall' ),
19
- 'href_options' => $mod->getUrl_AdminPage()
20
- ];
21
-
22
  $cards = [];
23
 
24
- if ( !$mod->isModOptEnabled() ) {
25
- $cards[ 'mod' ] = $this->getModDisabledCard();
26
- }
27
- else {
28
- $bGoodFrequency = $opts->getScanFrequency() > 1;
29
  $cards[ 'frequency' ] = [
30
  'name' => __( 'Scan Frequency', 'wp-simple-firewall' ),
31
- 'state' => $bGoodFrequency ? 1 : 0,
32
- 'summary' => $bGoodFrequency ?
33
  __( 'Automatic scanners run more than once per day', 'wp-simple-firewall' )
34
  : __( "Automatic scanners only run once per day", 'wp-simple-firewall' ),
35
  'href' => $mod->getUrl_DirectLinkToSection( 'section_scan_options' ),
@@ -46,8 +37,15 @@ class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
46
  );
47
  }
48
 
49
- $cardSection[ 'cards' ] = $cards;
50
- return [ 'hack_protect' => $cardSection ];
 
 
 
 
 
 
 
51
  }
52
 
53
  private function getCardsForWcf() :array {
7
 
8
  class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
9
 
10
+ protected function buildModCards() :array {
11
  /** @var HackGuard\ModCon $mod */
12
  $mod = $this->getMod();
13
  /** @var HackGuard\Options $opts */
14
  $opts = $this->getOptions();
15
 
 
 
 
 
 
 
16
  $cards = [];
17
 
18
+ if ( $mod->isModOptEnabled() ) {
19
+ $goodFrequency = $opts->getScanFrequency() > 1;
 
 
 
20
  $cards[ 'frequency' ] = [
21
  'name' => __( 'Scan Frequency', 'wp-simple-firewall' ),
22
+ 'state' => $goodFrequency ? 1 : 0,
23
+ 'summary' => $goodFrequency ?
24
  __( 'Automatic scanners run more than once per day', 'wp-simple-firewall' )
25
  : __( "Automatic scanners only run once per day", 'wp-simple-firewall' ),
26
  'href' => $mod->getUrl_DirectLinkToSection( 'section_scan_options' ),
37
  );
38
  }
39
 
40
+ return $cards;
41
+ }
42
+
43
+ protected function getSectionTitle() :string {
44
+ return __( 'Hack Guard', 'wp-simple-firewall' );
45
+ }
46
+
47
+ protected function getSectionSubTitle() :string {
48
+ return __( 'Threats/Intrusions Detection & Repair', 'wp-simple-firewall' );
49
  }
50
 
51
  private function getCardsForWcf() :array {
src/lib/src/Modules/HackGuard/Lib/Reports/ScanAlerts.php CHANGED
@@ -62,9 +62,9 @@ class ScanAlerts extends BaseReporter {
62
  private function markAlertsAsNotified() {
63
  /** @var HackGuard\ModCon $mod */
64
  $mod = $this->getMod();
65
- /** @var Scanner\Update $oUpdater */
66
- $oUpdater = $mod->getDbHandler_ScanResults()->getQueryUpdater();
67
- $oUpdater
68
  ->setUpdateWheres( [
69
  'ignored_at' => 0,
70
  'notified_at' => 0,
62
  private function markAlertsAsNotified() {
63
  /** @var HackGuard\ModCon $mod */
64
  $mod = $this->getMod();
65
+ /** @var Scanner\Update $updater */
66
+ $updater = $mod->getDbHandler_ScanResults()->getQueryUpdater();
67
+ $updater
68
  ->setUpdateWheres( [
69
  'ignored_at' => 0,
70
  'notified_at' => 0,
src/lib/src/Modules/HackGuard/Scan/Controller/Base.php CHANGED
@@ -2,11 +2,10 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Scan\Controller;
4
 
5
- use FernleafSystems\Utilities\Logic\ExecOnce;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Databases;
 
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\ModCon;
9
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
10
  use FernleafSystems\Wordpress\Plugin\Shield\Scans;
11
  use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\BaseResultItem;
12
  use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\BaseResultsSet;
@@ -14,10 +13,7 @@ use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\BaseScanActionVO;
14
  use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\Table\BaseEntryFormatter;
15
  use FernleafSystems\Wordpress\Services\Services;
16
 
17
- abstract class Base {
18
-
19
- use ModConsumer;
20
- use ExecOnce;
21
 
22
  const SCAN_SLUG = '';
23
 
@@ -197,9 +193,19 @@ abstract class Base {
197
  }
198
 
199
  public function isReady() :bool {
200
- return $this->isEnabled() && $this->isScanningAvailable();
 
 
 
 
 
 
201
  }
202
 
 
 
 
 
203
  public function isScanningAvailable() :bool {
204
  /** @var ModCon $mod */
205
  $mod = $this->getMod();
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Scan\Controller;
4
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Databases;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\ModCon;
 
9
  use FernleafSystems\Wordpress\Plugin\Shield\Scans;
10
  use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\BaseResultItem;
11
  use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\BaseResultsSet;
13
  use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\Table\BaseEntryFormatter;
14
  use FernleafSystems\Wordpress\Services\Services;
15
 
16
+ abstract class Base extends ExecOnceModConsumer {
 
 
 
17
 
18
  const SCAN_SLUG = '';
19
 
193
  }
194
 
195
  public function isReady() :bool {
196
+ /** @var ModCon $mod */
197
+ $mod = $this->getMod();
198
+ return $mod->isModuleEnabled() && $this->isEnabled() && !$this->isRestricted();
199
+ }
200
+
201
+ public function isRestricted() :bool {
202
+ return $this->isPremiumOnly() && !$this->getCon()->isPremiumActive();
203
  }
204
 
205
+ /**
206
+ * @return bool
207
+ * @deprecated 11.2
208
+ */
209
  public function isScanningAvailable() :bool {
210
  /** @var ModCon $mod */
211
  $mod = $this->getMod();
src/lib/src/Modules/HackGuard/Scan/Controller/Ptg.php CHANGED
@@ -87,8 +87,8 @@ class Ptg extends BaseForAssets {
87
  return $this->getOptions()->isOpt( 'ptg_enable', 'Y' ) && $this->getOptions()->isOptReqsMet( 'ptg_enable' );
88
  }
89
 
90
- public function isScanningAvailable() :bool {
91
- return parent::isScanningAvailable()
92
  && $this->getOptions()->isOptReqsMet( 'ptg_enable' )
93
  && $this->getMod()->canCacheDirWrite();
94
  }
87
  return $this->getOptions()->isOpt( 'ptg_enable', 'Y' ) && $this->getOptions()->isOptReqsMet( 'ptg_enable' );
88
  }
89
 
90
+ public function isReady() :bool {
91
+ return parent::isReady()
92
  && $this->getOptions()->isOptReqsMet( 'ptg_enable' )
93
  && $this->getMod()->canCacheDirWrite();
94
  }
src/lib/src/Modules/HackGuard/Scan/Queue/CompleteQueue.php CHANGED
@@ -52,8 +52,7 @@ class CompleteQueue {
52
 
53
  /** @var Databases\ScanQueue\Delete $deleter */
54
  $deleter = $dbh->getQueryDeleter();
55
- $deleter->filterByScan( $scanSlug )
56
- ->query();
57
  }
58
 
59
  /** @var HackGuard\Options $opts */
52
 
53
  /** @var Databases\ScanQueue\Delete $deleter */
54
  $deleter = $dbh->getQueryDeleter();
55
+ $deleter->filterByScan( $scanSlug )->query();
 
56
  }
57
 
58
  /** @var HackGuard\Options $opts */
src/lib/src/Modules/HackGuard/Scan/ScansController.php CHANGED
@@ -2,18 +2,15 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Scan;
4
 
5
- use FernleafSystems\Utilities\Logic\ExecOnce;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Crons\StandardCron;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Databases;
 
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard;
9
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Options;
10
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
11
  use FernleafSystems\Wordpress\Services\Services;
12
 
13
- class ScansController {
14
 
15
- use ModConsumer;
16
- use ExecOnce;
17
  use StandardCron;
18
 
19
  private $scanCons;
@@ -123,7 +120,7 @@ class ScansController {
123
  $scans = [];
124
  foreach ( $opts->getScanSlugs() as $slug ) {
125
  $scanCon = $mod->getScanCon( $slug );
126
- if ( $scanCon->isScanningAvailable() && $scanCon->isEnabled() ) {
127
  $scans[] = $slug;
128
  }
129
  }
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Scan;
4
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Crons\StandardCron;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Databases;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard;
9
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Options;
 
10
  use FernleafSystems\Wordpress\Services\Services;
11
 
12
+ class ScansController extends ExecOnceModConsumer {
13
 
 
 
14
  use StandardCron;
15
 
16
  private $scanCons;
120
  $scans = [];
121
  foreach ( $opts->getScanSlugs() as $slug ) {
122
  $scanCon = $mod->getScanCon( $slug );
123
+ if ( $scanCon->isReady() ) {
124
  $scans[] = $slug;
125
  }
126
  }
src/lib/src/Modules/HackGuard/UI.php CHANGED
@@ -38,8 +38,9 @@ class UI extends BaseShield\UI {
38
  'item_action' => $mod->getAjaxActionData( 'item_action', true ),
39
  ],
40
  'flags' => [
41
- 'is_premium' => $this->getCon()->isPremiumActive(),
42
- 'can_scan' => count( $reasonsCantScan ) === 0,
 
43
  ],
44
  'strings' => [
45
  'never' => __( 'Never', 'wp-simple-firewall' ),
@@ -65,15 +66,18 @@ class UI extends BaseShield\UI {
65
  'no_entries_to_display' => __( "The previous scan either didn't detect any items that require your attention or they've already been repaired.", 'wp-simple-firewall' ),
66
  'scan_progress' => __( 'Scan Progress', 'wp-simple-firewall' ),
67
  'reason_not_call_self' => __( "This site currently can't make HTTP requests to itself.", 'wp-simple-firewall' ),
 
 
68
  ],
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
  ],
@@ -109,7 +113,7 @@ class UI extends BaseShield\UI {
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
  ],
@@ -175,11 +179,11 @@ class UI extends BaseShield\UI {
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(
38
  'item_action' => $mod->getAjaxActionData( 'item_action', true ),
39
  ],
40
  'flags' => [
41
+ 'is_premium' => $this->getCon()->isPremiumActive(),
42
+ 'can_scan' => count( $reasonsCantScan ) === 0,
43
+ 'module_disabled' => !$mod->isModOptEnabled(),
44
  ],
45
  'strings' => [
46
  'never' => __( 'Never', 'wp-simple-firewall' ),
66
  'no_entries_to_display' => __( "The previous scan either didn't detect any items that require your attention or they've already been repaired.", 'wp-simple-firewall' ),
67
  'scan_progress' => __( 'Scan Progress', 'wp-simple-firewall' ),
68
  'reason_not_call_self' => __( "This site currently can't make HTTP requests to itself.", 'wp-simple-firewall' ),
69
+ 'module_disabled' => __( "Scans can't run because the module that controls them is currently disabled.", 'wp-simple-firewall' ),
70
+ 'review_scanner_config' => __( "Review Scanner Module configuration", 'wp-simple-firewall' ),
71
  ],
72
  'vars' => [
73
  'initial_check' => $mod->getScanQueueController()->hasRunningScans(),
74
  'cannot_scan_reasons' => $reasonsCantScan,
75
  ],
76
  'hrefs' => [
77
+ 'scanner_mod_config' => $mod->getUrl_DirectLinkToSection('section_enable_plugin_feature_hack_protection_tools'),
78
+ 'scans_results' => $this->getCon()
79
+ ->getModule_Insights()
80
+ ->getUrl_ScansResults(),
81
  ],
82
  'scan_results' => [
83
  ],
113
  __( 'The files listed below are WordPress Core files - official files that are installed with every WordPress website.', 'wp-simple-firewall' ),
114
  __( 'However, they have either been deleted, or their contents have changed in some way.', 'wp-simple-firewall' ),
115
  __( 'Under normal circumstances this should never happen.', 'wp-simple-firewall' ),
116
+ __( 'You should review each file below and repair them. Repair means to replace file with the original.', 'wp-simple-firewall' ),
117
  __( "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' ),
118
  ],
119
  ],
179
  $lastScanAt = $scon->getLastScanAt();
180
  $scData[ 'vars' ][ 'slug' ] = $slug;
181
  $scData[ 'count' ] = $selector->countForScan( $slug );
182
+ $scData[ 'flags' ][ 'is_available' ] = $scon->isReady();
183
  // $scData[ 'flags' ][ 'show_table' ] = $scData[ 'count' ] > 0;
184
+ $scData[ 'flags' ][ 'is_restricted' ] = $scon->isRestricted();
185
  $scData[ 'flags' ][ 'is_enabled' ] = $scon->isEnabled();
186
+ $scData[ 'flags' ][ 'is_selected' ] = $scon->isReady() && in_array( $slug, $uiTrack[ 'selected_scans' ] );
187
  $scData[ 'vars' ][ 'last_scan_at_ts' ] = $lastScanAt;
188
  $scData[ 'flags' ][ 'has_last_scan' ] = $lastScanAt > 0;
189
  $scData[ 'vars' ][ 'last_scan_at' ] = sprintf(
src/lib/src/Modules/Headers/Insights/OverviewCards.php CHANGED
@@ -7,24 +7,15 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Headers\Options;
7
 
8
  class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
9
 
10
- public function build() :array {
11
  /** @var Shield\Modules\Headers\ModCon $mod */
12
  $mod = $this->getMod();
13
  /** @var Options $opts */
14
  $opts = $this->getOptions();
15
 
16
- $cardSection = [
17
- 'title' => __( 'HTTP Security Headers', 'wp-simple-firewall' ),
18
- 'subtitle' => __( 'Protect Visitors With Powerful HTTP Headers', 'wp-simple-firewall' ),
19
- 'href_options' => $mod->getUrl_AdminPage()
20
- ];
21
-
22
  $cards = [];
23
 
24
- if ( !$mod->isModOptEnabled() ) {
25
- $cards[ 'mod' ] = $this->getModDisabledCard();
26
- }
27
- else {
28
  $bAllEnabled = $opts->isEnabledXFrame() && $opts->isEnabledXssProtection()
29
  && $opts->isEnabledContentTypeHeader() && $opts->isReferrerPolicyEnabled();
30
  $cards[ 'all' ] = [
@@ -46,7 +37,14 @@ class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
46
  ];
47
  }
48
 
49
- $cardSection[ 'cards' ] = $cards;
50
- return [ 'headers' => $cardSection ];
 
 
 
 
 
 
 
51
  }
52
  }
7
 
8
  class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
9
 
10
+ protected function buildModCards() :array {
11
  /** @var Shield\Modules\Headers\ModCon $mod */
12
  $mod = $this->getMod();
13
  /** @var Options $opts */
14
  $opts = $this->getOptions();
15
 
 
 
 
 
 
 
16
  $cards = [];
17
 
18
+ if ( $mod->isModOptEnabled() ) {
 
 
 
19
  $bAllEnabled = $opts->isEnabledXFrame() && $opts->isEnabledXssProtection()
20
  && $opts->isEnabledContentTypeHeader() && $opts->isReferrerPolicyEnabled();
21
  $cards[ 'all' ] = [
37
  ];
38
  }
39
 
40
+ return $cards;
41
+ }
42
+
43
+ protected function getSectionTitle() :string {
44
+ return __( 'HTTP Security Headers', 'wp-simple-firewall' );
45
+ }
46
+
47
+ protected function getSectionSubTitle() :string {
48
+ return __( 'Protect Visitors With Powerful HTTP Headers', 'wp-simple-firewall' );
49
  }
50
  }
src/lib/src/Modules/IPs/AjaxHandler.php CHANGED
@@ -265,6 +265,10 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
265
  break;
266
 
267
  case 'delete_notbot':
 
 
 
 
268
  $success = ( new Lib\Bots\BotSignalsRecord() )
269
  ->setMod( $this->getMod() )
270
  ->setIP( $ip )
265
  break;
266
 
267
  case 'delete_notbot':
268
+ ( new Ops\DeleteIp() )
269
+ ->setMod( $this->getMod() )
270
+ ->setIP( $ip )
271
+ ->fromBlacklist();
272
  $success = ( new Lib\Bots\BotSignalsRecord() )
273
  ->setMod( $this->getMod() )
274
  ->setIP( $ip )
src/lib/src/Modules/IPs/Components/IpAddressConsumer.php CHANGED
@@ -12,22 +12,29 @@ trait IpAddressConsumer {
12
 
13
  /**
14
  * @var string
 
15
  */
16
  private $sIpAddress;
17
 
 
 
 
 
 
18
  /**
19
  * @return string
20
  */
21
  public function getIP() {
22
- return $this->sIpAddress;
23
  }
24
 
25
  /**
26
- * @param string $sIP
27
  * @return $this
28
  */
29
- public function setIP( $sIP ) {
30
- $this->sIpAddress = $sIP;
 
31
  return $this;
32
  }
33
  }
12
 
13
  /**
14
  * @var string
15
+ * @deprecated 11.2
16
  */
17
  private $sIpAddress;
18
 
19
+ /**
20
+ * @var string
21
+ */
22
+ private $ipAddress;
23
+
24
  /**
25
  * @return string
26
  */
27
  public function getIP() {
28
+ return $this->ipAddress ?? $this->sIpAddress;
29
  }
30
 
31
  /**
32
+ * @param string $IP
33
  * @return $this
34
  */
35
+ public function setIP( $IP ) {
36
+ $this->ipAddress = $IP;
37
+ $this->sIpAddress = $IP;
38
  return $this;
39
  }
40
  }
src/lib/src/Modules/IPs/Lib/AutoUnblock.php CHANGED
@@ -2,7 +2,6 @@
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;
@@ -32,24 +31,6 @@ class AutoUnblock {
32
  return $unblocked;
33
  }
34
 
35
- /**
36
- * @deprecated 10.3 - temporary to ensure that service bots aren't blocked and reduce spurious Audit Trail
37
- */
38
- private function checkForBlockedServiceBot() :bool {
39
- /** @var IPs\ModCon $mod */
40
- $mod = $this->getMod();
41
-
42
- $unblocked = false;
43
- if ( $mod->isVerifiedBot() ) {
44
- ( new IPs\Lib\Ops\DeleteIp() )
45
- ->setMod( $mod )
46
- ->setIP( Services::IP()->getRequestIp() )
47
- ->fromBlacklist();
48
- $unblocked = true;
49
- }
50
- return $unblocked;
51
- }
52
-
53
  /**
54
  * @return bool
55
  * @throws \Exception
@@ -82,11 +63,6 @@ class AutoUnblock {
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();
@@ -103,6 +79,10 @@ class AutoUnblock {
103
  ->setMod( $mod )
104
  ->setIP( $ip )
105
  ->fromBlacklist();
 
 
 
 
106
  $unblocked = true;
107
  }
108
 
@@ -155,10 +135,10 @@ class AutoUnblock {
155
  $existing = $opts->getAutoUnblockEmailIDs();
156
  $existing[ $user->ID ] = Services::Request()->ts();
157
  $opts->setOpt( 'autounblock_emailids',
158
- array_filter( $existing, function ( $nTS ) {
159
  return Services::Request()
160
  ->carbon()
161
- ->subHours( 1 )->timestamp < $nTS;
162
  } )
163
  );
164
  }
@@ -169,6 +149,10 @@ class AutoUnblock {
169
  ->setMod( $mod )
170
  ->setIP( Services::IP()->getRequestIp() )
171
  ->fromBlacklist();
 
 
 
 
172
  $unblocked = true;
173
  }
174
  else {
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;
31
  return $unblocked;
32
  }
33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  /**
35
  * @return bool
36
  * @throws \Exception
63
  throw new \Exception( 'IP already processed in the last 1hr' );
64
  }
65
 
 
 
 
 
 
66
  {
67
  $existing = $opts->getAutoUnblockIps();
68
  $existing[ $ip ] = Services::Request()->ts();
79
  ->setMod( $mod )
80
  ->setIP( $ip )
81
  ->fromBlacklist();
82
+ ( new IPs\Lib\Bots\BotSignalsRecord() )
83
+ ->setMod( $this->getMod() )
84
+ ->setIP( $ip )
85
+ ->delete();
86
  $unblocked = true;
87
  }
88
 
135
  $existing = $opts->getAutoUnblockEmailIDs();
136
  $existing[ $user->ID ] = Services::Request()->ts();
137
  $opts->setOpt( 'autounblock_emailids',
138
+ array_filter( $existing, function ( $ts ) {
139
  return Services::Request()
140
  ->carbon()
141
+ ->subHours( 1 )->timestamp < $ts;
142
  } )
143
  );
144
  }
149
  ->setMod( $mod )
150
  ->setIP( Services::IP()->getRequestIp() )
151
  ->fromBlacklist();
152
+ ( new IPs\Lib\Bots\BotSignalsRecord() )
153
+ ->setMod( $this->getMod() )
154
+ ->setIP( Services::IP()->getRequestIp() )
155
+ ->delete();
156
  $unblocked = true;
157
  }
158
  else {
src/lib/src/Modules/IPs/Lib/BlockRequest.php CHANGED
@@ -2,16 +2,12 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib;
4
 
5
- use FernleafSystems\Utilities\Logic\ExecOnce;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
7
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
8
  use FernleafSystems\Wordpress\Services\Services;
9
  use FernleafSystems\Wordpress\Services\Utilities\Obfuscate;
10
 
11
- class BlockRequest {
12
-
13
- use ModConsumer;
14
- use ExecOnce;
15
 
16
  protected function run() {
17
  if ( $this->isBlocked() ) {
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
 
7
  use FernleafSystems\Wordpress\Services\Services;
8
  use FernleafSystems\Wordpress\Services\Utilities\Obfuscate;
9
 
10
+ class BlockRequest extends ExecOnceModConsumer {
 
 
 
11
 
12
  protected function run() {
13
  if ( $this->isBlocked() ) {
src/lib/src/Modules/IPs/Lib/Bots/BotEventListener.php CHANGED
@@ -2,15 +2,10 @@
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();
@@ -51,6 +46,7 @@ class BotEventListener {
51
  [
52
  'bottrack_notbot' => 'notbot',
53
  'frontpage_load' => 'frontpage',
 
54
  'bottrack_404' => 'bt404',
55
  'bottrack_fakewebcrawler' => 'btfake',
56
  'bottrack_linkcheese' => 'btcheese',
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Bots;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
 
 
6
  use FernleafSystems\Wordpress\Services\Services;
7
 
8
+ class BotEventListener extends ExecOnceModConsumer {
 
 
 
9
 
10
  public function fireEventForIP( $ip, $event ) {
11
  $events = $this->getEventsToColumn();
46
  [
47
  'bottrack_notbot' => 'notbot',
48
  'frontpage_load' => 'frontpage',
49
+ 'loginpage_load' => 'loginpage',
50
  'bottrack_404' => 'bt404',
51
  'bottrack_fakewebcrawler' => 'btfake',
52
  'bottrack_linkcheese' => 'btcheese',
src/lib/src/Modules/IPs/Lib/Bots/BotSignalsController.php CHANGED
@@ -2,15 +2,11 @@
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\Lib\Bots\Calculator\CalculateVisitorBotScores;
7
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
8
  use FernleafSystems\Wordpress\Services\Services;
9
 
10
- class BotSignalsController {
11
-
12
- use ModConsumer;
13
- use ExecOnce;
14
 
15
  /**
16
  * @var NotBot\NotBotHandler
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Bots;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Bots\Calculator\CalculateVisitorBotScores;
 
7
  use FernleafSystems\Wordpress\Services\Services;
8
 
9
+ class BotSignalsController extends ExecOnceModConsumer {
 
 
 
10
 
11
  /**
12
  * @var NotBot\NotBotHandler
src/lib/src/Modules/IPs/Lib/Bots/BotSignalsRecord.php CHANGED
@@ -4,10 +4,12 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Bots;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\BotSignals\EntryVO;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\BotSignals\Select;
 
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Components\IpAddressConsumer;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Ops\LookupIpOnList;
9
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\ModCon;
10
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
 
11
  use FernleafSystems\Wordpress\Services\Services;
12
 
13
  class BotSignalsRecord {
@@ -55,6 +57,18 @@ class BotSignalsRecord {
55
  ->hasCookie() ? Services::Request()->ts() : 0;
56
  }
57
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  if ( $storeOnLoad ) {
59
  $this->store( $e );
60
  }
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\BotSignals\EntryVO;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\BotSignals\Select;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Databases\Session;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Components\IpAddressConsumer;
9
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Ops\LookupIpOnList;
10
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\ModCon;
11
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
12
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Sessions\Lib\Ops\Retrieve;
13
  use FernleafSystems\Wordpress\Services\Services;
14
 
15
  class BotSignalsRecord {
57
  ->hasCookie() ? Services::Request()->ts() : 0;
58
  }
59
 
60
+ if ( empty( $e->auth_at ) ) {
61
+ $dbhSessions = $this->getCon()
62
+ ->getModule_Sessions()
63
+ ->getDbHandler_Sessions();
64
+ /** @var Session\Select $selector */
65
+ $selector = $dbhSessions->getQuerySelector();
66
+ $session = $selector->setIncludeSoftDeleted( true )
67
+ ->filterByIp( $this->getIP() )
68
+ ->first();
69
+ $e->auth_at = empty( $session ) ? 0 : $session->created_at;
70
+ }
71
+
72
  if ( $storeOnLoad ) {
73
  $this->store( $e );
74
  }
src/lib/src/Modules/IPs/Lib/Bots/Calculator/BuildScores.php CHANGED
@@ -17,6 +17,9 @@ class BuildScores {
17
  $scores[ $field ] = $this->{'score_'.$field}();
18
  }
19
  $scores[ 'known' ] = $this->score_known();
 
 
 
20
  return $scores;
21
  }
22
 
@@ -36,7 +39,7 @@ class BuildScores {
36
  $score = 0;
37
  }
38
  else {
39
- $score = $this->diffTs( __FUNCTION__ ) < DAY_IN_SECONDS ? 150 : 100;
40
  }
41
  return $score;
42
  }
@@ -46,7 +49,7 @@ class BuildScores {
46
  $score = 0;
47
  }
48
  else {
49
- $score = $this->diffTs( __FUNCTION__ ) < HOUR_IN_SECONDS ? -25 : -15;
50
  }
51
  return $score;
52
  }
@@ -56,7 +59,7 @@ class BuildScores {
56
  $score = 0;
57
  }
58
  else {
59
- $score = $this->diffTs( __FUNCTION__ ) < DAY_IN_SECONDS ? -100 : -75;
60
  }
61
  return $score;
62
  }
@@ -66,7 +69,7 @@ class BuildScores {
66
  $score = 0;
67
  }
68
  else {
69
- $score = $this->diffTs( __FUNCTION__ ) < DAY_IN_SECONDS ? -65 : -45;
70
  }
71
  return $score;
72
  }
@@ -76,7 +79,7 @@ class BuildScores {
76
  $score = 0;
77
  }
78
  else {
79
- $score = $this->diffTs( __FUNCTION__ ) < DAY_IN_SECONDS ? -35 : -25;
80
  }
81
  return $score;
82
  }
@@ -86,7 +89,7 @@ class BuildScores {
86
  $score = 0;
87
  }
88
  else {
89
- $score = $this->diffTs( __FUNCTION__ ) < MINUTE_IN_SECONDS ? -50 : -25;
90
  }
91
  return $score;
92
  }
@@ -96,7 +99,7 @@ class BuildScores {
96
  $score = 0;
97
  }
98
  else {
99
- $score = $this->diffTs( __FUNCTION__ ) < DAY_IN_SECONDS ? -85 : -55;
100
  }
101
  return $score;
102
  }
@@ -116,7 +119,7 @@ class BuildScores {
116
  $score = 0;
117
  }
118
  else {
119
- $score = $this->diffTs( __FUNCTION__ ) < DAY_IN_SECONDS ? -75 : -35;
120
  }
121
  return $score;
122
  }
@@ -126,7 +129,7 @@ class BuildScores {
126
  $score = 0;
127
  }
128
  else {
129
- $score = $this->diffTs( __FUNCTION__ ) < MINUTE_IN_SECONDS ? -35 : -15;
130
  }
131
  return $score;
132
  }
@@ -136,7 +139,7 @@ class BuildScores {
136
  $score = 0;
137
  }
138
  else {
139
- $score = $this->diffTs( __FUNCTION__ ) < DAY_IN_SECONDS ? -45 : -25;
140
  }
141
  return $score;
142
  }
@@ -146,7 +149,7 @@ class BuildScores {
146
  $score = 0;
147
  }
148
  else {
149
- $score = $this->diffTs( __FUNCTION__ ) < MINUTE_IN_SECONDS ? -45 : -25;
150
  }
151
  return $score;
152
  }
@@ -156,7 +159,7 @@ class BuildScores {
156
  $score = 0;
157
  }
158
  else {
159
- $score = $this->diffTs( __FUNCTION__ ) < DAY_IN_SECONDS ? -75 : -55;
160
  }
161
  return $score;
162
  }
@@ -245,12 +248,16 @@ class BuildScores {
245
  return $score;
246
  }
247
 
 
 
 
 
248
  private function score_notbot() :int {
249
  if ( $this->lastAtTs( __FUNCTION__ ) === 0 ) {
250
- $score = -15;
251
  }
252
  else {
253
- $score = $this->diffTs( __FUNCTION__ ) < HOUR_IN_SECONDS ? 125 : 65;
254
  }
255
  return $score;
256
  }
17
  $scores[ $field ] = $this->{'score_'.$field}();
18
  }
19
  $scores[ 'known' ] = $this->score_known();
20
+ if ( Services::Request()->ts() - $this->getRecord()->created_at < 30 ) {
21
+ $scores[ 'baseline' ] = 60;
22
+ }
23
  return $scores;
24
  }
25
 
39
  $score = 0;
40
  }
41
  else {
42
+ $score = $this->diffTs( __FUNCTION__ ) < DAY_IN_SECONDS ? 175 : 150;
43
  }
44
  return $score;
45
  }
49
  $score = 0;
50
  }
51
  else {
52
+ $score = $this->diffTs( __FUNCTION__ ) < HOUR_IN_SECONDS ? -15 : -5;
53
  }
54
  return $score;
55
  }
59
  $score = 0;
60
  }
61
  else {
62
+ $score = $this->diffTs( __FUNCTION__ ) < DAY_IN_SECONDS ? -65 : -45;
63
  }
64
  return $score;
65
  }
69
  $score = 0;
70
  }
71
  else {
72
+ $score = $this->diffTs( __FUNCTION__ ) < DAY_IN_SECONDS ? -75 : -45;
73
  }
74
  return $score;
75
  }
79
  $score = 0;
80
  }
81
  else {
82
+ $score = $this->diffTs( __FUNCTION__ ) < DAY_IN_SECONDS ? -25 : -15;
83
  }
84
  return $score;
85
  }
89
  $score = 0;
90
  }
91
  else {
92
+ $score = $this->diffTs( __FUNCTION__ ) < MINUTE_IN_SECONDS ? -35 : -15;
93
  }
94
  return $score;
95
  }
99
  $score = 0;
100
  }
101
  else {
102
+ $score = $this->diffTs( __FUNCTION__ ) < HOUR_IN_SECONDS ? -85 : -55;
103
  }
104
  return $score;
105
  }
119
  $score = 0;
120
  }
121
  else {
122
+ $score = $this->diffTs( __FUNCTION__ ) < DAY_IN_SECONDS ? -55 : -35;
123
  }
124
  return $score;
125
  }
129
  $score = 0;
130
  }
131
  else {
132
+ $score = $this->diffTs( __FUNCTION__ ) < MINUTE_IN_SECONDS ? -25 : -15;
133
  }
134
  return $score;
135
  }
139
  $score = 0;
140
  }
141
  else {
142
+ $score = $this->diffTs( __FUNCTION__ ) < DAY_IN_SECONDS ? -35 : -15;
143
  }
144
  return $score;
145
  }
149
  $score = 0;
150
  }
151
  else {
152
+ $score = $this->diffTs( __FUNCTION__ ) < MINUTE_IN_SECONDS ? -35 : -25;
153
  }
154
  return $score;
155
  }
159
  $score = 0;
160
  }
161
  else {
162
+ $score = $this->diffTs( __FUNCTION__ ) < DAY_IN_SECONDS ? -55 : -45;
163
  }
164
  return $score;
165
  }
248
  return $score;
249
  }
250
 
251
+ private function score_loginpage() :int {
252
+ return $this->lastAtTs( __FUNCTION__ ) > 0 ? 15 : 0;
253
+ }
254
+
255
  private function score_notbot() :int {
256
  if ( $this->lastAtTs( __FUNCTION__ ) === 0 ) {
257
+ $score = -10;
258
  }
259
  else {
260
+ $score = $this->diffTs( __FUNCTION__ ) < HOUR_IN_SECONDS ? 150 : 75;
261
  }
262
  return $score;
263
  }
src/lib/src/Modules/IPs/Lib/Bots/NotBot/InsertNotBotJs.php CHANGED
@@ -3,13 +3,20 @@
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Bots\NotBot;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Controller\Assets\Enqueue;
6
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
 
 
7
 
8
- class InsertNotBotJs {
9
 
10
- use ModConsumer;
 
 
 
 
 
11
 
12
- public function run() {
13
  $this->enqueueJS();
14
  $this->nonceJs();
15
  }
@@ -21,6 +28,9 @@ class InsertNotBotJs {
21
  } );
22
  }
23
 
 
 
 
24
  private function nonceJs() {
25
  add_filter( 'shield/custom_localisations', function ( array $localz ) {
26
 
@@ -31,14 +41,17 @@ class InsertNotBotJs {
31
  $localz[] = [
32
  'shield/antibot',
33
  'shield_vars_antibotjs',
34
- [
35
  'ajax' => [
36
  'not_bot' => http_build_query( $ajaxData )
37
  ],
38
  'hrefs' => [
39
  'ajax' => $ajaxHref
40
  ],
41
- ]
 
 
 
42
  ];
43
  return $localz;
44
  } );
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Bots\NotBot;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Controller\Assets\Enqueue;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Bots\BotSignalsRecord;
8
+ use FernleafSystems\Wordpress\Services\Services;
9
 
10
+ class InsertNotBotJs extends ExecOnceModConsumer {
11
 
12
+ protected function canRun() :bool {
13
+ return ( Services::Request()->ts() - ( new BotSignalsRecord() )
14
+ ->setMod( $this->getMod() )
15
+ ->setIP( Services::IP()->getRequestIp() )
16
+ ->retrieve()->notbot_at ) > MINUTE_IN_SECONDS*45;
17
+ }
18
 
19
+ protected function run() {
20
  $this->enqueueJS();
21
  $this->nonceJs();
22
  }
28
  } );
29
  }
30
 
31
+ /**
32
+ * @since 11.2 - don't fire for GTMetrix page requests
33
+ */
34
  private function nonceJs() {
35
  add_filter( 'shield/custom_localisations', function ( array $localz ) {
36
 
41
  $localz[] = [
42
  'shield/antibot',
43
  'shield_vars_antibotjs',
44
+ apply_filters( 'shield/notbot_data_js', [
45
  'ajax' => [
46
  'not_bot' => http_build_query( $ajaxData )
47
  ],
48
  'hrefs' => [
49
  'ajax' => $ajaxHref
50
  ],
51
+ 'flags' => [
52
+ 'run' => !in_array( Services::IP()->getIpDetector()->getIPIdentity(), [ 'gtmetrix' ] ),
53
+ ],
54
+ ] )
55
  ];
56
  return $localz;
57
  } );
src/lib/src/Modules/IPs/Lib/Bots/NotBot/NotBotHandler.php CHANGED
@@ -2,19 +2,20 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Bots\NotBot;
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 NotBotHandler {
11
 
12
  const LIFETIME = 600;
13
  const SLUG = 'notbot';
14
- use ModConsumer;
15
- use ExecOnce;
16
 
17
- private $hashTested = false;
 
 
 
 
18
 
19
  protected function canRun() :bool {
20
  return (bool)apply_filters( 'shield/can_run_antibot', true );
@@ -23,15 +24,16 @@ class NotBotHandler {
23
  protected function run() {
24
  ( new InsertNotBotJs() )
25
  ->setMod( $this->getMod() )
26
- ->run();
27
  $this->registerFrontPageLoad();
 
28
  $this->maybeDeleteCookie();
29
  }
30
 
31
  private function registerFrontPageLoad() {
32
- add_action( 'wp', function () {
33
  $req = Services::Request();
34
- if ( $req->isGet() && is_front_page() ) {
35
  /** @var ModCon $mod */
36
  $mod = $this->getMod();
37
  $mod->getBotSignalsController()
@@ -41,6 +43,19 @@ class NotBotHandler {
41
  } );
42
  }
43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  private function maybeDeleteCookie() {
45
  $cookie = $this->getCookieParts();
46
  if ( !empty( $cookie ) && $cookie[ 'ts' ] - Services::Request()->ts() < 300 ) {
@@ -49,12 +64,14 @@ class NotBotHandler {
49
  }
50
 
51
  public function registerAsNotBot() :bool {
52
- $ts = Services::Request()->ts() + self::LIFETIME;
53
- Services::Response()->cookieSet(
54
- $this->getMod()->prefix( self::SLUG ),
55
- sprintf( '%sz%s', $ts, $this->getHashForVisitorTS( $ts ) ),
56
- self::LIFETIME
57
- );
 
 
58
  $this->getCon()->fireEvent( 'bottrack_notbot' );
59
  return true;
60
  }
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Bots\NotBot;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\ModCon;
 
7
  use FernleafSystems\Wordpress\Services\Services;
8
 
9
+ class NotBotHandler extends ExecOnceModConsumer {
10
 
11
  const LIFETIME = 600;
12
  const SLUG = 'notbot';
 
 
13
 
14
+ private $useCookies;
15
+
16
+ public function __construct( bool $useCookies = false ) {
17
+ $this->useCookies = $useCookies;
18
+ }
19
 
20
  protected function canRun() :bool {
21
  return (bool)apply_filters( 'shield/can_run_antibot', true );
24
  protected function run() {
25
  ( new InsertNotBotJs() )
26
  ->setMod( $this->getMod() )
27
+ ->execute();
28
  $this->registerFrontPageLoad();
29
+ $this->registerLoginPageLoad();
30
  $this->maybeDeleteCookie();
31
  }
32
 
33
  private function registerFrontPageLoad() {
34
+ add_action( $this->getCon()->prefix( 'pre_plugin_shutdown' ), function () {
35
  $req = Services::Request();
36
+ if ( $req->isGet() && ( is_front_page() || is_home() ) ) {
37
  /** @var ModCon $mod */
38
  $mod = $this->getMod();
39
  $mod->getBotSignalsController()
43
  } );
44
  }
45
 
46
+ private function registerLoginPageLoad() {
47
+ add_action( 'login_footer', function () {
48
+ $req = Services::Request();
49
+ if ( $req->isGet() ) {
50
+ /** @var ModCon $mod */
51
+ $mod = $this->getMod();
52
+ $mod->getBotSignalsController()
53
+ ->getEventListener()
54
+ ->fireEventForIP( Services::IP()->getRequestIp(), 'loginpage_load' );
55
+ }
56
+ } );
57
+ }
58
+
59
  private function maybeDeleteCookie() {
60
  $cookie = $this->getCookieParts();
61
  if ( !empty( $cookie ) && $cookie[ 'ts' ] - Services::Request()->ts() < 300 ) {
64
  }
65
 
66
  public function registerAsNotBot() :bool {
67
+ if ( $this->useCookies ) {
68
+ $ts = Services::Request()->ts() + self::LIFETIME;
69
+ Services::Response()->cookieSet(
70
+ $this->getMod()->prefix( self::SLUG ),
71
+ sprintf( '%sz%s', $ts, $this->getHashForVisitorTS( $ts ) ),
72
+ self::LIFETIME
73
+ );
74
+ }
75
  $this->getCon()->fireEvent( 'bottrack_notbot' );
76
  return true;
77
  }
src/lib/src/Modules/IPs/Lib/IpAnalyse/BuildDisplay.php CHANGED
@@ -6,8 +6,8 @@ use FernleafSystems\Wordpress\Plugin\Shield\Databases;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\Lib\AuditMessageBuilder;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\GeoIp\Lookup;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Components\IpAddressConsumer;
9
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Bots\Calculator\CalculateVisitorBotScores;
10
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Bots\BotSignalsRecord;
 
11
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Ops\DeleteIp;
12
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Ops\LookupIpOnList;
13
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\ModCon;
@@ -299,7 +299,7 @@ class BuildDisplay {
299
  $column = $scoreKey.'_at';
300
  if ( $scoreValue !== 0 ) {
301
  if ( empty( $record ) || empty( $record->{$column} ) ) {
302
- if ( in_array( $scoreKey, [ 'known' ] ) ) {
303
  $signals[ $scoreKey ] = __( 'N/A', 'wp-simple-firewall' );
304
  }
305
  else {
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\Lib\AuditMessageBuilder;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\GeoIp\Lookup;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Components\IpAddressConsumer;
 
9
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Bots\BotSignalsRecord;
10
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Bots\Calculator\CalculateVisitorBotScores;
11
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Ops\DeleteIp;
12
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Ops\LookupIpOnList;
13
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\ModCon;
299
  $column = $scoreKey.'_at';
300
  if ( $scoreValue !== 0 ) {
301
  if ( empty( $record ) || empty( $record->{$column} ) ) {
302
+ if ( in_array( $scoreKey, [ 'known', 'baseline' ] ) ) {
303
  $signals[ $scoreKey ] = __( 'N/A', 'wp-simple-firewall' );
304
  }
305
  else {
src/lib/src/Modules/IPs/Lib/OffenseTracker.php CHANGED
@@ -22,10 +22,8 @@ class OffenseTracker extends EventsListener {
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' ] ) ) {
22
  * @param array $def
23
  */
24
  protected function captureEvent( string $evt, $meta = [], $def = [] ) {
25
+ if ( empty( $def ) ) { // TODO: @deprecated 11.2 - remove this if
26
+ $def = $this->getCon()->loadEventsService()->getEventDef( $evt );
 
 
27
  }
28
 
29
  if ( !empty( $def[ 'offense' ] ) && empty( $meta[ 'suppress_offense' ] ) ) {
src/lib/src/Modules/IPs/Lib/Ops/LookupIpOnList.php CHANGED
@@ -129,22 +129,4 @@ class LookupIpOnList {
129
  $this->listType = 'white';
130
  return $this;
131
  }
132
-
133
- /**
134
- * @return $this
135
- * @deprecated 11.1
136
- */
137
- public function setListTypeBlack() {
138
- $this->listType = 'black';
139
- return $this;
140
- }
141
-
142
- /**
143
- * @return $this
144
- * @deprecated 11.1
145
- */
146
- public function setListTypeWhite() {
147
- $this->listType = 'white';
148
- return $this;
149
- }
150
  }
129
  $this->listType = 'white';
130
  return $this;
131
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
  }
src/lib/src/Modules/IPs/Lib/ProcessOffenses.php CHANGED
@@ -2,15 +2,11 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib;
4
 
5
- use FernleafSystems\Utilities\Logic\ExecOnce;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
7
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
8
  use FernleafSystems\Wordpress\Services\Services;
9
 
10
- class ProcessOffenses {
11
-
12
- use ModConsumer;
13
- use ExecOnce;
14
 
15
  protected function canRun() :bool {
16
  return !$this->getMod()->isTrustedVerifiedBot();
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
 
7
  use FernleafSystems\Wordpress\Services\Services;
8
 
9
+ class ProcessOffenses extends ExecOnceModConsumer {
 
 
 
10
 
11
  protected function canRun() :bool {
12
  return !$this->getMod()->isTrustedVerifiedBot();
src/lib/src/Modules/IPs/Options.php CHANGED
@@ -14,20 +14,14 @@ class Options extends BaseShield\Options {
14
  return constant( strtoupper( $this->getOpt( 'auto_expire' ).'_IN_SECONDS' ) );
15
  }
16
 
17
- /**
18
- * @return array
19
- */
20
- public function getAutoUnblockIps() {
21
- $aIps = $this->getOpt( 'autounblock_ips', [] );
22
- return is_array( $aIps ) ? $aIps : [];
23
  }
24
 
25
- /**
26
- * @return array
27
- */
28
- public function getAutoUnblockEmailIDs() {
29
- $aIps = $this->getOpt( 'autounblock_emailids', [] );
30
- return is_array( $aIps ) ? $aIps : [];
31
  }
32
 
33
  public function getCanIpRequestAutoUnblock( string $ip ) :bool {
@@ -36,20 +30,13 @@ class Options extends BaseShield\Options {
36
  || ( Services::Request()->carbon()->subHour( 1 )->timestamp > $existing[ $ip ] );
37
  }
38
 
39
- /**
40
- * @param \WP_User $user
41
- * @return bool
42
- */
43
- public function getCanRequestAutoUnblockEmailLink( \WP_User $user ) {
44
  $existing = $this->getAutoUnblockEmailIDs();
45
  return !array_key_exists( $user->ID, $existing )
46
  || ( Services::Request()->carbon()->subHour( 1 )->timestamp > $existing[ $user->ID ] );
47
  }
48
 
49
- /**
50
- * @return int
51
- */
52
- public function getOffenseLimit() {
53
  return (int)$this->getOpt( 'transgression_limit' );
54
  }
55
 
@@ -58,8 +45,8 @@ class Options extends BaseShield\Options {
58
  */
59
  public function getRequestWhitelistAsRegex() {
60
  return array_map(
61
- function ( $sRule ) {
62
- return sprintf( '#^%s$#i', str_replace( 'STAR', '.*', preg_quote( str_replace( '*', 'STAR', $sRule ), '#' ) ) );
63
  },
64
  $this->isPremium() ? $this->getOpt( 'request_whitelist', [] ) : []
65
  );
14
  return constant( strtoupper( $this->getOpt( 'auto_expire' ).'_IN_SECONDS' ) );
15
  }
16
 
17
+ public function getAutoUnblockIps() :array {
18
+ $ips = $this->getOpt( 'autounblock_ips', [] );
19
+ return is_array( $ips ) ? $ips : [];
 
 
 
20
  }
21
 
22
+ public function getAutoUnblockEmailIDs() :array {
23
+ $ips = $this->getOpt( 'autounblock_emailids', [] );
24
+ return is_array( $ips ) ? $ips : [];
 
 
 
25
  }
26
 
27
  public function getCanIpRequestAutoUnblock( string $ip ) :bool {
30
  || ( Services::Request()->carbon()->subHour( 1 )->timestamp > $existing[ $ip ] );
31
  }
32
 
33
+ public function getCanRequestAutoUnblockEmailLink( \WP_User $user ) :bool {
 
 
 
 
34
  $existing = $this->getAutoUnblockEmailIDs();
35
  return !array_key_exists( $user->ID, $existing )
36
  || ( Services::Request()->carbon()->subHour( 1 )->timestamp > $existing[ $user->ID ] );
37
  }
38
 
39
+ public function getOffenseLimit() :int {
 
 
 
40
  return (int)$this->getOpt( 'transgression_limit' );
41
  }
42
 
45
  */
46
  public function getRequestWhitelistAsRegex() {
47
  return array_map(
48
+ function ( $rule ) {
49
+ return sprintf( '#^%s$#i', str_replace( 'STAR', '.*', preg_quote( str_replace( '*', 'STAR', $rule ), '#' ) ) );
50
  },
51
  $this->isPremium() ? $this->getOpt( 'request_whitelist', [] ) : []
52
  );
src/lib/src/Modules/IPs/Strings.php CHANGED
@@ -270,9 +270,11 @@ class Strings extends Base\Strings {
270
  */
271
  public function getBotSignalNames() :array {
272
  return [
 
273
  'known' => __( 'A Known Service Provider/Bot', 'wp-simple-firewall' ),
274
  'notbot' => __( '"Not Bot" Registration', 'wp-simple-firewall' ),
275
- 'frontpage' => __( 'Normal Frontpage Visited', 'wp-simple-firewall' ),
 
276
  'bt404' => __( '404 Triggered', 'wp-simple-firewall' ),
277
  'btfake' => __( 'Fake Web Crawler', 'wp-simple-firewall' ),
278
  'btcheese' => __( 'Link Cheese', 'wp-simple-firewall' ),
270
  */
271
  public function getBotSignalNames() :array {
272
  return [
273
+ 'baseline' => __( 'Baseline Starting Score', 'wp-simple-firewall' ),
274
  'known' => __( 'A Known Service Provider/Bot', 'wp-simple-firewall' ),
275
  'notbot' => __( '"Not Bot" Registration', 'wp-simple-firewall' ),
276
+ 'frontpage' => __( 'Frontpage Visited', 'wp-simple-firewall' ),
277
+ 'loginpage' => __( 'Login Page Visited', 'wp-simple-firewall' ),
278
  'bt404' => __( '404 Triggered', 'wp-simple-firewall' ),
279
  'btfake' => __( 'Fake Web Crawler', 'wp-simple-firewall' ),
280
  'btcheese' => __( 'Link Cheese', 'wp-simple-firewall' ),
src/lib/src/Modules/IPs/UI.php CHANGED
@@ -72,7 +72,7 @@ class UI extends BaseShield\UI {
72
  }
73
 
74
  protected function getSectionWarnings( string $section ) :array {
75
- $aWarnings = [];
76
 
77
  /** @var Options $opts */
78
  $opts = $this->getOptions();
@@ -81,7 +81,7 @@ class UI extends BaseShield\UI {
81
 
82
  case 'section_auto_black_list':
83
  if ( !$opts->isEnabledAutoBlackList() ) {
84
- $aWarnings[] = sprintf( '%s: %s', __( 'Note', 'wp-simple-firewall' ), __( "IP blocking is turned-off because the offenses limit is set to 0.", 'wp-simple-firewall' ) );
85
  }
86
  break;
87
 
@@ -89,16 +89,16 @@ class UI extends BaseShield\UI {
89
  case 'section_probes':
90
  case 'section_logins':
91
  if ( !$opts->isEnabledAutoBlackList() ) {
92
- $aWarnings[] = __( "Since the offenses limit is set to 0, these options have no effect.", 'wp-simple-firewall' );
93
  }
94
 
95
  if ( $section == 'section_behaviours' && strlen( Services::Request()->getUserAgent() ) == 0 ) {
96
- $aWarnings[] = __( "Your User Agent appears to be empty. We recommend not turning on this option.", 'wp-simple-firewall' );
97
  }
98
  break;
99
  }
100
 
101
- return $aWarnings;
102
  }
103
 
104
  private function renderIpAnalyse() :string {
72
  }
73
 
74
  protected function getSectionWarnings( string $section ) :array {
75
+ $warnings = [];
76
 
77
  /** @var Options $opts */
78
  $opts = $this->getOptions();
81
 
82
  case 'section_auto_black_list':
83
  if ( !$opts->isEnabledAutoBlackList() ) {
84
+ $warnings[] = sprintf( '%s: %s', __( 'Note', 'wp-simple-firewall' ), __( "IP blocking is turned-off because the offenses limit is set to 0.", 'wp-simple-firewall' ) );
85
  }
86
  break;
87
 
89
  case 'section_probes':
90
  case 'section_logins':
91
  if ( !$opts->isEnabledAutoBlackList() ) {
92
+ $warnings[] = __( "Since the offenses limit is set to 0, these options have no effect.", 'wp-simple-firewall' );
93
  }
94
 
95
  if ( $section == 'section_behaviours' && strlen( Services::Request()->getUserAgent() ) == 0 ) {
96
+ $warnings[] = __( "Your User Agent appears to be empty. We recommend not turning on this option.", 'wp-simple-firewall' );
97
  }
98
  break;
99
  }
100
 
101
+ return $warnings;
102
  }
103
 
104
  private function renderIpAnalyse() :string {
src/lib/src/Modules/Insights/AdminPage.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Insights;
4
+
5
+ class AdminPage extends \FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield\AdminPage {
6
+
7
+ protected function renderModulePage( array $data = [] ) :string {
8
+ /** @var UI $UI */
9
+ $UI = $this->getMod()->getUIHandler();
10
+ return $UI->renderPages();
11
+ }
12
+ }
src/lib/src/Modules/Insights/Lib/Requests/DynamicPageLoader.php CHANGED
@@ -28,6 +28,9 @@ class DynamicPageLoader extends DynPropertiesClass {
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(),
@@ -35,11 +38,20 @@ class DynamicPageLoader extends DynPropertiesClass {
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:
@@ -53,7 +65,7 @@ class DynamicPageLoader extends DynPropertiesClass {
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
 
@@ -67,9 +79,9 @@ class DynamicPageLoader extends DynPropertiesClass {
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;
@@ -83,7 +95,7 @@ class DynamicPageLoader extends DynPropertiesClass {
83
  /**
84
  * @throws \Exception
85
  */
86
- private function renderSettings() :string {
87
 
88
  $mod = $this->getCon()->getModule( $this->load_variant );
89
  if ( !$mod instanceof ModCon ) {
28
  throw new \Exception( 'No dynamic page loading params' );
29
  }
30
  $this->applyFromArray( $params[ 'load_params' ] );
31
+
32
+ $this->verifyLoadParams();
33
+
34
  return [
35
  'html' => $this->getContent(),
36
  'page_url' => $this->getPageUrl(),
38
  ];
39
  }
40
 
41
+ /**
42
+ * @throws \Exception
43
+ */
44
+ private function verifyLoadParams() {
45
+ if ( !in_array( $this->load_type, [ 'configuration' ] ) ) {
46
+ throw new \Exception( 'Unsupported dynamic page load type' );
47
+ }
48
+ }
49
+
50
  private function getContent() :string {
51
 
52
  switch ( $this->load_type ) {
53
+ case 'configuration':
54
+ $content = $this->renderConfiguration();
55
  break;
56
 
57
  default:
65
  $con = $this->getCon();
66
 
67
  switch ( $this->load_type ) {
68
+ case 'configuration':
69
  $url = $con->getModule( $this->load_variant )->getUrl_AdminPage();
70
  break;
71
 
79
  $con = $this->getCon();
80
 
81
  switch ( $this->load_type ) {
82
+ case 'configuration':
83
  $title = sprintf( '%s: %s',
84
+ __( 'Configuration', 'wp-simple-firewall' ),
85
  $con->getModule( $this->load_variant )->getMainFeatureName()
86
  );
87
  break;
95
  /**
96
  * @throws \Exception
97
  */
98
+ private function renderConfiguration() :string {
99
 
100
  $mod = $this->getCon()->getModule( $this->load_variant );
101
  if ( !$mod instanceof ModCon ) {
src/lib/src/Modules/Insights/Lib/SideMenuBuilder.php CHANGED
@@ -15,7 +15,7 @@ class SideMenuBuilder {
15
  $this->search(),
16
  $this->overview(),
17
  $this->stats(),
18
- $this->settings(),
19
  $this->scans(),
20
  $this->ips(),
21
  $this->audit(),
@@ -39,12 +39,30 @@ class SideMenuBuilder {
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 ) {
@@ -53,6 +71,10 @@ class SideMenuBuilder {
53
  }
54
  }
55
 
 
 
 
 
56
  $menu[ $key ] = $item;
57
  }
58
 
@@ -75,12 +97,12 @@ class SideMenuBuilder {
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
  [
@@ -95,7 +117,9 @@ class SideMenuBuilder {
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
  }
@@ -109,13 +133,13 @@ class SideMenuBuilder {
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
  [
@@ -133,10 +157,12 @@ class SideMenuBuilder {
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
  }
@@ -163,7 +189,7 @@ class SideMenuBuilder {
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
  ];
@@ -172,8 +198,10 @@ class SideMenuBuilder {
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
  }
@@ -187,7 +215,9 @@ class SideMenuBuilder {
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',
@@ -204,7 +234,9 @@ class SideMenuBuilder {
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',
@@ -230,15 +262,17 @@ class SideMenuBuilder {
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 ) {
@@ -259,10 +293,12 @@ class SideMenuBuilder {
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
  }
@@ -273,33 +309,24 @@ class SideMenuBuilder {
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();
@@ -331,8 +358,8 @@ class SideMenuBuilder {
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',
@@ -388,7 +415,9 @@ class SideMenuBuilder {
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
  }
@@ -402,13 +431,13 @@ class SideMenuBuilder {
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
  [
@@ -423,7 +452,9 @@ class SideMenuBuilder {
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
  }
@@ -441,23 +472,23 @@ class SideMenuBuilder {
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
  ];
@@ -466,11 +497,17 @@ class SideMenuBuilder {
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
  }
15
  $this->search(),
16
  $this->overview(),
17
  $this->stats(),
18
+ $this->configuration(),
19
  $this->scans(),
20
  $this->ips(),
21
  $this->audit(),
39
  'target' => '',
40
  'data' => [],
41
  'badge' => [],
42
+ 'introjs' => [],
43
  ], $item );
44
 
45
+ if ( !empty( $item[ 'introjs' ] ) ) {
46
+ $item[ 'classes' ][] = 'tour-'.$this->getIntroJsTourID();
47
+ if ( empty( $item[ 'introjs' ][ 'title' ] ) ) {
48
+ $item[ 'introjs' ][ 'title' ] = $item[ 'title' ];
49
+ }
50
+ }
51
+
52
  if ( !empty( $item[ 'sub_items' ] ) ) {
53
  $item[ 'data' ][ 'toggle' ] = 'collapse';
54
  $item[ 'href' ] = '#collapse-'.$item[ 'slug' ];
55
 
56
+ $item[ 'sub_items' ] = array_map( function ( $sub ) {
57
+ if ( empty( $sub[ 'classes' ] ) ) {
58
+ $sub[ 'classes' ] = [];
59
+ }
60
+ if ( $sub[ 'active' ] ?? false ) {
61
+ $sub[ 'classes' ][] = 'active';
62
+ }
63
+ return $sub;
64
+ }, $item[ 'sub_items' ] );
65
+
66
  // Set parent active if any sub-items are active
67
  if ( !$item[ 'active' ] ) {
68
  $item[ 'active' ] = count( array_filter( $item[ 'sub_items' ], function ( $sub ) {
71
  }
72
  }
73
 
74
+ if ( $item[ 'active' ] ) {
75
+ $item[ 'classes' ][] = 'active';
76
+ }
77
+
78
  $menu[ $key ] = $item;
79
  }
80
 
97
  ],
98
  [
99
  'slug' => $slug.'-blocksettings',
100
+ 'title' => sprintf( '%s: %s', __( 'Configure', 'wp-simple-firewall' ), __( 'IP Blocking', 'wp-simple-firewall' ) ),
101
  'href' => $con->getModule_IPs()->getUrl_AdminPage(),
102
  ],
103
  [
104
  'slug' => $slug.'-antibotsettings',
105
+ 'title' => sprintf( '%s: %s', __( 'Configure', 'wp-simple-firewall' ), __( 'AntiBot', 'wp-simple-firewall' ) ),
106
  'href' => $con->getModule_IPs()->getUrl_DirectLinkToSection( 'section_antibot' ),
107
  ],
108
  [
117
  'slug' => $slug,
118
  'title' => __( 'IPs and Bots', 'wp-simple-firewall' ),
119
  'img' => $this->getCon()->urls->forImage( 'bootstrap/diagram-3.svg' ),
120
+ 'introjs' => [
121
+ 'body' => __( "Protection begins by detecting bad bots - Review and Analyse all visitor IPs that have an impact on your site.", 'wp-simple-firewall' ),
122
+ ],
123
  'sub_items' => $subItems,
124
  ];
125
  }
133
  $subItems = [
134
  [
135
  'slug' => $slug.'-log',
136
+ 'title' => __( 'View Audit Trail Log', 'wp-simple-firewall' ),
137
  'href' => $mod->getUrl_SubInsightsPage( $slug ),
138
  'active' => $this->getInav() === $slug,
139
  ],
140
  [
141
  'slug' => $slug.'-settings',
142
+ 'title' => __( 'Configuration', 'wp-simple-firewall' ),
143
  'href' => $con->getModule_AuditTrail()->getUrl_AdminPage(),
144
  ],
145
  [
157
  ];
158
 
159
  return [
160
+ 'slug' => $slug,
161
  'title' => __( 'Audit Trail', 'wp-simple-firewall' ),
162
  'img' => $this->getCon()->urls->forImage( 'bootstrap/person-lines-fill.svg' ),
163
+ 'introjs' => [
164
+ 'body' => __( "Track and review all important actions taken on your site - see the Who, What and When.", 'wp-simple-firewall' ),
165
+ ],
166
  'sub_items' => $subItems,
167
  ];
168
  }
189
  ],
190
  [
191
  'slug' => $slug.'-settings',
192
+ 'title' => sprintf( '%s: %s', __( 'Configure', 'wp-simple-firewall' ), __( 'Automatic Scans', 'wp-simple-firewall' ) ),
193
  'href' => $con->getModule_HackGuard()->getUrl_AdminPage(),
194
  ],
195
  ];
198
  'slug' => $slug,
199
  'title' => __( 'Scans', 'wp-simple-firewall' ),
200
  'img' => $this->getCon()->urls->forImage( 'bootstrap/shield-shaded.svg' ),
201
+ 'introjs' => [
202
+ 'body' => sprintf( __( "Run a %s scan at any time, or view the results from the latest scan.", 'wp-simple-firewall' ),
203
+ $this->getCon()->getHumanName() ),
204
+ ],
205
  'sub_items' => $subItems,
206
  ];
207
  }
215
  'img' => $this->getCon()->urls->forImage( 'bootstrap/search.svg' ),
216
  'id' => 'NavMenuSearch',
217
  'href' => $mod->getUrl_SubInsightsPage( 'overview' ),
218
+ 'introjs' => [
219
+ 'body' => __( 'Use Search to find any option within the entire plugin' ),
220
+ ],
221
  'data' => [
222
  'toggle' => 'modal',
223
  'target' => '#SearchDialog',
234
  'title' => __( 'Reports', 'wp-simple-firewall' ),
235
  'img' => $this->getCon()->urls->forImage( 'bootstrap/graph-up.svg' ),
236
  'href' => $mod->getUrl_SubInsightsPage( 'reports' ),
237
+ 'introjs' => [
238
+ 'body' => __( 'Reports use the built-in stats to show you how Shield is working to secure your site.' ),
239
+ ],
240
  'sub_items' => [
241
  [
242
  'slug' => 'reports-stats',
262
  'title' => __( 'Overview', 'wp-simple-firewall' ),
263
  'img' => $this->getCon()->urls->forImage( 'bootstrap/binoculars.svg' ),
264
  'href' => $mod->getUrl_SubInsightsPage( 'overview' ),
265
+ 'introjs' => [
266
+ 'body' => sprintf( __( "Review your entire %s configuration at a glance to see what's working and what's not.", 'wp-simple-firewall' ),
267
+ $this->getCon()->getHumanName() ),
268
+ ],
269
  ];
270
  }
271
 
272
+ private function configuration() :array {
273
  /** @var ModCon $mod */
274
  $mod = $this->getMod();
275
+ $slug = 'configuration';
276
 
277
  $subItems = [];
278
  foreach ( $mod->getModulesSummaryData() as $modData ) {
293
 
294
  return [
295
  'slug' => $slug,
296
+ 'title' => __( 'Configuration', 'wp-simple-firewall' ),
297
  'img' => $this->getCon()->urls->forImage( 'bootstrap/sliders.svg' ),
298
+ 'introjs' => [
299
+ 'body' => 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' ),
300
+ $this->getCon()->getHumanName() ),
301
+ ],
302
  'sub_items' => $subItems,
303
  ];
304
  }
309
  'slug' => 'integrations',
310
  'img' => $this->getCon()->urls->forImage( 'bootstrap/puzzle-fill.svg' ),
311
  'title' => __( 'Integrations', 'wp-simple-firewall' ),
312
+ 'introjs' => [
313
+ 'body' => __( "Integrate with your favourite plugins to block SPAM and manage Shield better.", 'wp-simple-firewall' ),
314
+ ],
315
  'sub_items' => [
316
  [
317
+ 'slug' => 'integrations-contact',
 
 
 
 
 
318
  'title' => __( 'Contact Form SPAM', 'wp-simple-firewall' ),
319
  'href' => $con->getModule_Integrations()->getUrl_DirectLinkToSection( 'section_spam' ),
320
  ],
321
+ [
322
+ 'slug' => 'integrations-login',
323
+ 'title' => __( 'Custom Login Forms', 'wp-simple-firewall' ),
324
+ 'href' => $con->getModule_Integrations()->getUrl_DirectLinkToSection( 'section_user_forms' ),
325
+ ],
326
  ],
327
  ];
328
  }
329
 
 
 
 
 
 
 
 
 
 
 
 
330
  private function docs() :array {
331
  /** @var ModCon $mod */
332
  $mod = $this->getMod();
358
  [
359
  'slug' => 'license-trial',
360
  'title' => __( 'Free Trial', 'wp-simple-firewall' ),
361
+ 'href' => 'https://shsec.io/shieldfreetrialinplugin',
362
+ 'target' => '_blank',
363
  ],
364
  [
365
  'slug' => 'license-features',
415
  'slug' => $slug,
416
  'title' => __( 'Tools', 'wp-simple-firewall' ),
417
  'img' => $this->getCon()->urls->forImage( 'bootstrap/tools.svg' ),
418
+ 'introjs' => [
419
+ 'body' => __( "Important security tools, such a import/export, whitelabel and admin notes.", 'wp-simple-firewall' ),
420
+ ],
421
  'sub_items' => $subItems,
422
  ];
423
  }
431
  $subItems = [
432
  [
433
  'slug' => $slug.'-log',
434
+ 'title' => __( 'View Traffic Log', 'wp-simple-firewall' ),
435
  'href' => $mod->getUrl_SubInsightsPage( $slug ),
436
  'active' => $this->getInav() === $slug,
437
  ],
438
  [
439
  'slug' => $slug.'-ratelimitsettings',
440
+ 'title' => sprintf( '%s: %s', __( 'Configure', 'wp-simple-firewall' ), __( 'Rate Limiting', 'wp-simple-firewall' ) ),
441
  'href' => $con->getModule_Traffic()->getUrl_DirectLinkToSection( 'section_traffic_limiter' ),
442
  ],
443
  [
452
  'slug' => 'traffic',
453
  'title' => __( 'Traffic', 'wp-simple-firewall' ),
454
  'img' => $this->getCon()->urls->forImage( 'bootstrap/stoplights.svg' ),
455
+ 'introjs' => [
456
+ 'body' => __( "Monitor and watch traffic as it hits your site.", 'wp-simple-firewall' ),
457
+ ],
458
  'sub_items' => $subItems,
459
  ];
460
  }
472
  ],
473
  [
474
  'slug' => 'users-secadmin',
475
+ 'title' => sprintf( '%s: %s', __( 'Configure', 'wp-simple-firewall' ), __( 'Security Admin', 'wp-simple-firewall' ) ),
476
  'href' => $con->getModule_SecAdmin()->getUrl_DirectLinkToSection( 'section_security_admin_settings' ),
477
  ],
478
  [
479
  'slug' => 'users-settings',
480
+ 'title' => sprintf( '%s: %s', __( 'Configure', 'wp-simple-firewall' ), __( 'Sessions', 'wp-simple-firewall' ) ),
481
  'href' => $con->getModule_UserManagement()
482
  ->getUrl_DirectLinkToSection( 'section_user_session_management' ),
483
  ],
484
  [
485
  'slug' => 'users-passwords',
486
+ 'title' => sprintf( '%s: %s', __( 'Configure', 'wp-simple-firewall' ), __( 'Password Policies', 'wp-simple-firewall' ) ),
487
  'href' => $con->getModule_UserManagement()->getUrl_DirectLinkToSection( 'section_passwords' ),
488
  ],
489
  [
490
  'slug' => 'users-suspend',
491
+ 'title' => sprintf( '%s: %s', __( 'Configure', 'wp-simple-firewall' ), __( 'User Suspension', 'wp-simple-firewall' ) ),
492
  'href' => $con->getModule_UserManagement()->getUrl_DirectLinkToSection( 'section_suspend' ),
493
  ],
494
  ];
497
  'slug' => 'users',
498
  'title' => __( 'Users', 'wp-simple-firewall' ),
499
  'img' => $this->getCon()->urls->forImage( 'bootstrap/person-badge.svg' ),
500
+ 'introjs' => [
501
+ 'body' => __( 'View sessions, and configure session timeouts and passwords requirements.', 'wp-simple-firewall' ),
502
+ ],
503
  'sub_items' => $subItems,
504
  ];
505
  }
506
 
507
+ private function getIntroJsTourID() :string {
508
+ return 'navigation_v1';
509
+ }
510
+
511
  private function getInav() :string {
512
  return (string)Services::Request()->query( 'inav' );
513
  }
src/lib/src/Modules/Insights/Lib/SummaryCards.php ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Insights\Lib;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Scan\Controller\{
7
+ Wcf
8
+ };
9
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
10
+
11
+ class SummaryCards {
12
+
13
+ use ModConsumer;
14
+
15
+ public function build() :array {
16
+ $cards = [];
17
+ $cards = array_merge(
18
+ $cards,
19
+ $this->getLoginSummary(),
20
+ $this->getFirewallSummary(),
21
+ $this->getIPBlockingSummary(),
22
+ $this->getSecurityAdminSummary(),
23
+ $this->getCommentSpamSummary(),
24
+ $this->getHackguardSummary(),
25
+ $this->getUserSummary(),
26
+ $this->getAuditTrailSummary(),
27
+ $this->getPluginSummary()
28
+ );
29
+
30
+ return array_map(
31
+ function ( $card ) {
32
+ $card = array_merge(
33
+ [
34
+ 'enabled' => false
35
+ ],
36
+ $card
37
+ );
38
+
39
+ if ( empty( $card[ 'icon' ] ) ) {
40
+ $card[ 'icon' ] = $card[ 'enabled' ] ?
41
+ $this->getCon()->svgs->raw( 'bootstrap/shield-fill-check.svg' )
42
+ : $this->getCon()->svgs->raw( 'bootstrap/shield-fill-exclamation.svg' );
43
+ }
44
+
45
+ return $card;
46
+ },
47
+ $cards
48
+ );
49
+ }
50
+
51
+ private function getPluginSummary() :array {
52
+ $mod = $this->getCon()->getModule_Plugin();
53
+ return [
54
+ $mod->getSlug() => [
55
+ 'title' => 'Plugin',
56
+ 'enabled' => $mod->isModuleEnabled(),
57
+ 'href' => $mod->getUrl_DirectLinkToOption( 'global_enable_plugin_features' ),
58
+ ]
59
+ ];
60
+ }
61
+
62
+ private function getCommentSpamSummary() :array {
63
+ $mod = $this->getCon()->getModule_Comments();
64
+ /** @var Modules\CommentsFilter\Options $opts */
65
+ $opts = $mod->getOptions();
66
+ return [
67
+ $mod->getSlug() => [
68
+ 'title' => 'Comment SPAM',
69
+ 'enabled' => $mod->isModuleEnabled()
70
+ && $opts->isEnabledAntiBot(),
71
+ 'href' => $mod->getUrl_AdminPage(),
72
+ ]
73
+ ];
74
+ }
75
+
76
+ private function getAuditTrailSummary() :array {
77
+ $mod = $this->getCon()->getModule_AuditTrail();
78
+ return [
79
+ $mod->getSlug() => [
80
+ 'title' => "Audit Trail",
81
+ 'enabled' => $mod->isModuleEnabled(),
82
+ 'href' => $mod->getUrl_AdminPage(),
83
+ ]
84
+ ];
85
+ }
86
+
87
+ private function getUserSummary() :array {
88
+ $mod = $this->getCon()->getModule_UserManagement();
89
+ /** @var Modules\UserManagement\Options $opts */
90
+ $opts = $mod->getOptions();
91
+ return [
92
+ $mod->getSlug() => [
93
+ 'title' => "'Pwned' Passwords",
94
+ 'enabled' => $mod->isModuleEnabled()
95
+ && $opts->isPasswordPoliciesEnabled()
96
+ && $opts->isPassPreventPwned(),
97
+ 'href' => $mod->getUrl_DirectLinkToOption( 'enable_password_policies' ),
98
+ ]
99
+ ];
100
+ }
101
+
102
+ private function getHackguardSummary() :array {
103
+ $mod = $this->getCon()->getModule_HackGuard();
104
+ return [
105
+ $mod->getSlug() => [
106
+ 'title' => 'Scanners',
107
+ 'enabled' => $mod->isModuleEnabled(),
108
+ 'href' => $mod->getUrl_DirectLinkToOption( 'enable_hack_protect' ),
109
+ ],
110
+ 'core_files' => [
111
+ 'title' => 'Core File Scan',
112
+ 'enabled' => $mod->isModuleEnabled()
113
+ && $mod->getScanCon( Wcf::SCAN_SLUG )->isEnabled(),
114
+ 'href' => $mod->getUrl_DirectLinkToOption( 'enable_core_file_integrity_scan' ),
115
+ ]
116
+ ];
117
+ }
118
+
119
+ private function getIPBlockingSummary() :array {
120
+ $mod = $this->getCon()->getModule_IPs();
121
+ /** @var Modules\IPs\Options $opts */
122
+ $opts = $mod->getOptions();
123
+ return [
124
+ $mod->getSlug() => [
125
+ 'title' => 'Auto IP Block',
126
+ 'enabled' => $mod->isModuleEnabled()
127
+ && ( $opts->getOffenseLimit() > 0 ),
128
+ 'href' => $mod->getUrl_AdminPage(),
129
+ ]
130
+ ];
131
+ }
132
+
133
+ private function getSecurityAdminSummary() :array {
134
+ $mod = $this->getCon()->getModule_SecAdmin();
135
+ return [
136
+ $mod->getSlug() => [
137
+ 'title' => $mod->getMainFeatureName(),
138
+ 'enabled' => $mod->isModuleEnabled()
139
+ && $mod->getSecurityAdminController()->isEnabledSecAdmin(),
140
+ 'href' => $mod->getUrl_AdminPage(),
141
+ ]
142
+ ];
143
+ }
144
+
145
+ private function getLoginSummary() :array {
146
+ $mod = $this->getCon()->getModule_LoginGuard();
147
+ /** @var Modules\LoginGuard\Options $opts */
148
+ $opts = $mod->getOptions();
149
+ return [
150
+ $mod->getSlug() => [
151
+ 'title' => 'Login',
152
+ 'enabled' => $mod->isModuleEnabled() && $opts->isEnabledAntiBot(),
153
+ 'href' => $mod->getUrl_AdminPage(),
154
+ ]
155
+ ];
156
+ }
157
+
158
+ private function getFirewallSummary() :array {
159
+ $mod = $this->getCon()->getModule_Firewall();
160
+ /** @var Modules\LoginGuard\Options $opts */
161
+ $opts = $mod->getOptions();
162
+ return [
163
+ $mod->getSlug() => [
164
+ 'title' => 'Firewall',
165
+ 'enabled' => $mod->isModuleEnabled(),
166
+ 'href' => $mod->getUrl_DirectLinkToOption( 'enable_firewall' ),
167
+ ]
168
+ ];
169
+ }
170
+
171
+ /**
172
+ * @param Modules\Base\ModCon $mod
173
+ * @return array[]
174
+ */
175
+ private function getBasicModSummary( $mod ) :array {
176
+ return [
177
+ $mod->getSlug() => [
178
+ 'title' => $mod->getMainFeatureName(),
179
+ 'enabled' => $mod->isModuleEnabled(),
180
+ 'href' => $mod->getUrl_AdminPage(),
181
+ ]
182
+ ];
183
+ }
184
+ }
src/lib/src/Modules/Insights/ModCon.php CHANGED
@@ -17,21 +17,25 @@ class ModCon extends BaseShield\ModCon {
17
  }
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
  }
@@ -108,7 +112,7 @@ class ModCon extends BaseShield\ModCon {
108
  $inav = 'overview';
109
  }
110
 
111
- if ( $con->getIsPage_PluginAdmin() && !empty( $inav ) ) {
112
  switch ( $inav ) {
113
 
114
  case 'importexport':
@@ -136,6 +140,11 @@ class ModCon extends BaseShield\ModCon {
136
  ];
137
  break;
138
 
 
 
 
 
 
139
  case 'notes':
140
  case 'scans_results':
141
  case 'scans_run':
17
  }
18
 
19
  protected function onModulesLoaded() {
20
+ $this->handleCustomRedirection();
 
21
  }
22
 
23
+ private function handleCustomRedirection() {
24
+ $con = $this->getCon();
25
+ if ( !Services::WpGeneral()->isAjax() && is_admin() && !$con->isModulePage() ) {
26
+ if ( $con->getModule_Plugin()->getActivateLength() < 5 ) {
27
+ Services::Response()->redirect( $con->getModule_Plugin()->getUrl_Wizard( 'welcome' ) );
28
+ }
29
+ elseif ( $this->isThisModAdminPage() && empty( Services::Request()->query( 'inav' ) ) ) {
30
+ Services::Response()->redirect( $con->getPluginUrl_DashboardHome() );
31
+ }
32
  }
33
  }
34
 
35
  private function maybeRedirectToAdmin() {
36
  $con = $this->getCon();
37
  $activeFor = $con->getModule_Plugin()->getActivateLength();
38
+ if ( !Services::WpGeneral()->isAjax() && $activeFor < 4 ) {
39
  Services::Response()->redirect( $this->getCon()->getPluginUrl_DashboardHome() );
40
  }
41
  }
112
  $inav = 'overview';
113
  }
114
 
115
+ if ( $con->getIsPage_PluginAdmin() ) {
116
  switch ( $inav ) {
117
 
118
  case 'importexport':
140
  ];
141
  break;
142
 
143
+ case 'wizard':
144
+ $enq[ Enqueue::JS ][] = 'shield/wizard';
145
+ $enq[ Enqueue::CSS ][] = 'shield/wizard';
146
+ break;
147
+
148
  case 'notes':
149
  case 'scans_results':
150
  case 'scans_run':
src/lib/src/Modules/Insights/UI.php CHANGED
@@ -4,7 +4,6 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Insights;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
7
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\Insights\Lib\OverviewCards;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Insights\AdminNotes;
9
  use FernleafSystems\Wordpress\Plugin\Shield\Utilities\Changelog\Retrieve;
10
  use FernleafSystems\Wordpress\Services\Services;
@@ -15,12 +14,14 @@ class UI extends BaseShield\UI {
15
  $con = $this->getCon();
16
  return [
17
  'content' => [
18
- 'tab_updates' => $this->renderTabUpdates(),
19
- 'tab_freetrial' => $this->renderFreeTrial(),
20
  ],
21
  'flags' => [
22
  'is_pro' => $con->isPremiumActive(),
23
  ],
 
 
 
24
  'strings' => [
25
  'tab_freetrial' => __( 'Free Trial', 'wp-simple-firewall' ),
26
  'tab_updates' => __( 'Updates and Changes', 'wp-simple-firewall' ),
@@ -31,9 +32,12 @@ class UI extends BaseShield\UI {
31
  private function buildInsightsVars_Overview() :array {
32
  return [
33
  'vars' => [
34
- 'overview_cards' => ( new OverviewCards() )
35
  ->setMod( $this->getMod() )
36
  ->buildForShuffle(),
 
 
 
37
  ],
38
  'strings' => [
39
  'click_clear_filter' => __( 'Click To Filter By Security Area or Status', 'wp-simple-firewall' ),
@@ -97,14 +101,6 @@ class UI extends BaseShield\UI {
97
  $data = $this->buildInsightsVars_Docs();
98
  break;
99
 
100
- case 'free_trial':
101
- $data = [
102
- 'content' => [
103
- 'free_trial' => $this->renderFreeTrial()
104
- ]
105
- ];
106
- break;
107
-
108
  case 'importexport':
109
  $data = $modPlugin->getImpExpController()->buildInsightsVars();
110
  break;
@@ -164,6 +160,21 @@ class UI extends BaseShield\UI {
164
  case 'index':
165
  $data = $this->buildInsightsVars_Overview();
166
  break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  default:
168
  throw new \Exception( 'Not available' );
169
  }
@@ -186,6 +197,7 @@ class UI extends BaseShield\UI {
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(
@@ -198,12 +210,10 @@ class UI extends BaseShield\UI {
198
  $pageTitle = $availablePages[ $inav ];
199
  if ( !empty( $subNavSection ) ) {
200
  $pageTitle = sprintf( '%s: %s',
201
- __( 'Settings', 'wp-simple-firewall' ), $modsToSearch[ $subNavSection ][ 'name' ] );
202
  }
203
 
204
- /** @var Shield\Modules\SecurityAdmin\Options $secAdminOpts */
205
- $secAdminOpts = $this->getCon()->getModule_SecAdmin()->getOptions();
206
- if ( $secAdminOpts->isEnabledWhitelabel() ) {
207
  $dashboardLogo = ( new Shield\Modules\SecurityAdmin\Lib\WhiteLabel\BuildOptions() )
208
  ->setMod( $this->getCon()->getModule_SecAdmin() )
209
  ->build()[ 'url_login2fa_logourl' ];
@@ -255,6 +265,10 @@ class UI extends BaseShield\UI {
255
  );
256
  }
257
 
 
 
 
 
258
  private function renderFreeTrial() :string {
259
  $user = Services::WpUsers()->getCurrentWpUser();
260
  return $this->getMod()
@@ -326,7 +340,7 @@ class UI extends BaseShield\UI {
326
  'flags' => [
327
  'show_promo' => $con->isModulePage()
328
  && !$con->isPremiumActive()
329
- && ( !in_array( $nav, [ 'scans_results', 'scans_run' ] ) ),
330
  ],
331
  'hrefs' => [
332
  'go_pro' => 'https://shsec.io/shieldgoprofeature',
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
 
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Insights\AdminNotes;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Utilities\Changelog\Retrieve;
9
  use FernleafSystems\Wordpress\Services\Services;
14
  $con = $this->getCon();
15
  return [
16
  'content' => [
17
+ 'tab_updates' => $this->renderTabUpdates(),
 
18
  ],
19
  'flags' => [
20
  'is_pro' => $con->isPremiumActive(),
21
  ],
22
+ 'hrefs' => [
23
+ 'free_trial' => 'https://shsec.io/shieldfreetrialinplugin',
24
+ ],
25
  'strings' => [
26
  'tab_freetrial' => __( 'Free Trial', 'wp-simple-firewall' ),
27
  'tab_updates' => __( 'Updates and Changes', 'wp-simple-firewall' ),
32
  private function buildInsightsVars_Overview() :array {
33
  return [
34
  'vars' => [
35
+ 'overview_cards' => ( new Lib\OverviewCards() )
36
  ->setMod( $this->getMod() )
37
  ->buildForShuffle(),
38
+ 'summary_cards' => ( new Lib\SummaryCards() )
39
+ ->setMod( $this->getMod() )
40
+ ->build(),
41
  ],
42
  'strings' => [
43
  'click_clear_filter' => __( 'Click To Filter By Security Area or Status', 'wp-simple-firewall' ),
101
  $data = $this->buildInsightsVars_Docs();
102
  break;
103
 
 
 
 
 
 
 
 
 
104
  case 'importexport':
105
  $data = $modPlugin->getImpExpController()->buildInsightsVars();
106
  break;
160
  case 'index':
161
  $data = $this->buildInsightsVars_Overview();
162
  break;
163
+
164
+ case 'wizard':
165
+ $wiz = $con->getModule_Plugin()->getWizardHandler();
166
+ if ( $wiz instanceof \ICWP_WPSF_Wizard_Base ) {
167
+ $data = [
168
+ 'content' => [
169
+ 'wizard' => $wiz->setCurrentWizard( $req->query( 'wizard' ) )
170
+ ->renderWizard()
171
+ ],
172
+ 'flags' => [
173
+ 'show_sidebar_nav' => 0
174
+ ],
175
+ ];
176
+ }
177
+ break;
178
  default:
179
  throw new \Exception( 'Not available' );
180
  }
197
  'reports' => __( 'Reports', 'wp-simple-firewall' ),
198
  'debug' => __( 'Debug', 'wp-simple-firewall' ),
199
  'free_trial' => __( 'Free Trial', 'wp-simple-firewall' ),
200
+ 'wizard' => __( 'Wizard', 'wp-simple-firewall' ),
201
  ];
202
 
203
  $modsToSearch = array_filter(
210
  $pageTitle = $availablePages[ $inav ];
211
  if ( !empty( $subNavSection ) ) {
212
  $pageTitle = sprintf( '%s: %s',
213
+ __( 'Configuration', 'wp-simple-firewall' ), $modsToSearch[ $subNavSection ][ 'name' ] );
214
  }
215
 
216
+ if ( $this->getCon()->getModule_SecAdmin()->getWhiteLabelController()->isEnabled() ) {
 
 
217
  $dashboardLogo = ( new Shield\Modules\SecurityAdmin\Lib\WhiteLabel\BuildOptions() )
218
  ->setMod( $this->getCon()->getModule_SecAdmin() )
219
  ->build()[ 'url_login2fa_logourl' ];
265
  );
266
  }
267
 
268
+ /**
269
+ * @return string
270
+ * @deprecated 11.2
271
+ */
272
  private function renderFreeTrial() :string {
273
  $user = Services::WpUsers()->getCurrentWpUser();
274
  return $this->getMod()
340
  'flags' => [
341
  'show_promo' => $con->isModulePage()
342
  && !$con->isPremiumActive()
343
+ && ( !in_array( $nav, [ 'scans_results', 'scans_run', 'wizard' ] ) ),
344
  ],
345
  'hrefs' => [
346
  'go_pro' => 'https://shsec.io/shieldgoprofeature',
src/lib/src/Modules/Integrations/Lib/Bots/Common/BaseBotDetectionController.php ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Common;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
6
+
7
+ abstract class BaseBotDetectionController extends ExecOnceModConsumer {
8
+
9
+ protected function canRun() :bool {
10
+ return $this->isEnabled();
11
+ }
12
+
13
+ protected function run() {
14
+ array_map(
15
+ function ( $provider ) {
16
+ $provider->execute();
17
+ },
18
+ $this->getInstalledProviders()
19
+ );
20
+ }
21
+
22
+ /**
23
+ * Inserts the ModCon;
24
+ * @return BaseHandler[]
25
+ */
26
+ public function getInstalledProviders() :array {
27
+ return array_map(
28
+ function ( $provider ) {
29
+ return $provider->setMod( $this->getMod() );
30
+ },
31
+ array_filter(
32
+ $this->enumProviders(),
33
+ function ( $provider ) {
34
+ return $provider::IsProviderInstalled();
35
+ }
36
+ )
37
+ );
38
+ }
39
+
40
+ /**
41
+ * @return BaseHandler[]
42
+ */
43
+ public function enumProviders() :array {
44
+ return [];
45
+ }
46
+
47
+ protected function isEnabled() :bool {
48
+ return false;
49
+ }
50
+ }
src/lib/src/Modules/Integrations/Lib/Bots/Common/BaseHandler.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Common;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
+
8
+ abstract class BaseHandler extends ExecOnceModConsumer {
9
+
10
+ const SLUG = '';
11
+
12
+ protected function canRun() :bool {
13
+ return ( $this->getCon()->isPremiumActive() || !$this->isProOnly() )
14
+ && $this->isEnabled() && static::IsProviderInstalled();
15
+ }
16
+
17
+ protected function isBot() :bool {
18
+ return $this->getCon()
19
+ ->getModule_IPs()
20
+ ->getBotSignalsController()
21
+ ->isBot( Services::IP()->getRequestIp() );
22
+ }
23
+
24
+ public function isEnabled() :bool {
25
+ return false;
26
+ }
27
+
28
+ public static function IsProviderInstalled() :bool {
29
+ return false;
30
+ }
31
+
32
+ protected function getProviderName() :string {
33
+ return '';
34
+ }
35
+
36
+ public function getHandlerSlug() :string {
37
+ try {
38
+ $slug = strtolower( ( new \ReflectionClass( $this ) )->getShortName() );
39
+ }
40
+ catch ( \Exception $e ) {
41
+ $slug = '';
42
+ }
43
+ return $slug;
44
+ }
45
+
46
+ protected function isProOnly() :bool {
47
+ return true;
48
+ }
49
+ }
src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/Base.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Spam\Handlers;
4
+
5
+ use FernleafSystems\Utilities\Logic\ExecOnce;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Common\BaseHandler;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
8
+ use FernleafSystems\Wordpress\Services\Services;
9
+
10
+ abstract class Base extends BaseHandler {
11
+
12
+ public function isSpam() :bool {
13
+ $isSpam = $this->isBot();
14
+ $this->getCon()->fireEvent(
15
+ sprintf( 'spam_form_%s', $isSpam ? 'fail' : 'pass' ),
16
+ [
17
+ 'audit' => [
18
+ 'form_provider' => $this->getProviderName(),
19
+ ]
20
+ ]
21
+ );
22
+ return $isSpam;
23
+ }
24
+
25
+ protected function isSpam_Human() :bool {
26
+ return false;
27
+ }
28
+
29
+ public function isEnabled() :bool {
30
+ return in_array( $this->getHandlerSlug(), $this->getOptions()->getOpt( 'form_spam_providers', [] ) );
31
+ }
32
+ }
src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/ContactForm7.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Spam\Handlers;
4
+
5
+ class ContactForm7 extends Base {
6
+
7
+ protected function run() {
8
+ add_filter( 'wpcf7_spam', function ( $wasSpam, $submission ) {
9
+ return $wasSpam || $this->isSpam();
10
+ }, 1000, 2 );
11
+ }
12
+
13
+ protected function getProviderName() :string {
14
+ return 'Contact Form 7';
15
+ }
16
+
17
+ public static function IsProviderInstalled() :bool {
18
+ return defined( 'WPCF7_TEXT_DOMAIN' ) && WPCF7_TEXT_DOMAIN === 'contact-form-7';
19
+ }
20
+ }
src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/ElementorPro.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Spam\Handlers;
4
+
5
+ class ElementorPro extends Base {
6
+
7
+ protected function run() {
8
+ add_action( 'elementor_pro/forms/validation', function ( $form, $ajax_handler ) {
9
+ /** @var \ElementorPro\Modules\Forms\Classes\Ajax_Handler $ajax_handler */
10
+ if ( empty( $ajax_handler->errors ) && $this->isSpam() ) {
11
+ $msg = sprintf( __( "This appears to be spam - failed %s AntiBot protection checks.", 'wp-simple-firewall' ),
12
+ $this->getCon()->getHumanName() );
13
+ $ajax_handler->add_error( 'shield-antibot', $msg );
14
+ $ajax_handler->add_error_message( $msg );
15
+ }
16
+ }, 1000, 2 );
17
+ }
18
+
19
+ protected function getProviderName() :string {
20
+ return 'Elementor Pro';
21
+ }
22
+
23
+ public static function IsProviderInstalled() :bool {
24
+ return defined( 'ELEMENTOR_PRO_VERSION' ) && @function_exists( 'elementor_pro_load_plugin' );
25
+ }
26
+ }
src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/FluentForms.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Spam\Handlers;
4
+
5
+ /**
6
+ * This form only provides a filter on the "Akismet" spam result, not a general spam result.
7
+ *
8
+ * Luckily the error message within the plugin is non-Akismet specific.
9
+ *
10
+ * Class FluentForms
11
+ * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Spam\Handlers
12
+ */
13
+ class FluentForms extends Base {
14
+
15
+ protected function run() {
16
+ add_filter( 'fluentform_akismet_spam_result', function ( $wasSpam ) {
17
+ return $wasSpam || $this->isSpam();
18
+ }, 1000 );
19
+ }
20
+
21
+ protected function getProviderName() :string {
22
+ return 'Fluent Forms';
23
+ }
24
+
25
+ public static function IsProviderInstalled() :bool {
26
+ return defined( 'FLUENTFORM' ) && @class_exists( '\FluentForm\Framework\Foundation\Bootstrap' );
27
+ }
28
+ }
src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/FormidableForms.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Spam\Handlers;
4
+
5
+ class FormidableForms extends Base {
6
+
7
+ protected function run() {
8
+ add_filter( 'frm_validate_entry', function ( $errors ) {
9
+ if ( !is_array( $errors ) || empty( $errors[ 'spam' ] ) ) {
10
+ if ( $this->isSpam() ) {
11
+ if ( !is_array( $errors ) ) {
12
+ $errors = [];
13
+ }
14
+ // string taken from Formidable forms FrmEntryValidate.php
15
+ $errors[ 'spam' ] = __( 'Your entry appears to be spam!', 'formidable' );
16
+ }
17
+ }
18
+ return $errors;
19
+ }, 1000 );
20
+ }
21
+
22
+ protected function getProviderName() :string {
23
+ return 'Formidable Forms';
24
+ }
25
+
26
+ public static function IsProviderInstalled() :bool {
27
+ return function_exists( 'load_formidable_forms' ) && @class_exists( '\FrmHooksController' );
28
+ }
29
+ }
src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/Forminator.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Spam\Handlers;
4
+
5
+ class Forminator extends Base {
6
+
7
+ protected function run() {
8
+ add_filter( 'forminator_spam_protection', function ( $wasSpam ) {
9
+ return $wasSpam || $this->isSpam();
10
+ }, 1000 );
11
+ }
12
+
13
+ protected function getProviderName() :string {
14
+ return 'Forminator';
15
+ }
16
+
17
+ public static function IsProviderInstalled() :bool {
18
+ return defined( 'FORMINATOR_VERSION' ) && @class_exists( '\Forminator' );
19
+ }
20
+ }
src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/GravityForms.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Spam\Handlers;
4
+
5
+ class GravityForms extends Base {
6
+
7
+ protected function run() {
8
+ add_filter( 'gform_entry_is_spam', function ( $wasSpam ) {
9
+ return $wasSpam || $this->isSpam();
10
+ }, 1000 );
11
+ }
12
+
13
+ protected function getProviderName() :string {
14
+ return 'Gravity Forms';
15
+ }
16
+
17
+ public static function IsProviderInstalled() :bool {
18
+ return @class_exists( '\GFForms' )
19
+ && isset( \GFForms::$version )
20
+ && version_compare( \GFForms::$version, '2.4.17', '>=' );
21
+ }
22
+ }
src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/Groundhogg.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Spam\Handlers;
4
+
5
+ class Groundhogg extends Base {
6
+
7
+ protected function run() {
8
+ add_filter( 'groundhogg/form/submission_handler/is_spam', function ( $wasSpam ) {
9
+ return $wasSpam || $this->isSpam();
10
+ }, 1000 );
11
+ }
12
+
13
+ protected function getProviderName() :string {
14
+ return 'Groundhogg';
15
+ }
16
+
17
+ public static function IsProviderInstalled() :bool {
18
+ return defined( 'GROUNDHOGG_TEXT_DOMAIN' ) && defined( 'GROUNDHOGG_VERSION' )
19
+ && version_compare( GROUNDHOGG_VERSION, '2.4.5.5', '>=' );
20
+ }
21
+ }
src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/Helpers/NinjaForms_ShieldSpamAction.php ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Spam\Handlers\Helpers;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Spam\Handlers\NinjaForms;
6
+
7
+ final class NinjaForms_ShieldSpamAction extends \NF_Abstracts_Action {
8
+
9
+ /**
10
+ * @var string
11
+ */
12
+ protected $_name = 'shieldantibot';
13
+
14
+ /**
15
+ * @var NinjaForms
16
+ */
17
+ private $shieldNinjaFormsHandler;
18
+
19
+ /**
20
+ * @var array
21
+ */
22
+ protected $_tags = [ 'spam', 'filtering', 'shield' ];
23
+
24
+ public function __construct() {
25
+ parent::__construct();
26
+ $this->_nicename = esc_html__( 'Shield Anti-Spam', 'ninja-forms' );
27
+ }
28
+
29
+ /**
30
+ * @param NinjaForms $handler
31
+ * @return $this
32
+ */
33
+ public function setHandler( NinjaForms $handler ) {
34
+ $this->shieldNinjaFormsHandler = $handler;
35
+ return $this;
36
+ }
37
+
38
+ /**
39
+ * @inheritDoc
40
+ */
41
+ public function process( $action_settings, $form_id, $data ) {
42
+ if ( $this->shieldNinjaFormsHandler->isSpam() ) {
43
+ $data[ 'errors' ][ 'form' ][ 'spam' ] = esc_html__( 'There was an error trying to send your message. Please try again later', 'ninja-forms' );
44
+ }
45
+ return $data;
46
+ }
47
+ }
src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/KaliForms.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Spam\Handlers;
4
+
5
+ class KaliForms extends Base {
6
+
7
+ protected function run() {
8
+ add_filter( 'kaliforms_before_form_process', function ( $data ) {
9
+ if ( is_array( $data ) && empty( $data[ 'error_bag' ] ) && $this->isSpam() ) {
10
+ $data[ 'admin_stop_execution' ] = true;
11
+ $data[ 'admin_stop_reason' ] = __( 'Your entry appears to be spam!', 'wp-simple-firewall' );
12
+ $data[ 'error_bag' ] = [
13
+ __( 'SPAM Bot detected.', 'wp-simple-firewall' )
14
+ ];
15
+ }
16
+ return $data;
17
+ }, 1000 );
18
+ }
19
+
20
+ protected function getProviderName() :string {
21
+ return 'Kali Forms';
22
+ }
23
+
24
+ public static function IsProviderInstalled() :bool {
25
+ return defined( 'KALIFORMS_PLUGIN_FILE' ) && @class_exists( '\KaliForms\Inc\KaliForms' );
26
+ }
27
+ }
src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/NinjaForms.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Spam\Handlers;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Spam\Handlers\Helpers\NinjaForms_ShieldSpamAction;
6
+
7
+ /**
8
+ * A rather convoluted way to integrate. First you must add your custom "action" to the list
9
+ * of actions to be executed on a submission.
10
+ *
11
+ * Then you must create a Custom Action class which will handle the action and add it to the
12
+ * registered action.
13
+ *
14
+ * Unfortunately the action register is executed early and so hooking to Init breaks it.
15
+ *
16
+ * Class NinjaForms
17
+ * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Spam\Handlers
18
+ */
19
+ class NinjaForms extends Base {
20
+
21
+ protected function run() {
22
+
23
+ add_filter( 'ninja_forms_register_actions', function ( $actions ) {
24
+ $actions[ 'shieldantibot' ] = ( new NinjaForms_ShieldSpamAction() )
25
+ ->setHandler( $this );
26
+ return $actions;
27
+ }, 1000 );
28
+
29
+ add_filter( 'ninja_forms_submission_actions', function ( $actions ) {
30
+ $actions[] = [
31
+ 'id' => 'shieldantibot',
32
+ 'settings' => [
33
+ 'active' => true,
34
+ 'type' => 'shieldantibot',
35
+ ]
36
+ ];
37
+ return $actions;
38
+ }, 1000 );
39
+ }
40
+
41
+ protected function getProviderName() :string {
42
+ return 'Ninja Forms';
43
+ }
44
+
45
+ public static function IsProviderInstalled() :bool {
46
+ return @class_exists( '\Ninja_Forms' );
47
+ }
48
+ }
src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/WPForms.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Spam\Handlers;
4
+
5
+ class WPForms extends Base {
6
+
7
+ private $workingFormID = null;
8
+
9
+ protected function run() {
10
+ add_filter( 'wpforms_process_before_form_data',
11
+ function ( $formData, $formEntry ) {
12
+ $this->workingFormID = absint( $formEntry[ 'id' ] );
13
+ return $formData;
14
+ },
15
+ 1000, 2
16
+ );
17
+
18
+ add_filter( 'wpforms_process_initial_errors', function ( $errors, $formData ) {
19
+
20
+ if ( empty( $errors[ $this->workingFormID ] ) && $this->isSpam() ) {
21
+ $errors[ $this->workingFormID ] = [
22
+ 'header' => __( 'Shield detected this as a SPAM Bot submission.' ),
23
+ ];
24
+ }
25
+
26
+ return $errors;
27
+ }, 1000, 2 );
28
+ }
29
+
30
+ protected function getProviderName() :string {
31
+ return 'WP Forms';
32
+ }
33
+
34
+ public static function IsProviderInstalled() :bool {
35
+ return defined( 'WPFORMS_VERSION' ) && function_exists( 'wpforms' );
36
+ }
37
+ }
src/lib/src/Modules/Integrations/Lib/Bots/Spam/Handlers/WpForo.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Spam\Handlers;
4
+
5
+ class WpForo extends Base {
6
+
7
+ protected function run() {
8
+ foreach ( $this->getFiltersToMonitor() as $filter ) {
9
+ add_filter( $filter, function ( array $args = [] ) {
10
+
11
+ $status = $args[ 'status' ] ?? null;
12
+ if ( $status !== 1 && $this->isSpam() ) {
13
+ if ( !empty( WPF()->current_userid ) ) {
14
+ WPF()->moderation->ban_for_spam( WPF()->current_userid );
15
+ }
16
+ $args[ 'status' ] = 1; // 1 signifies not approved
17
+ }
18
+
19
+ return $args;
20
+ }, 1000 );
21
+ }
22
+ }
23
+
24
+ private function getFiltersToMonitor() :array {
25
+ return [
26
+ 'wpforo_add_topic_data_filter',
27
+ 'wpforo_edit_topic_data_filter',
28
+ 'wpforo_add_post_data_filter',
29
+ 'wpforo_edit_post_data_filter',
30
+ ];
31
+ }
32
+
33
+ protected function getProviderName() :string {
34
+ return 'wpForo';
35
+ }
36
+
37
+ public static function IsProviderInstalled() :bool {
38
+ return function_exists( 'WPF' ) && @class_exists( 'wpForo' ) && !empty( WPF()->tools_antispam[ 'spam_filter' ] );
39
+ }
40
+ }
src/lib/src/Modules/Integrations/Lib/Bots/Spam/SpamController.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Spam;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\Common\BaseBotDetectionController;
6
+
7
+ class SpamController extends BaseBotDetectionController {
8
+
9
+ protected function isEnabled() :bool {
10
+ return !empty( $this->getOptions()->getOpt( 'form_spam_providers' ) );
11
+ }
12
+
13
+ /**
14
+ * @return Handlers\Base[]
15
+ */
16
+ public function enumProviders() :array {
17
+ return [
18
+ new Handlers\ContactForm7(),
19
+ new Handlers\ElementorPro(),
20
+ new Handlers\FormidableForms(),
21
+ new Handlers\FluentForms(),
22
+ new Handlers\Forminator(),
23
+ new Handlers\GravityForms(),
24
+ new Handlers\KaliForms(),
25
+ new Handlers\NinjaForms(),
26
+ new Handlers\WPForms(),
27
+ new Handlers\WpForo(),
28
+ ];
29
+ }
30
+ }
src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/Base.php ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms\Handlers;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
7
+
8
+ abstract class Base extends Integrations\Lib\Bots\Common\BaseHandler {
9
+
10
+ /**
11
+ * @var string
12
+ */
13
+ private $auditAction;
14
+
15
+ /**
16
+ * @var string
17
+ */
18
+ private $auditUser;
19
+
20
+ private static $isBot = null;
21
+
22
+ protected function run() {
23
+ /** @var LoginGuard\Options $opts */
24
+ $opts = $this->getCon()->getModule_LoginGuard()->getOptions();
25
+ if ( $opts->isProtectLogin() ) {
26
+ $this->login();
27
+ }
28
+ if ( $opts->isProtectRegister() ) {
29
+ $this->register();
30
+ }
31
+ if ( $opts->isProtectLostPassword() ) {
32
+ $this->lostpassword();
33
+ }
34
+ $this->checkout();
35
+ }
36
+
37
+ protected function login() {
38
+ }
39
+
40
+ protected function register() {
41
+ }
42
+
43
+ protected function lostpassword() {
44
+ }
45
+
46
+ protected function checkout() {
47
+ }
48
+
49
+ public function getAuditAction() :string {
50
+ return sprintf( '%s-%s', $this->getHandlerSlug(), empty( $this->auditAction ) ? 'unknown' : $this->auditAction );
51
+ }
52
+
53
+ public function getAuditUser() :string {
54
+ return empty( $this->auditUser ) ? 'unknown' : $this->auditUser;
55
+ }
56
+
57
+ /**
58
+ * @param string $action
59
+ * @return $this
60
+ */
61
+ protected function setAuditAction( string $action ) {
62
+ $this->auditAction = $action;
63
+ return $this;
64
+ }
65
+
66
+ /**
67
+ * @param string $user
68
+ * @return $this
69
+ */
70
+ protected function setAuditUser( string $user ) {
71
+ $this->auditUser = sanitize_user( $user );
72
+ return $this;
73
+ }
74
+
75
+ public function checkIsBot() :bool {
76
+ if ( is_null( self::$isBot ) ) {
77
+ self::$isBot = $this->isBot();
78
+ $this->getCon()->fireEvent(
79
+ sprintf( 'user_form_bot_%s', self::$isBot ? 'fail' : 'pass' ),
80
+ [
81
+ 'audit' => [
82
+ 'form_provider' => $this->getProviderName(),
83
+ 'action' => $this->getAuditAction(),
84
+ 'username' => $this->getAuditUser(),
85
+ ]
86
+ ]
87
+ );
88
+ }
89
+ return self::$isBot;
90
+ }
91
+
92
+ public function isEnabled() :bool {
93
+ /** @var Integrations\Options $opts */
94
+ $opts = $this->getOptions();
95
+ return in_array( $this->getHandlerSlug(), $opts->getUserFormProviders() );
96
+ }
97
+
98
+ protected function getErrorMessage() :string {
99
+ return sprintf( __( '%s Bot Check Failed.', 'wp-simple-firewall' ), $this->getCon()->getHumanName() );
100
+ }
101
+ }
src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/Buddypress.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms\Handlers;
4
+
5
+ /**
6
+ * Class Buddypress
7
+ * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms\Handlers
8
+ */
9
+ class Buddypress extends Base {
10
+
11
+ protected function register() {
12
+ add_action( 'bp_signup_validate', [ $this, 'checkRegister_BP' ], 10 );
13
+ }
14
+
15
+ public function checkRegister_BP() {
16
+ if ( $this->setAuditAction( 'register' )->checkIsBot() ) {
17
+ wp_die( $this->getErrorMessage() );
18
+ }
19
+ }
20
+
21
+ protected function getProviderName() :string {
22
+ return 'BuddyPress';
23
+ }
24
+
25
+ public static function IsProviderInstalled() :bool {
26
+ return @class_exists( 'BuddyPress' );
27
+ }
28
+ }
src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/EasyDigitalDownloads.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms\Handlers;
4
+
5
+ /**
6
+ * Class EasyDigitalDownloads
7
+ * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms\Handlers
8
+ */
9
+ class EasyDigitalDownloads extends Base {
10
+
11
+ protected function register() {
12
+ add_action( 'edd_process_register_form', [ $this, 'checkRegister_EDD' ], 10 );
13
+ }
14
+
15
+ public function checkRegister_EDD() {
16
+ if ( $this->setAuditAction( 'register' )->checkIsBot() ) {
17
+ edd_set_error( $this->getCon()->prefix( rand() ), $this->getErrorMessage() );
18
+ }
19
+ }
20
+
21
+ protected function getProviderName() :string {
22
+ return 'Easy Digital Downloads';
23
+ }
24
+
25
+ public static function IsProviderInstalled() :bool {
26
+ return function_exists( 'edd_set_error' ) && @class_exists( 'Easy_Digital_Downloads' );
27
+ }
28
+ }
src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/LearnPress.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms\Handlers;
4
+
5
+ /**
6
+ * Class LearnPress
7
+ * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms\Handlers
8
+ */
9
+ class LearnPress extends Base {
10
+
11
+ protected function login() {
12
+ add_filter( 'learn-press/login-validate-field', [ $this, 'checkLogin_LP' ], 100 );
13
+ }
14
+
15
+ protected function register() {
16
+ add_filter( 'learn-press/register-validate-field', [ $this, 'checkRegister_LP' ], 100, 1 );
17
+ }
18
+
19
+ /**
20
+ * @param string|\WP_Error $maybeError
21
+ * @return string|\WP_Error
22
+ */
23
+ public function checkLogin_LP( $maybeError ) {
24
+ if ( !is_wp_error( $maybeError ) && $this->setAuditAction( 'login' )->checkIsBot() ) {
25
+ $maybeError = new \WP_Error( 'shield-fail-login', $this->getErrorMessage() );
26
+ }
27
+ return $maybeError;
28
+ }
29
+
30
+ /**
31
+ * @param string|\WP_Error $maybeError
32
+ * @return string|\WP_Error
33
+ */
34
+ public function checkRegister_LP( $maybeError ) {
35
+ if ( !is_wp_error( $maybeError ) && $this->setAuditAction( 'register' )->checkIsBot() ) {
36
+ $maybeError = new \WP_Error( 'shield-fail-register', $this->getErrorMessage() );
37
+ }
38
+ return $maybeError;
39
+ }
40
+
41
+ protected function getProviderName() :string {
42
+ return 'LearnPress';
43
+ }
44
+
45
+ public static function IsProviderInstalled() :bool {
46
+ return @class_exists( 'LearnPress' );
47
+ }
48
+ }
src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/LifterLMS.php ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms\Handlers;
4
+
5
+ /**
6
+ * Lost Password is mimicked after WordPress so no separate integration necessary
7
+ * Class LifterLMS
8
+ * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms\Handlers
9
+ */
10
+ class LifterLMS extends Base {
11
+
12
+ protected function login() {
13
+ add_filter( 'llms_after_user_login_data_validation', [ $this, 'checkLogin_LLMS' ], 100 );
14
+ }
15
+
16
+ protected function register() {
17
+ add_filter( 'lifterlms_user_registration_data', [ $this, 'checkRegister_LLMS' ], 100 );
18
+ }
19
+
20
+ /**
21
+ * @param bool|\WP_Error $valid
22
+ * @return bool|\WP_Error
23
+ */
24
+ public function checkLogin_LLMS( $valid ) {
25
+ if ( !is_wp_error( $valid ) && $this->setAuditAction( 'login' )->checkIsBot() ) {
26
+ $valid = new \WP_Error( 'shield-fail-login', $this->getErrorMessage() );
27
+ }
28
+ return $valid;
29
+ }
30
+
31
+ /**
32
+ * @param bool|\WP_Error $valid
33
+ * @return bool|\WP_Error
34
+ */
35
+ public function checkRegister_LLMS( $valid ) {
36
+ if ( !is_wp_error( $valid ) && $this->setAuditAction( 'register' )->checkIsBot() ) {
37
+ $valid = new \WP_Error( 'shield-fail-register', $this->getErrorMessage() );
38
+ }
39
+ return $valid;
40
+ }
41
+
42
+ protected function getProviderName() :string {
43
+ return 'LifterLMS';
44
+ }
45
+
46
+ public static function IsProviderInstalled() :bool {
47
+ return defined( 'LLMS_PLUGIN_FILE' ) && @class_exists( 'LifterLMS' )
48
+ && defined( 'LLMS_VERSION' ) && version_compare( LLMS_VERSION, '4.20', '>' );
49
+ }
50
+ }
src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/MemberPress.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms\Handlers;
4
+
5
+ /**
6
+ * Errors are passed about using an array of strings.
7
+ *
8
+ * Class MemberPress
9
+ * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms\Handlers
10
+ */
11
+ class MemberPress extends Base {
12
+
13
+ protected function login() {
14
+ add_filter( 'mepr-validate-login', [ $this, 'checkLogin_MP' ], 100 );
15
+ }
16
+
17
+ protected function register() {
18
+ add_filter( 'mepr-validate-signup', [ $this, 'checkRegister_MP' ], 10, 2 );
19
+ }
20
+
21
+ protected function lostpassword() {
22
+ add_filter( 'mepr-validate-forgot-password', [ $this, 'checkLostPassword_MP' ], 100 );
23
+ }
24
+
25
+ /**
26
+ * @param array $errors
27
+ * @return array
28
+ */
29
+ public function checkLogin_MP( $errors ) {
30
+ if ( empty( $errors ) && $this->setAuditAction( 'login' )->checkIsBot() ) {
31
+ $errors = [
32
+ $this->getErrorMessage()
33
+ ];
34
+ }
35
+ return $errors;
36
+ }
37
+
38
+ /**
39
+ * @param array $errors
40
+ * @return array
41
+ */
42
+ public function checkLostPassword_MP( $errors ) {
43
+ if ( empty( $errors ) && $this->setAuditAction( 'lostpassword' )->checkIsBot() ) {
44
+ $errors = [
45
+ $this->getErrorMessage()
46
+ ];
47
+ }
48
+ return $errors;
49
+ }
50
+
51
+ /**
52
+ * @param string[] $errors
53
+ * @return string[]
54
+ */
55
+ public function checkRegister_MP( $errors ) {
56
+ if ( empty( $errors ) && $this->setAuditAction( 'register' )->checkIsBot() ) {
57
+ $errors = [
58
+ $this->getErrorMessage()
59
+ ];
60
+ }
61
+ return $errors;
62
+ }
63
+
64
+ protected function getProviderName() :string {
65
+ return 'MemberPress';
66
+ }
67
+
68
+ public static function IsProviderInstalled() :bool {
69
+ return function_exists( 'mepr_autoloader' ) || @class_exists( '\MeprAccountCtrl' );
70
+ }
71
+ }
src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/PaidMemberSubscriptions.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms\Handlers;
4
+
5
+ /**
6
+ * Class PaidMemberSubscriptions
7
+ * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms\Handlers
8
+ */
9
+ class PaidMemberSubscriptions extends Base {
10
+
11
+ protected function register() {
12
+ add_filter( 'pms_register_form_validation', [ $this, 'checkRegister_PMS' ], 100 );
13
+ }
14
+
15
+ public function checkRegister_PMS() {
16
+ if ( $this->setAuditAction( 'register' )->checkIsBot() ) {
17
+ \pms_errors()->add( 'shield-fail-register', $this->getErrorMessage() );
18
+ }
19
+ }
20
+
21
+ protected function getProviderName() :string {
22
+ return 'Paid Member Subscriptions';
23
+ }
24
+
25
+ public static function IsProviderInstalled() :bool {
26
+ return @class_exists( 'Paid_Member_Subscriptions' ) && function_exists( 'pms_errors' );
27
+ }
28
+ }
src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/ProfileBuilder.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms\Handlers;
4
+
5
+ /**
6
+ * https://wordpress.org/plugins/profile-builder/
7
+ *
8
+ * Class ProfileBuilder
9
+ * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms\Handlers
10
+ */
11
+ class ProfileBuilder extends Base {
12
+
13
+ protected function register() {
14
+ add_filter( 'wppb_output_field_errors_filter', [ $this, 'checkRegister_PB' ], 100 );
15
+ }
16
+
17
+ /**
18
+ * @param array $errors
19
+ * @return array
20
+ */
21
+ public function checkRegister_PB( $errors ) {
22
+ if ( empty( $errors ) && $this->setAuditAction( 'register' )->checkIsBot() ) {
23
+ $errors[ 'shield-fail-register' ] = sprintf( '<span class="wppb-form-error">%s</span>', $this->getErrorMessage() );
24
+ }
25
+ return $errors;
26
+ }
27
+
28
+ protected function getProviderName() :string {
29
+ return 'Profile Builder';
30
+ }
31
+
32
+ public static function IsProviderInstalled() :bool {
33
+ return defined( 'PROFILE_BUILDER_VERSION' );
34
+ }
35
+ }
src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/UltimateMember.php ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms\Handlers;
4
+
5
+ /**
6
+ * https://wordpress.org/plugins/ultimate-member/
7
+ *
8
+ * Class UltimateMember
9
+ * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms\Handlers
10
+ */
11
+ class UltimateMember extends Base {
12
+
13
+ protected function login() {
14
+ add_action( 'um_submit_form_login', [ $this, 'checkLogin_UM' ], 100 );
15
+ }
16
+
17
+ protected function register() {
18
+ add_action( 'um_submit_form_register', [ $this, 'checkRegister_UM' ], 5, 0 );
19
+ }
20
+
21
+ protected function lostpassword() {
22
+ add_action( 'um_submit_form_password_reset', [ $this, 'checkLostPassword_UM' ], 5, 0 );
23
+ }
24
+
25
+ public function checkLogin_UM() {
26
+ if ( $this->setAuditAction( 'login' )->checkIsBot() ) {
27
+ \UM()->form()->add_error( 'shield-fail-login', $this->getErrorMessage() );
28
+ }
29
+ }
30
+
31
+ public function checkLostPassword_UM() {
32
+ if ( $this->setAuditAction( 'lostpassword' )->checkIsBot() ) {
33
+ \UM()->form()->add_error( 'shield-fail-lostpassword', $this->getErrorMessage() );
34
+ }
35
+ }
36
+
37
+ public function checkRegister_UM() {
38
+ if ( $this->setAuditAction( 'register' )->checkIsBot() ) {
39
+ \UM()->form()->add_error( 'shield-fail-register', $this->getErrorMessage() );
40
+ }
41
+ }
42
+
43
+ protected function getProviderName() :string {
44
+ return 'Ultimate Member';
45
+ }
46
+
47
+ public static function IsProviderInstalled() :bool {
48
+ return function_exists( '\UM' ) && @class_exists( '\UM' ) && method_exists( '\UM', 'form' );
49
+ }
50
+ }
src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/WPMembers.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms\Handlers;
4
+
5
+ /**
6
+ * https://wordpress.org/plugins/wp-members/
7
+ *
8
+ * Class WPMembers
9
+ * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms\Handlers
10
+ */
11
+ class WPMembers extends Base {
12
+
13
+ protected function register() {
14
+ add_action( 'wpmem_pre_register_data', [ $this, 'checkRegister_WM' ], 5, 0 );
15
+ }
16
+
17
+ protected function lostpassword() {
18
+ add_action( 'wpmem_pwdreset_args', [ $this, 'checkLostPassword_WM' ], 5, 1 );
19
+ }
20
+
21
+ /**
22
+ * Again, nowhere to add custom validation so we hack it a little and clear
23
+ * the argument for user and email and this triggers a failure.
24
+ * @param array $args
25
+ * @return array
26
+ */
27
+ public function checkLostPassword_WM( array $args ) {
28
+ if ( $this->setAuditAction( 'lostpassword' )->checkIsBot() ) {
29
+ $args[ 'user' ] = null;
30
+ $args[ 'email' ] = null;
31
+ }
32
+ return $args;
33
+ }
34
+
35
+ /**
36
+ * Offers no direct validation filter, so we jump in right before the DB insert.
37
+ */
38
+ public function checkRegister_WM() {
39
+ if ( $this->setAuditAction( 'register' )->checkIsBot() ) {
40
+ global $wpmem_themsg;
41
+ $wpmem_themsg = $this->getErrorMessage();
42
+ }
43
+ }
44
+
45
+ protected function getProviderName() :string {
46
+ return 'WP Members';
47
+ }
48
+
49
+ public static function IsProviderInstalled() :bool {
50
+ return defined( 'WPMEM_VERSION' ) && function_exists( 'wpmem_init' );
51
+ }
52
+ }
src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/WooCommerce.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms\Handlers;
4
+
5
+ /**
6
+ * Class WooCommerce
7
+ * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms\Handlers
8
+ */
9
+ class WooCommerce extends Base {
10
+
11
+ protected function login() {
12
+ add_filter( 'woocommerce_process_login_errors', [ $this, 'checkLogin_Woo' ], 10, 2 );
13
+ }
14
+
15
+ protected function register() {
16
+ add_filter( 'woocommerce_process_registration_errors', [ $this, 'checkRegister_Woo' ], 10, 2 );
17
+ }
18
+
19
+ protected function checkout() {
20
+ add_action( 'woocommerce_after_checkout_validation', [ $this, 'checkCheckout_Woo' ], 10, 2 );
21
+ }
22
+
23
+ /**
24
+ * @param array $data
25
+ * @param \WP_Error $wpError
26
+ */
27
+ public function checkCheckout_Woo( $data, $wpError ) {
28
+ if ( empty( $wpError->get_error_code() ) && $this->setAuditAction( 'checkout' )->checkIsBot() ) {
29
+ $wpError->add( 'shield-user-checkout', $this->getErrorMessage() );
30
+ }
31
+ }
32
+
33
+ /**
34
+ * @param null|\WP_User|\WP_Error $wpError
35
+ * @param string $username
36
+ * @return \WP_User|\WP_Error
37
+ */
38
+ public function checkLogin_Woo( $wpError, $username ) {
39
+ if ( empty( $wpError->get_error_code() ) && $this->setAuditAction( 'login' )->checkIsBot() ) {
40
+ $this->setAuditUser( $username );
41
+ $wpError->add( 'shield-user-login', $this->getErrorMessage() );
42
+ }
43
+ return $wpError;
44
+ }
45
+
46
+ /**
47
+ * @param \WP_Error $wpError
48
+ * @param string $username
49
+ * @return \WP_Error
50
+ */
51
+ public function checkRegister_Woo( $wpError, $username ) {
52
+ if ( empty( $wpError->get_error_code() ) && $this->setAuditAction( 'register' )->checkIsBot() ) {
53
+ $this->setAuditUser( $username );
54
+ $wpError->add( 'shield-user-register', $this->getErrorMessage() );
55
+ }
56
+ return $wpError;
57
+ }
58
+
59
+ protected function getProviderName() :string {
60
+ return 'WooCommerce';
61
+ }
62
+
63
+ public static function IsProviderInstalled() :bool {
64
+ return @class_exists( 'WooCommerce' );
65
+ }
66
+ }
src/lib/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/WordPress.php ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms\Handlers;
4
+
5
+ use FernleafSystems\Wordpress\Services\Services;
6
+
7
+ /**
8
+ * Class WordPress
9
+ * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms\Handlers
10
+ */
11
+ class WordPress extends Base {
12
+
13
+ protected function login() {
14
+ // We give it a priority of 10 so that we can jump in before WordPress does its own validation.
15
+ add_filter( 'authenticate', [ $this, 'checkLogin_WP' ], 10, 2 );
16
+ }
17
+
18
+ protected function register() {
19
+ add_filter( 'registration_errors', [ $this, 'checkRegister_WP' ], 10, 2 );
20
+ }
21
+
22
+ protected function lostpassword() {
23
+ add_action( 'lostpassword_post', [ $this, 'checkLostPassword_WP' ], 10, 2 );
24
+ }
25
+
26
+ /**
27
+ * Should be a filter added to WordPress's "authenticate" filter, but before WordPress performs
28
+ * it's own authentication (theirs is priority 30, so we could go in at around 20).
29
+ * @param null|\WP_User|\WP_Error $userOrError
30
+ * @param string $username
31
+ * @return \WP_User|\WP_Error
32
+ */
33
+ public function checkLogin_WP( $userOrError, $username ) {
34
+ if ( !is_wp_error( $userOrError ) || empty( $userOrError->get_error_codes() ) ) {
35
+ $this->setAuditAction( 'login' )
36
+ ->setAuditUser( $username );
37
+ if ( $this->checkIsBot() ) {
38
+ $userOrError = new \WP_Error( 'shield-fail-login', $this->getErrorMessage() );
39
+ remove_filter( 'authenticate', 'wp_authenticate_username_password', 20 ); // wp-includes/user.php
40
+ remove_filter( 'authenticate', 'wp_authenticate_email_password', 20 ); // wp-includes/user.php
41
+ }
42
+ }
43
+ return $userOrError;
44
+ }
45
+
46
+ /**
47
+ * @param \WP_Error $wpError
48
+ * @param \WP_User|false $user
49
+ */
50
+ public function checkLostPassword_WP( $wpError = null, $user = false ) {
51
+ if ( is_wp_error( $wpError ) && empty( $wpError->get_error_codes() ) ) {
52
+ $this->setAuditAction( 'lostpassword' );
53
+ if ( $user instanceof \WP_User ) {
54
+ $this->setAuditUser( $user->user_login );
55
+ }
56
+ else {
57
+ $this->setAuditUser( sanitize_user( Services::Request()->post( 'user_login', '' ) ) );
58
+ }
59
+ if ( $this->checkIsBot() ) {
60
+ $wpError->add( 'shield-fail-lostpassword', $this->getErrorMessage() );
61
+ }
62
+ }
63
+ }
64
+
65
+ /**
66
+ * @param \WP_Error $wpError
67
+ * @param string $username
68
+ * @return \WP_Error
69
+ */
70
+ public function checkRegister_WP( $wpError, $username ) {
71
+ if ( !is_wp_error( $wpError ) || empty( $wpError->get_error_codes() ) ) {
72
+ $this->setAuditAction( 'register' )
73
+ ->setAuditUser( $username );
74
+ if ( $this->checkIsBot() ) {
75
+ $wpError = new \WP_Error( 'shield-fail-login', $this->getErrorMessage() );
76
+ }
77
+ }
78
+ return $wpError;
79
+ }
80
+
81
+ protected function getProviderName() :string {
82
+ return 'WordPress';
83
+ }
84
+
85
+ public static function IsProviderInstalled() :bool {
86
+ return true;
87
+ }
88
+
89
+ protected function isProOnly() :bool {
90
+ return false;
91
+ }
92
+ }
src/lib/src/Modules/Integrations/Lib/Bots/UserForms/UserFormsController.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Options;
7
+ use FernleafSystems\Wordpress\Services\Services;
8
+
9
+ class UserFormsController extends Integrations\Lib\Bots\Common\BaseBotDetectionController {
10
+
11
+ protected function canRun() :bool {
12
+ /** @var Options $loginOpts */
13
+ $loginOpts = $this->getCon()->getModule_LoginGuard()->getOptions();
14
+ return parent::canRun() && Services::Request()->isPost()
15
+ && !Services::WpUsers()->isUserLoggedIn()
16
+ && $loginOpts->isEnabledAntiBot();
17
+ }
18
+
19
+ protected function isEnabled() :bool {
20
+ /** @var Integrations\Options $opts */
21
+ $opts = $this->getOptions();
22
+ return !empty( $opts->getUserFormProviders() );
23
+ }
24
+
25
+ /**
26
+ * @return Handlers\Base[]
27
+ */
28
+ public function enumProviders() :array {
29
+ return [
30
+ new Handlers\Buddypress(),
31
+ new Handlers\EasyDigitalDownloads(),
32
+ new Handlers\LearnPress(),
33
+ new Handlers\LifterLMS(),
34
+ new Handlers\MemberPress(),
35
+ new Handlers\PaidMemberSubscriptions(),
36
+ new Handlers\ProfileBuilder(),
37
+ new Handlers\UltimateMember(),
38
+ new Handlers\WooCommerce(),
39
+ new Handlers\WordPress(),
40
+ new Handlers\WPMembers(),
41
+ ];
42
+ }
43
+ }
src/lib/src/Modules/Integrations/Lib/MainWP/Controller.php CHANGED
@@ -2,16 +2,12 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP;
4
 
5
- use FernleafSystems\Utilities\Logic\ExecOnce;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Client;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Common\MainWPVO;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Server;
9
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
10
 
11
- class Controller {
12
-
13
- use ModConsumer;
14
- use ExecOnce;
15
 
16
  const MIN_VERSION_MAINWP = '4.1';
17
 
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Client;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Common\MainWPVO;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Server;
 
9
 
10
+ class Controller extends ExecOnceModConsumer {
 
 
 
11
 
12
  const MIN_VERSION_MAINWP = '4.1';
13
 
src/lib/src/Modules/Integrations/Lib/MainWP/Server/Data/SyncHandler.php CHANGED
@@ -2,14 +2,10 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Server\Data;
4
 
5
- use FernleafSystems\Utilities\Logic\ExecOnce;
6
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
  use MainWP\Dashboard\MainWP_DB;
8
 
9
- class SyncHandler {
10
-
11
- use ModConsumer;
12
- use ExecOnce;
13
 
14
  protected function run() {
15
  add_action( 'mainwp_sync_others_data', function ( $othersData, $website ) {
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Server\Data;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
 
6
  use MainWP\Dashboard\MainWP_DB;
7
 
8
+ class SyncHandler extends ExecOnceModConsumer {
 
 
 
9
 
10
  protected function run() {
11
  add_action( 'mainwp_sync_others_data', function ( $othersData, $website ) {
src/lib/src/Modules/Integrations/Lib/MainWP/Server/UI/ExtensionSettingsPage.php CHANGED
@@ -2,17 +2,13 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Server\UI;
4
 
5
- use FernleafSystems\Utilities\Logic\ExecOnce;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Controller\Assets\Enqueue;
 
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Controller;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Server\UI\PageRender;
9
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
10
  use FernleafSystems\Wordpress\Services\Services;
11
 
12
- class ExtensionSettingsPage {
13
-
14
- use ModConsumer;
15
- use ExecOnce;
16
 
17
  protected function run() {
18
 
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Server\UI;
4
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Controller\Assets\Enqueue;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Controller;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Server\UI\PageRender;
 
9
  use FernleafSystems\Wordpress\Services\Services;
10
 
11
+ class ExtensionSettingsPage extends ExecOnceModConsumer {
 
 
 
12
 
13
  protected function run() {
14
 
src/lib/src/Modules/Integrations/Lib/Spam/Handlers/Base.php CHANGED
@@ -2,14 +2,10 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Spam\Handlers;
4
 
5
- use FernleafSystems\Utilities\Logic\ExecOnce;
6
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
  use FernleafSystems\Wordpress\Services\Services;
8
 
9
- abstract class Base {
10
-
11
- use ModConsumer;
12
- use ExecOnce;
13
 
14
  const SLUG = '';
15
 
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Spam\Handlers;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
 
6
  use FernleafSystems\Wordpress\Services\Services;
7
 
8
+ abstract class Base extends ExecOnceModConsumer {
 
 
 
9
 
10
  const SLUG = '';
11
 
src/lib/src/Modules/Integrations/Lib/Spam/SpamController.php CHANGED
@@ -5,6 +5,11 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Spam;
5
  use FernleafSystems\Utilities\Logic\ExecOnce;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
 
 
 
 
 
 
8
  class SpamController {
9
 
10
  use ModConsumer;
5
  use FernleafSystems\Utilities\Logic\ExecOnce;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
 
8
+ /**
9
+ * Class SpamController
10
+ * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Spam
11
+ * @deprecated 11.2
12
+ */
13
  class SpamController {
14
 
15
  use ModConsumer;
src/lib/src/Modules/Integrations/ModCon.php CHANGED
@@ -12,6 +12,11 @@ class ModCon extends BaseShield\ModCon {
12
  */
13
  private $mwp;
14
 
 
 
 
 
 
15
  public function getControllerMWP() :Lib\MainWP\Controller {
16
  if ( empty( $this->mwp ) ) {
17
  $this->mwp = ( new Lib\MainWP\Controller() )
@@ -19,4 +24,12 @@ class ModCon extends BaseShield\ModCon {
19
  }
20
  return $this->mwp;
21
  }
 
 
 
 
 
 
 
 
22
  }
12
  */
13
  private $mwp;
14
 
15
+ /**
16
+ * @var Lib\Bots\UserForms\UserFormsController
17
+ */
18
+ private $userFormsCon;
19
+
20
  public function getControllerMWP() :Lib\MainWP\Controller {
21
  if ( empty( $this->mwp ) ) {
22
  $this->mwp = ( new Lib\MainWP\Controller() )
24
  }
25
  return $this->mwp;
26
  }
27
+
28
+ public function getController_UserForms() :Lib\Bots\UserForms\UserFormsController {
29
+ if ( !$this->userFormsCon instanceof Lib\Bots\UserForms\UserFormsController ) {
30
+ $this->userFormsCon = ( new Lib\Bots\UserForms\UserFormsController() )
31
+ ->setMod( $this );
32
+ }
33
+ return $this->userFormsCon;
34
+ }
35
  }
src/lib/src/Modules/Integrations/Options.php CHANGED
@@ -9,4 +9,16 @@ class Options extends BaseShield\Options {
9
  public function isEnabledMainWP() :bool {
10
  return $this->isOpt( 'enable_mainwp', 'Y' );
11
  }
 
 
 
 
 
 
 
 
 
 
 
 
12
  }
9
  public function isEnabledMainWP() :bool {
10
  return $this->isOpt( 'enable_mainwp', 'Y' );
11
  }
12
+
13
+ public function getUserFormProviders() :array {
14
+ $userForms = $this->getOpt( 'user_form_providers' );
15
+ if ( !is_array( $userForms ) ) {
16
+ $userForms = [];
17
+ }
18
+ if ( !in_array( 'wordpress', $userForms ) ) {
19
+ $userForms[] = 'wordpress';
20
+ $this->setOpt( 'user_form_providers', $userForms );
21
+ }
22
+ return array_unique( $userForms );
23
+ }
24
  }
src/lib/src/Modules/Integrations/Processor.php CHANGED
@@ -3,6 +3,7 @@
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
 
6
 
7
  class Processor extends BaseShield\Processor {
8
 
@@ -10,9 +11,15 @@ class Processor extends BaseShield\Processor {
10
  /** @var ModCon $mod */
11
  $mod = $this->getMod();
12
  $mod->getControllerMWP()->execute();
13
-
14
- ( new Lib\Spam\SpamController() )
15
- ->setMod( $this->getMod() )
16
- ->execute();
 
 
 
 
 
 
17
  }
18
  }
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
 
8
  class Processor extends BaseShield\Processor {
9
 
11
  /** @var ModCon $mod */
12
  $mod = $this->getMod();
13
  $mod->getControllerMWP()->execute();
14
+
15
+ if ( !empty( Services::IP()->getRequestIp() ) ) {
16
+ ( new Lib\Bots\Spam\SpamController() )
17
+ ->setMod( $this->getMod() )
18
+ ->execute();
19
+
20
+ add_action( 'init', function () use ( $mod ) {
21
+ $mod->getController_UserForms()->execute();
22
+ }, -100 );
23
+ }
24
  }
25
  }
src/lib/src/Modules/Integrations/Strings.php CHANGED
@@ -11,12 +11,18 @@ class Strings extends Base\Strings {
11
  */
12
  protected function getAuditMessages() :array {
13
  return [
14
- 'spam_form_pass' => [
15
  __( '"%s" submission passed SPAM check.', 'wp-simple-firewall' ),
16
  ],
17
- 'spam_form_fail' => [
18
  __( '"%s" submission failed SPAM check.', 'wp-simple-firewall' )
19
  ],
 
 
 
 
 
 
20
  ];
21
  }
22
 
@@ -40,6 +46,21 @@ class Strings extends Base\Strings {
40
  ];
41
  break;
42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  default:
44
  return parent::getSectionStrings( $section );
45
  }
@@ -57,6 +78,7 @@ class Strings extends Base\Strings {
57
  * @throws \Exception
58
  */
59
  public function getOptionStrings( string $key ) :array {
 
60
 
61
  switch ( $key ) {
62
 
@@ -72,6 +94,22 @@ class Strings extends Base\Strings {
72
  ];
73
  break;
74
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  default:
76
  return parent::getOptionStrings( $key );
77
  }
11
  */
12
  protected function getAuditMessages() :array {
13
  return [
14
+ 'spam_form_pass' => [
15
  __( '"%s" submission passed SPAM check.', 'wp-simple-firewall' ),
16
  ],
17
+ 'spam_form_fail' => [
18
  __( '"%s" submission failed SPAM check.', 'wp-simple-firewall' )
19
  ],
20
+ 'user_form_bot_pass' => [
21
+ __( '"%s" submission for form "%s" with username "%s" passed Bot check.', 'wp-simple-firewall' ),
22
+ ],
23
+ 'user_form_bot_fail' => [
24
+ __( '"%s" submission for form "%s" with username "%s" failed Bot check.', 'wp-simple-firewall' ),
25
+ ],
26
  ];
27
  }
28
 
46
  ];
47
  break;
48
 
49
+ case 'section_user_forms':
50
+ $titleShort = __( 'User Forms Bot Checking', 'wp-simple-firewall' );
51
+ $title = __( 'User Forms Bot Checking', 'wp-simple-firewall' );
52
+ $summary = [
53
+ sprintf( '%s - %s %s', __( 'Summary', 'wp-simple-firewall' ),
54
+ __( "Shield can automatically protect 3rd party login and registration forms against Bots.", 'wp-simple-firewall' ),
55
+ __( "It uses our exclusive AntiBot Detection Engine to reliably identify bots.", 'wp-simple-firewall' )
56
+ ),
57
+ sprintf( '%s - %s (%s)', __( 'Recommendation', 'wp-simple-firewall' ),
58
+ __( "Only enable the integrations you require.", 'wp-simple-firewall' ),
59
+ __( "WordPress is always enabled.", 'wp-simple-firewall' )
60
+ ),
61
+ ];
62
+ break;
63
+
64
  default:
65
  return parent::getSectionStrings( $section );
66
  }
78
  * @throws \Exception
79
  */
80
  public function getOptionStrings( string $key ) :array {
81
+ $con = $this->getCon();
82
 
83
  switch ( $key ) {
84
 
94
  ];
95
  break;
96
 
97
+ case 'user_form_providers' :
98
+ $name = __( 'User Forms Bot Detection', 'wp-simple-firewall' );
99
+ $summary = __( "Select The User Forms Provider That You Use", 'wp-simple-firewall' );
100
+ $desc = [
101
+ __( 'This is a ShieldPRO-only feature.', 'wp-simple-firewall' ),
102
+ __( 'Many 3rd party plugins provide custom user login, registration, and lost password forms.', 'wp-simple-firewall' )
103
+ .' '.__( "They aren't normally checked for Bots since they require a custom integration.", 'wp-simple-firewall' ),
104
+ __( "Select your 3rd party providers to have Shield automatically detect Bot requests to these forms.", 'wp-simple-firewall' ),
105
+ sprintf( '%s: %s', __( 'Important', 'wp-simple-firewall' ),
106
+ __( 'Only the form types (login, registration, lost password), that you have selected in the Login Guard module will be checked.', 'wp-simple-firewall' ) ),
107
+ sprintf( '<a href="%s">%s</a>', $con->getModule_LoginGuard()
108
+ ->getUrl_DirectLinkToSection( 'section_brute_force_login_protection' ),
109
+ sprintf( __( 'Choose the types of forms you want %s to check', 'wp-simple-firewall' ), $con->getHumanName() ) ),
110
+ ];
111
+ break;
112
+
113
  default:
114
  return parent::getOptionStrings( $key );
115
  }
src/lib/src/Modules/Integrations/UI.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules;
6
+
7
+ class UI extends Modules\BaseShield\UI {
8
+
9
+ protected function getSectionNotices( string $section ) :array {
10
+ $notices = [];
11
+
12
+ /** @var Modules\LoginGuard\Options $loginGuardOpts */
13
+ $loginGuardOpts = $this->getCon()->getModule_LoginGuard()->getOptions();
14
+ $locations = $loginGuardOpts->getBotProtectionLocations();
15
+ $locations = array_intersect_key(
16
+ array_merge(
17
+ array_flip( $locations ),
18
+ [
19
+ 'login' => __( 'Login', 'wp-simple-firewall' ),
20
+ 'register' => __( 'Registration', 'wp-simple-firewall' ),
21
+ 'password' => __( 'Lost Password', 'wp-simple-firewall' ),
22
+ 'checkout_woo' => __( 'Checkout', 'wp-simple-firewall' ),
23
+ ]
24
+ ),
25
+ array_flip( $locations )
26
+ );
27
+ $locations = empty( $locations ) ? __( 'None', 'wp-simple-firewall' ) : implode( ', ', $locations );
28
+
29
+ switch ( $section ) {
30
+
31
+ case 'section_user_forms':
32
+ if ( $loginGuardOpts->isEnabledAntiBot() ) {
33
+ $notices[] = sprintf( '%s: %s %s', __( 'Note', 'wp-simple-firewall' ),
34
+ sprintf(
35
+ __( "The following forms are protected by AntiBot Detection: %s.", 'wp-simple-firewall' ),
36
+ $locations
37
+ ),
38
+ sprintf( '<a href="%s" target="_blank">%s</a>',
39
+ $this->getCon()->getModule_LoginGuard()->getUrl_AdminPage(),
40
+ __( 'Click here to review those settings.', 'wp-simple-firewall' ) )
41
+ );
42
+ }
43
+ break;
44
+ }
45
+
46
+ return $notices;
47
+ }
48
+
49
+ protected function getSectionWarnings( string $section ) :array {
50
+ $warnings = [];
51
+
52
+ /** @var Modules\LoginGuard\Options $loginGuardOpts */
53
+ $loginGuardOpts = $this->getCon()->getModule_LoginGuard()->getOptions();
54
+
55
+ switch ( $section ) {
56
+
57
+ case 'section_user_forms':
58
+ if ( !$loginGuardOpts->isEnabledAntiBot() ) {
59
+ $warnings[] = sprintf( '%s: %s %s', __( 'Important', 'wp-simple-firewall' ),
60
+ __( "Use of the AntiBot Detection Engine for user forms isn't turned on in the Login Guard module.", 'wp-simple-firewall' ),
61
+ sprintf( '<a href="%s" target="_blank">%s</a>',
62
+ $this->getCon()->getModule_LoginGuard()->getUrl_AdminPage(),
63
+ __( 'Click here to review those settings.', 'wp-simple-firewall' ) )
64
+ );
65
+ }
66
+ break;
67
+ }
68
+
69
+ return $warnings;
70
+ }
71
+ }
src/lib/src/Modules/Integrations/Upgrade.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Bots\UserForms\UserFormsController;
7
+
8
+ class Upgrade extends Base\Upgrade {
9
+
10
+ protected function upgrade_1120() {
11
+ /** @var Options $opts */
12
+ $opts = $this->getOptions();
13
+ $providers = ( new UserFormsController() )
14
+ ->setMod( $this->getMod() )
15
+ ->enumProviders();
16
+
17
+ $enabledProviders = $opts->getUserFormProviders();
18
+ foreach ( $providers as $provider ) {
19
+ if ( $provider::IsProviderInstalled() ) {
20
+ $enabledProviders[] = $provider->getHandlerSlug();
21
+ }
22
+ }
23
+ $opts->setOpt( 'user_form_providers', array_unique( $enabledProviders ) );
24
+ }
25
+ }
src/lib/src/Modules/License/Lib/LookupRequest.php CHANGED
@@ -1,7 +1,8 @@
1
- <?php
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\License\Lib;
4
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
  use FernleafSystems\Wordpress\Plugin\Shield\ShieldNetApi\HandshakingNonce;
7
  use FernleafSystems\Wordpress\Services\Services;
@@ -11,39 +12,24 @@ class LookupRequest {
11
 
12
  use ModConsumer;
13
 
14
- /**
15
- * @return \FernleafSystems\Wordpress\Services\Utilities\Licenses\EddLicenseVO
16
- */
17
- public function lookup() {
18
- $oCon = $this->getCon();
19
- $oOpts = $this->getOptions();
20
 
21
  {
22
- $oLook = new Lookup();
23
- $oLook->lookup_url_stub = $oOpts->getDef( 'license_store_url_api' );
24
- $oLook->item_id = $oOpts->getDef( 'license_item_id' );
25
- $oLook->install_id = $oCon->getSiteInstallationId();
26
- $oLook->url = Services::WpGeneral()->getHomeUrl( '', true );
27
- $oLook->nonce = ( new HandshakingNonce() )->setMod( $this->getMod() )->create();
28
- $oLook->meta = [
29
- 'version_shield' => $oCon->getVersion(),
30
  'version_php' => Services::Data()->getPhpVersionCleaned()
31
  ];
32
- $oLicense = $oLook->lookup();
33
  }
34
 
35
- return $oLicense;
36
- }
37
-
38
- /**
39
- * @param string $sNonce - empty string to clear the nonce
40
- */
41
- private function setKeylessHandshakeNonce( $sNonce = '' ) {
42
- $oOpts = $this->getOptions();
43
- $oOpts->setOpt( 'keyless_handshake_hash', $sNonce )
44
- ->setOpt( 'keyless_handshake_until',
45
- empty( $sNonce ) ? 0 : Services::Request()->ts() + $oOpts->getDef( 'keyless_handshake_expire' )
46
- );
47
- $this->getMod()->saveModOptions();
48
  }
49
  }
1
+ <?php declare( strict_types=1 );
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\License\Lib;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\License\EddLicenseVO;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
  use FernleafSystems\Wordpress\Plugin\Shield\ShieldNetApi\HandshakingNonce;
8
  use FernleafSystems\Wordpress\Services\Services;
12
 
13
  use ModConsumer;
14
 
15
+ public function lookup() :EddLicenseVO {
16
+ $con = $this->getCon();
17
+ $opts = $this->getOptions();
 
 
 
18
 
19
  {
20
+ $lookup = new Lookup();
21
+ $lookup->lookup_url_stub = $opts->getDef( 'license_store_url_api' );
22
+ $lookup->item_id = $opts->getDef( 'license_item_id' );
23
+ $lookup->install_id = $con->getSiteInstallationId();
24
+ $lookup->url = Services::WpGeneral()->getHomeUrl( '', true );
25
+ $lookup->nonce = ( new HandshakingNonce() )->setMod( $this->getMod() )->create();
26
+ $lookup->meta = [
27
+ 'version_shield' => $con->getVersion(),
28
  'version_php' => Services::Data()->getPhpVersionCleaned()
29
  ];
30
+ $license = $lookup->lookup();
31
  }
32
 
33
+ return ( new EddLicenseVO() )->applyFromArray( $license->getRawDataAsArray() );
 
 
 
 
 
 
 
 
 
 
 
 
34
  }
35
  }
src/lib/src/Modules/License/Lib/PluginNameSuffix.php CHANGED
@@ -4,7 +4,6 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\License\Lib;
4
 
5
  use FernleafSystems\Utilities\Logic\ExecOnce;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules;
7
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin;
8
 
9
  class PluginNameSuffix {
10
 
@@ -13,9 +12,8 @@ class PluginNameSuffix {
13
 
14
  protected function canRun() :bool {
15
  $con = $this->getCon();
16
- /** @var SecurityAdmin\Options $optsSecAdmin */
17
- $optsSecAdmin = $con->getModule_SecAdmin()->getOptions();
18
- return (bool)apply_filters( 'shield/add_pro_suffix', $con->isPremiumActive() && !$optsSecAdmin->isEnabledWhitelabel() );
19
  }
20
 
21
  protected function run() {
4
 
5
  use FernleafSystems\Utilities\Logic\ExecOnce;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules;
 
7
 
8
  class PluginNameSuffix {
9
 
12
 
13
  protected function canRun() :bool {
14
  $con = $this->getCon();
15
+ return (bool)apply_filters( 'shield/add_pro_suffix',
16
+ $con->isPremiumActive() && !$con->getModule_SecAdmin()->getWhiteLabelController()->isEnabled() );
 
17
  }
18
 
19
  protected function run() {
src/lib/src/Modules/License/Lib/Verify.php CHANGED
@@ -14,51 +14,50 @@ class Verify {
14
  * @throws \Exception
15
  */
16
  public function run() {
17
- $con = $this->getCon();
18
  /** @var License\ModCon $mod */
19
  $mod = $this->getMod();
20
  /** @var License\Options $opts */
21
  $opts = $this->getOptions();
22
- $oHandler = $mod->getLicenseHandler();
23
 
24
  $this->preVerify();
25
 
26
- $oExisting = $oHandler->getLicense();
27
 
28
- $oLookupLicense = ( new LookupRequest() )
29
  ->setMod( $mod )
30
  ->lookup();
31
 
32
- $bSuccessfulApiRequest = false;
33
 
34
- if ( $oLookupLicense->isValid() ) {
35
- $bSuccessfulApiRequest = true;
36
- $oExisting = $oLookupLicense;
37
- $oExisting->updateLastVerifiedAt( true );
38
- if ( !$oHandler->isActive() ) {
39
  $opts->setOptAt( 'license_activated_at' );
40
  }
41
  $mod->clearLastErrors();
42
- $opts->setOpt( 'license_data', $oExisting->getRawDataAsArray() ); // need to do this before event
43
- $con->fireEvent( 'lic_check_success' );
44
  }
45
- elseif ( $oLookupLicense->isReady() ) {
46
- $bSuccessfulApiRequest = true;
47
  // License lookup failed but request was successful - so use what we get
48
- $oHandler->deactivate();
49
- $oExisting = $oHandler->getLicense();
50
  }
51
- elseif ( $oExisting->isReady() ) { // Has a stored license but license HTTP request failed
52
 
53
  $mod->setLastErrors( [
54
  __( 'The most recent request to verify the site license encountered a problem.', 'wp-simple-firewall' )
55
  ] );
56
 
57
- if ( Services::Request()->ts() > $oHandler->getRegistrationExpiresAt() ) {
58
- $oHandler->deactivate();
59
- $oExisting = $oHandler->getLicense();
60
  }
61
- elseif ( $oHandler->isLastVerifiedExpired() ) {
62
  /**
63
  * At this stage we have a license stored, but we couldn't
64
  * verify it, but we're within the grace period for checking.
@@ -71,15 +70,15 @@ class Verify {
71
  }
72
  }
73
  else { // all else fails, clear any license details entirely
74
- $oHandler->clearLicense();
75
- $oExisting = $oHandler->getLicense();
76
  }
77
 
78
- $oExisting->last_request_at = Services::Request()->ts();
79
- $opts->setOpt( 'license_data', $oExisting->getRawDataAsArray() );
80
  $this->getMod()->saveModOptions();
81
 
82
- if ( !$bSuccessfulApiRequest ) {
83
  throw new \Exception( 'License API HTTP Request Failed.' );
84
  }
85
  }
14
  * @throws \Exception
15
  */
16
  public function run() {
 
17
  /** @var License\ModCon $mod */
18
  $mod = $this->getMod();
19
  /** @var License\Options $opts */
20
  $opts = $this->getOptions();
21
+ $licHandler = $mod->getLicenseHandler();
22
 
23
  $this->preVerify();
24
 
25
+ $existing = $licHandler->getLicense();
26
 
27
+ $license = ( new LookupRequest() )
28
  ->setMod( $mod )
29
  ->lookup();
30
 
31
+ $isSuccessfulApiRequest = false;
32
 
33
+ if ( $license->isValid() ) {
34
+ $isSuccessfulApiRequest = true;
35
+ $existing = $license;
36
+ $existing->updateLastVerifiedAt( true );
37
+ if ( !$licHandler->isActive() ) {
38
  $opts->setOptAt( 'license_activated_at' );
39
  }
40
  $mod->clearLastErrors();
41
+ $opts->setOpt( 'license_data', $existing->getRawDataAsArray() ); // need to do this before event
42
+ $this->getCon()->fireEvent( 'lic_check_success' );
43
  }
44
+ elseif ( $license->isReady() ) {
45
+ $isSuccessfulApiRequest = true;
46
  // License lookup failed but request was successful - so use what we get
47
+ $licHandler->deactivate();
48
+ $existing = $licHandler->getLicense();
49
  }
50
+ elseif ( $existing->isReady() ) { // Has a stored license but license HTTP request failed
51
 
52
  $mod->setLastErrors( [
53
  __( 'The most recent request to verify the site license encountered a problem.', 'wp-simple-firewall' )
54
  ] );
55
 
56
+ if ( Services::Request()->ts() > $licHandler->getRegistrationExpiresAt() ) {
57
+ $licHandler->deactivate();
58
+ $existing = $licHandler->getLicense();
59
  }
60
+ elseif ( $licHandler->isLastVerifiedExpired() ) {
61
  /**
62
  * At this stage we have a license stored, but we couldn't
63
  * verify it, but we're within the grace period for checking.
70
  }
71
  }
72
  else { // all else fails, clear any license details entirely
73
+ $licHandler->clearLicense();
74
+ $existing = $licHandler->getLicense();
75
  }
76
 
77
+ $existing->last_request_at = Services::Request()->ts();
78
+ $opts->setOpt( 'license_data', $existing->getRawDataAsArray() );
79
  $this->getMod()->saveModOptions();
80
 
81
+ if ( !$isSuccessfulApiRequest ) {
82
  throw new \Exception( 'License API HTTP Request Failed.' );
83
  }
84
  }
src/lib/src/Modules/Lockdown/Insights/OverviewCards.php CHANGED
@@ -6,24 +6,15 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules;
6
 
7
  class OverviewCards extends Modules\Base\Insights\OverviewCards {
8
 
9
- public function build() :array {
10
  /** @var Modules\Lockdown\ModCon $mod */
11
  $mod = $this->getMod();
12
  /** @var Modules\Lockdown\Options $opts */
13
  $opts = $this->getOptions();
14
 
15
- $cardSection = [
16
- 'title' => __( 'WordPress Lockdown', 'wp-simple-firewall' ),
17
- 'subtitle' => __( 'Restrict WP Functionality e.g. XMLRPC & REST API', 'wp-simple-firewall' ),
18
- 'href_options' => $mod->getUrl_AdminPage()
19
- ];
20
-
21
  $cards = [];
22
 
23
- if ( !$mod->isModOptEnabled() ) {
24
- $cards[ 'mod' ] = $this->getModDisabledCard();
25
- }
26
- else {
27
  $bUserCanEdit = current_user_can( 'edit_plugins' );
28
 
29
  if ( !$bUserCanEdit ) {
@@ -70,7 +61,14 @@ class OverviewCards extends Modules\Base\Insights\OverviewCards {
70
  ];
71
  }
72
 
73
- $cardSection[ 'cards' ] = $cards;
74
- return [ 'lockdown' => $cardSection ];
 
 
 
 
 
 
 
75
  }
76
  }
6
 
7
  class OverviewCards extends Modules\Base\Insights\OverviewCards {
8
 
9
+ protected function buildModCards() :array {
10
  /** @var Modules\Lockdown\ModCon $mod */
11
  $mod = $this->getMod();
12
  /** @var Modules\Lockdown\Options $opts */
13
  $opts = $this->getOptions();
14
 
 
 
 
 
 
 
15
  $cards = [];
16
 
17
+ if ( $mod->isModOptEnabled() ) {
 
 
 
18
  $bUserCanEdit = current_user_can( 'edit_plugins' );
19
 
20
  if ( !$bUserCanEdit ) {
61
  ];
62
  }
63
 
64
+ return $cards;
65
+ }
66
+
67
+ protected function getSectionTitle() :string {
68
+ return __( 'WordPress Lockdown', 'wp-simple-firewall' );
69
+ }
70
+
71
+ protected function getSectionSubTitle() :string {
72
+ return __( 'Restrict WP Functionality e.g. XMLRPC & REST API', 'wp-simple-firewall' );
73
  }
74
  }
src/lib/src/Modules/Lockdown/Lib/CleanRubbish.php CHANGED
@@ -2,14 +2,10 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Lockdown\Lib;
4
 
5
- use FernleafSystems\Utilities\Logic\ExecOnce;
6
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
  use FernleafSystems\Wordpress\Services\Services;
8
 
9
- class CleanRubbish {
10
-
11
- use ModConsumer;
12
- use ExecOnce;
13
 
14
  protected function canRun() :bool {
15
  return $this->getOptions()->isOpt( 'clean_wp_rubbish', 'Y' );
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Lockdown\Lib;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
 
6
  use FernleafSystems\Wordpress\Services\Services;
7
 
8
+ class CleanRubbish extends ExecOnceModConsumer {
 
 
 
9
 
10
  protected function canRun() :bool {
11
  return $this->getOptions()->isOpt( 'clean_wp_rubbish', 'Y' );
src/lib/src/Modules/LoginGuard/AjaxHandler.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
4
 
@@ -11,6 +11,10 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
11
  protected function processAjaxAction( string $action ) :array {
12
 
13
  switch ( $action ) {
 
 
 
 
14
  case 'gen_backup_codes':
15
  $response = $this->ajaxExec_GenBackupCodes();
16
  break;
@@ -23,16 +27,28 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
23
  $response = $this->ajaxExec_Disable2faEmail();
24
  break;
25
 
 
 
 
 
 
 
 
 
26
  case 'resend_verification_email':
27
  $response = $this->ajaxExec_ResendEmailVerification();
28
  break;
29
 
 
 
 
 
30
  case 'u2f_remove':
31
  $response = $this->ajaxExec_ProfileU2fRemove();
32
  break;
33
 
34
- case 'yubikey_remove':
35
- $response = $this->ajaxExec_ProfileYubikeyRemove();
36
  break;
37
 
38
  default:
@@ -42,19 +58,38 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
42
  return $response;
43
  }
44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  protected function ajaxExec_GenBackupCodes() :array {
46
  /** @var ModCon $mod */
47
  $mod = $this->getMod();
48
- /** @var TwoFactor\Provider\Backup $oBU */
49
- $oBU = $mod->getLoginIntentController()
50
- ->getProviders()[ TwoFactor\Provider\Backup::SLUG ];
51
- $pass = $oBU->resetSecret( Services::WpUsers()->getCurrentWpUser() );
52
 
53
- foreach ( [ 20, 15, 10, 5 ] as $pos ) {
54
- $pass = substr_replace( $pass, '-', $pos, 0 );
55
- }
56
 
57
  return [
 
58
  'code' => $pass,
59
  'success' => true
60
  ];
@@ -63,16 +98,60 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
63
  private function ajaxExec_DeleteBackupCodes() :array {
64
  /** @var ModCon $mod */
65
  $mod = $this->getMod();
66
- /** @var TwoFactor\Provider\Backup $oBU */
67
- $oBU = $mod->getLoginIntentController()
68
- ->getProviders()[ TwoFactor\Provider\Backup::SLUG ];
69
- $oBU->deleteSecret( Services::WpUsers()->getCurrentWpUser() );
70
  $mod->setFlashAdminNotice( __( 'Multi-factor login backup code has been removed from your profile', 'wp-simple-firewall' ) );
 
71
  return [
 
72
  'success' => true
73
  ];
74
  }
75
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  private function ajaxExec_Disable2faEmail() :array {
77
  /** @var ModCon $mod */
78
  $mod = $this->getMod();
@@ -84,15 +163,41 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
84
  ];
85
  }
86
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  private function ajaxExec_ProfileU2fRemove() :array {
88
  /** @var ModCon $mod */
89
  $mod = $this->getMod();
 
 
 
90
 
91
  $key = Services::Request()->post( 'u2fid' );
92
  if ( !empty( $key ) ) {
93
- ( new TwoFactor\Provider\U2F() )
94
- ->setMod( $mod )
95
- ->removeRegisteredU2fId( Services::WpUsers()->getCurrentWpUser(), $key );
96
  }
97
  return [
98
  'success' => !empty( $key ),
@@ -101,28 +206,23 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
101
  ];
102
  }
103
 
104
- /**
105
- * @return array
106
- */
107
- private function ajaxExec_ProfileYubikeyRemove() {
108
  /** @var ModCon $mod */
109
  $mod = $this->getMod();
 
 
 
110
 
111
- $key = Services::Request()->post( 'yubikeyid' );
112
- ( new TwoFactor\Provider\Yubikey() )
113
- ->setMod( $mod )
114
- ->addRemoveRegisteredYubiId( Services::WpUsers()->getCurrentWpUser(), $key, false );
115
  return [
116
- 'success' => true,
117
- 'message' => __( 'Yubikey removed from profile.', 'wp-simple-firewall' ),
118
  'page_reload' => true
119
  ];
120
  }
121
 
122
- /**
123
- * @return array
124
- */
125
- private function ajaxExec_ResendEmailVerification() {
126
  /** @var ModCon $mod */
127
  $mod = $this->getMod();
128
  /** @var Options $opts */
@@ -130,21 +230,21 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
130
  $success = true;
131
 
132
  if ( !$opts->isEnabledEmailAuth() ) {
133
- $sMessage = __( 'Email 2FA option is not currently enabled.', 'wp-simple-firewall' );
134
  $success = false;
135
  }
136
  elseif ( $opts->getIfCanSendEmailVerified() ) {
137
- $sMessage = __( 'Email sending has already been verified.', 'wp-simple-firewall' );
138
  }
139
  else {
140
- $sMessage = __( 'Verification email resent.', 'wp-simple-firewall' );
141
  $mod->setIfCanSendEmail( false )
142
  ->sendEmailVerifyCanSend();
143
  }
144
 
145
  return [
146
  'success' => $success,
147
- 'message' => $sMessage
148
  ];
149
  }
150
  }
1
+ <?php declare( strict_types=1 );
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
4
 
11
  protected function processAjaxAction( string $action ) :array {
12
 
13
  switch ( $action ) {
14
+ case 'mfa_remove_all':
15
+ $response = $this->ajaxExec_MfaRemoveAll();
16
+ break;
17
+
18
  case 'gen_backup_codes':
19
  $response = $this->ajaxExec_GenBackupCodes();
20
  break;
27
  $response = $this->ajaxExec_Disable2faEmail();
28
  break;
29
 
30
+ case 'user_ga_toggle':
31
+ $response = $this->ajaxExec_UserGaToggle();
32
+ break;
33
+
34
+ case 'user_email2fa_toggle':
35
+ $response = $this->ajaxExec_User2faEmailToggle();
36
+ break;
37
+
38
  case 'resend_verification_email':
39
  $response = $this->ajaxExec_ResendEmailVerification();
40
  break;
41
 
42
+ case 'u2f_add':
43
+ $response = $this->ajaxExec_ProfileU2fAdd();
44
+ break;
45
+
46
  case 'u2f_remove':
47
  $response = $this->ajaxExec_ProfileU2fRemove();
48
  break;
49
 
50
+ case 'user_yubikey_toggle':
51
+ $response = $this->ajaxExec_UserYubikeyToggle();
52
  break;
53
 
54
  default:
58
  return $response;
59
  }
60
 
61
+ private function ajaxExec_MfaRemoveAll() :array {
62
+ /** @var ModCon $mod */
63
+ $mod = $this->getMod();
64
+ $userID = Services::Request()->post( 'user_id' );
65
+ if ( !empty( $userID ) ) {
66
+ $result = $mod->getLoginIntentController()->removeAllFactorsForUser( (int)$userID );
67
+ $response = [
68
+ 'success' => $result->success,
69
+ 'message' => $result->success ? $result->msg_text : $result->error_text,
70
+ ];
71
+ }
72
+ else {
73
+ $response = [
74
+ 'success' => false,
75
+ 'message' => 'Invalid request with no User ID',
76
+ ];
77
+ }
78
+
79
+ return $response;
80
+ }
81
+
82
  protected function ajaxExec_GenBackupCodes() :array {
83
  /** @var ModCon $mod */
84
  $mod = $this->getMod();
85
+ /** @var TwoFactor\Provider\BackupCodes $provider */
86
+ $provider = $mod->getLoginIntentController()->getProviders()[ TwoFactor\Provider\BackupCodes::SLUG ];
 
 
87
 
88
+ $pass = $provider->resetSecret( Services::WpUsers()->getCurrentWpUser() );
89
+ $pass = implode( '-', str_split( $pass, 5 ) );
 
90
 
91
  return [
92
+ 'message' => sprintf( 'Your backup login code is:<br/><code>%s</code>', $pass ),
93
  'code' => $pass,
94
  'success' => true
95
  ];
98
  private function ajaxExec_DeleteBackupCodes() :array {
99
  /** @var ModCon $mod */
100
  $mod = $this->getMod();
101
+ /** @var TwoFactor\Provider\BackupCodes $provider */
102
+ $provider = $mod->getLoginIntentController()->getProviders()[ TwoFactor\Provider\BackupCodes::SLUG ];
103
+ $provider->deleteSecret( Services::WpUsers()->getCurrentWpUser() );
 
104
  $mod->setFlashAdminNotice( __( 'Multi-factor login backup code has been removed from your profile', 'wp-simple-firewall' ) );
105
+
106
  return [
107
+ 'message' => __( 'Your backup login codes have been deleted.', 'wp-simple-firewall' ),
108
  'success' => true
109
  ];
110
  }
111
 
112
+ private function ajaxExec_UserGaToggle() :array {
113
+ /** @var ModCon $mod */
114
+ $mod = $this->getMod();
115
+ /** @var TwoFactor\Provider\GoogleAuth $provider */
116
+ $provider = $mod->getLoginIntentController()->getProviders()[ TwoFactor\Provider\GoogleAuth::SLUG ];
117
+
118
+ $otp = Services::Request()->post( 'ga_otp', '' );
119
+ $result = empty( $otp ) ?
120
+ $provider->removeGaOnAccount( Services::WpUsers()->getCurrentWpUser() )
121
+ : $provider->activateGaOnAccount( Services::WpUsers()->getCurrentWpUser(), $otp );
122
+
123
+ return [
124
+ 'success' => $result->success,
125
+ 'message' => $result->success ? $result->msg_text : $result->error_text,
126
+ 'page_reload' => true
127
+ ];
128
+ }
129
+
130
+ private function ajaxExec_User2faEmailToggle() :array {
131
+ /** @var ModCon $mod */
132
+ $mod = $this->getMod();
133
+ /** @var TwoFactor\Provider\Email $provider */
134
+ $provider = $mod->getLoginIntentController()->getProviders()[ TwoFactor\Provider\Email::SLUG ];
135
+
136
+ $turnOn = Services::Request()->post( 'direction' ) == 'on';
137
+ $provider->setProfileValidated( Services::WpUsers()->getCurrentWpUser(), $turnOn );
138
+ $success = $turnOn === $provider->isProfileActive( Services::WpUsers()->getCurrentWpUser() );
139
+
140
+ if ( $success ) {
141
+ $msg = $turnOn ? __( 'Email 2FA activated.', 'wp-simple-firewall' )
142
+ : __( 'Email 2FA deactivated.', 'wp-simple-firewall' );
143
+ }
144
+ else {
145
+ $msg = __( "Email 2FA settings couldn't be changed.", 'wp-simple-firewall' );
146
+ }
147
+
148
+ return [
149
+ 'success' => $success,
150
+ 'message' => $msg,
151
+ 'page_reload' => true
152
+ ];
153
+ }
154
+
155
  private function ajaxExec_Disable2faEmail() :array {
156
  /** @var ModCon $mod */
157
  $mod = $this->getMod();
163
  ];
164
  }
165
 
166
+ private function ajaxExec_ProfileU2fAdd() :array {
167
+ /** @var ModCon $mod */
168
+ $mod = $this->getMod();
169
+ /** @var TwoFactor\Provider\U2F $provider */
170
+ $provider = $mod->getLoginIntentController()->getProviders()[ TwoFactor\Provider\U2F::SLUG ];
171
+
172
+ $u2fReg = Services::Request()->post( 'icwp_wpsf_new_u2f_response' );
173
+ if ( empty( $u2fReg ) ) {
174
+ $response = [
175
+ 'success' => false,
176
+ 'message' => __( 'U2F registration details were missing in the request.', 'wp-simple-firewall' ),
177
+ 'page_reload' => true
178
+ ];
179
+ }
180
+ else {
181
+ $result = $provider->addNewRegistration( Services::WpUsers()->getCurrentWpUser(), $u2fReg );
182
+ $response = [
183
+ 'success' => $result->success,
184
+ 'message' => $result->success ? $result->msg_text : $result->error_text,
185
+ 'page_reload' => true
186
+ ];
187
+ }
188
+ return $response;
189
+ }
190
+
191
  private function ajaxExec_ProfileU2fRemove() :array {
192
  /** @var ModCon $mod */
193
  $mod = $this->getMod();
194
+ /** @var TwoFactor\Provider\U2F $provider */
195
+ $provider = $mod->getLoginIntentController()
196
+ ->getProviders()[ TwoFactor\Provider\U2F::SLUG ];
197
 
198
  $key = Services::Request()->post( 'u2fid' );
199
  if ( !empty( $key ) ) {
200
+ $provider->removeRegisteredU2fId( Services::WpUsers()->getCurrentWpUser(), $key );
 
 
201
  }
202
  return [
203
  'success' => !empty( $key ),
206
  ];
207
  }
208
 
209
+ private function ajaxExec_UserYubikeyToggle() :array {
 
 
 
210
  /** @var ModCon $mod */
211
  $mod = $this->getMod();
212
+ /** @var TwoFactor\Provider\Yubikey $provider */
213
+ $provider = $mod->getLoginIntentController()
214
+ ->getProviders()[ TwoFactor\Provider\Yubikey::SLUG ];
215
 
216
+ $otp = Services::Request()->post( 'otp', '' );
217
+ $result = $provider->toggleRegisteredYubiID( Services::WpUsers()->getCurrentWpUser(), $otp );
 
 
218
  return [
219
+ 'success' => $result->success,
220
+ 'message' => $result->success ? $result->msg_text : $result->error_text,
221
  'page_reload' => true
222
  ];
223
  }
224
 
225
+ private function ajaxExec_ResendEmailVerification() :array {
 
 
 
226
  /** @var ModCon $mod */
227
  $mod = $this->getMod();
228
  /** @var Options $opts */
230
  $success = true;
231
 
232
  if ( !$opts->isEnabledEmailAuth() ) {
233
+ $msg = __( 'Email 2FA option is not currently enabled.', 'wp-simple-firewall' );
234
  $success = false;
235
  }
236
  elseif ( $opts->getIfCanSendEmailVerified() ) {
237
+ $msg = __( 'Email sending has already been verified.', 'wp-simple-firewall' );
238
  }
239
  else {
240
+ $msg = __( 'Verification email resent.', 'wp-simple-firewall' );
241
  $mod->setIfCanSendEmail( false )
242
  ->sendEmailVerifyCanSend();
243
  }
244
 
245
  return [
246
  'success' => $success,
247
+ 'message' => $msg
248
  ];
249
  }
250
  }
src/lib/src/Modules/LoginGuard/Insights/OverviewCards.php CHANGED
@@ -7,24 +7,16 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
7
 
8
  class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
9
 
10
- public function build() :array {
11
  /** @var LoginGuard\ModCon $mod */
12
  $mod = $this->getMod();
13
  /** @var LoginGuard\Options $opts */
14
  $opts = $this->getOptions();
15
 
16
- $cardSection = [
17
- 'title' => __( 'Login Guard', 'wp-simple-firewall' ),
18
- 'subtitle' => __( 'Brute Force Protection & Identity Verification', 'wp-simple-firewall' ),
19
- 'href_options' => $mod->getUrl_AdminPage()
20
- ];
21
-
22
  $cards = [];
23
 
24
- if ( !$mod->isModOptEnabled() ) {
25
- $cards[ 'mod' ] = $this->getModDisabledCard();
26
- }
27
- else {
28
  $hasBotCheck = $opts->isEnabledAntiBot() || $opts->isEnabledGaspCheck() || $mod->isEnabledCaptcha();
29
 
30
  $boLogin = $hasBotCheck && $opts->isProtectLogin();
@@ -67,7 +59,14 @@ class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
67
  ];
68
  }
69
 
70
- $cardSection[ 'cards' ] = $cards;
71
- return [ 'login_protect' => $cardSection ];
 
 
 
 
 
 
 
72
  }
73
  }
7
 
8
  class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
9
 
10
+ protected function buildModCards() :array {
11
  /** @var LoginGuard\ModCon $mod */
12
  $mod = $this->getMod();
13
  /** @var LoginGuard\Options $opts */
14
  $opts = $this->getOptions();
15
 
 
 
 
 
 
 
16
  $cards = [];
17
 
18
+ if ( $mod->isModOptEnabled() ) {
19
+
 
 
20
  $hasBotCheck = $opts->isEnabledAntiBot() || $opts->isEnabledGaspCheck() || $mod->isEnabledCaptcha();
21
 
22
  $boLogin = $hasBotCheck && $opts->isProtectLogin();
59
  ];
60
  }
61
 
62
+ return $cards;
63
+ }
64
+
65
+ protected function getSectionTitle() :string {
66
+ return __( 'Login Guard', 'wp-simple-firewall' );
67
+ }
68
+
69
+ protected function getSectionSubTitle() :string {
70
+ return __( 'Brute Force Protection & Identity Verification', 'wp-simple-firewall' );
71
  }
72
  }
src/lib/src/Modules/LoginGuard/Lib/AntiBot/AntibotSetup.php CHANGED
@@ -2,17 +2,13 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\AntiBot;
4
 
5
- use FernleafSystems\Utilities\Logic\ExecOnce;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\AntiBot;
8
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
9
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Lib\Captcha\CaptchaConfigVO;
10
  use FernleafSystems\Wordpress\Services\Services;
11
 
12
- class AntibotSetup {
13
-
14
- use ModConsumer;
15
- use ExecOnce;
16
 
17
  protected function canRun() :bool {
18
  return !Services::WpUsers()->isUserLoggedIn();
@@ -30,12 +26,7 @@ class AntibotSetup {
30
  ->setMod( $mod );
31
  }
32
 
33
- if ( $opts->isEnabledAntiBot() ) {
34
- $providers[] = ( new AntiBot\ProtectionProviders\AntiBot() )
35
- ->setMod( $mod );
36
- }
37
- else {
38
-
39
  if ( $opts->isEnabledGaspCheck() ) {
40
  $providers[] = ( new AntiBot\ProtectionProviders\GaspJs() )
41
  ->setMod( $mod );
@@ -96,7 +87,7 @@ class AntibotSetup {
96
  }
97
 
98
  foreach ( $formProviders as $form ) {
99
- $form->setMod( $mod )->run();
100
  }
101
  }
102
  }
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\AntiBot;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\AntiBot;
 
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Lib\Captcha\CaptchaConfigVO;
9
  use FernleafSystems\Wordpress\Services\Services;
10
 
11
+ class AntibotSetup extends ExecOnceModConsumer {
 
 
 
12
 
13
  protected function canRun() :bool {
14
  return !Services::WpUsers()->isUserLoggedIn();
26
  ->setMod( $mod );
27
  }
28
 
29
+ if ( !$opts->isEnabledAntiBot() ) {
 
 
 
 
 
30
  if ( $opts->isEnabledGaspCheck() ) {
31
  $providers[] = ( new AntiBot\ProtectionProviders\GaspJs() )
32
  ->setMod( $mod );
87
  }
88
 
89
  foreach ( $formProviders as $form ) {
90
+ $form->setMod( $mod )->execute();
91
  }
92
  }
93
  }
src/lib/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/BaseFormProvider.php CHANGED
@@ -2,13 +2,13 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\AntiBot\FormProviders;
4
 
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
  use FernleafSystems\Wordpress\Services\Services;
8
 
9
- abstract class BaseFormProvider {
10
-
11
- use ModConsumer;
12
 
13
  /**
14
  * @var string
@@ -25,21 +25,21 @@ abstract class BaseFormProvider {
25
  */
26
  private static $aProtectionProviders;
27
 
28
- public static function SetProviders( array $aProviders ) {
29
- self::$aProtectionProviders = $aProviders;
30
  }
31
 
32
  /**
33
- * @return true
34
  * @throws \Exception
35
  */
36
  protected function checkProviders() {
37
- if ( is_array( self::$aProtectionProviders ) ) {
38
- foreach ( self::$aProtectionProviders as $oProvider ) {
39
- $oProvider->performCheck( $this );
40
- }
41
  }
42
- return true;
 
 
 
43
  }
44
 
45
  protected function checkThenDie() {
@@ -51,7 +51,7 @@ abstract class BaseFormProvider {
51
  }
52
  }
53
 
54
- public function run() {
55
  /** @var LoginGuard\Options $opts */
56
  $opts = $this->getOptions();
57
  if ( $opts->isProtectLogin() ) {
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\AntiBot\FormProviders;
4
 
5
+ use FernleafSystems\Utilities\Logic\ExecOnce;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
9
  use FernleafSystems\Wordpress\Services\Services;
10
 
11
+ abstract class BaseFormProvider extends ExecOnceModConsumer {
 
 
12
 
13
  /**
14
  * @var string
25
  */
26
  private static $aProtectionProviders;
27
 
28
+ public static function SetProviders( array $providers ) {
29
+ self::$aProtectionProviders = $providers;
30
  }
31
 
32
  /**
 
33
  * @throws \Exception
34
  */
35
  protected function checkProviders() {
36
+ foreach ( $this->getProtectionProviders() as $provider ) {
37
+ $provider->performCheck( $this );
 
 
38
  }
39
+ }
40
+
41
+ protected function getProtectionProviders() :array {
42
+ return is_array( self::$aProtectionProviders ) ? self::$aProtectionProviders : [];
43
  }
44
 
45
  protected function checkThenDie() {
51
  }
52
  }
53
 
54
+ protected function run() {
55
  /** @var LoginGuard\Options $opts */
56
  $opts = $this->getOptions();
57
  if ( $opts->isProtectLogin() ) {
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/LoginIntentPage.php CHANGED
@@ -19,12 +19,12 @@ class LoginIntentPage {
19
  * @return string
20
  */
21
  public function renderForm() {
22
- $oIC = $this->getMfaCon();
23
  /** @var LoginGuard\ModCon $mod */
24
- $mod = $oIC->getMod();
25
  /** @var LoginGuard\Options $opts */
26
- $opts = $oIC->getOptions();
27
- $con = $oIC->getCon();
28
  $req = Services::Request();
29
  $WP = Services::WpGeneral();
30
 
@@ -83,7 +83,7 @@ class LoginIntentPage {
83
  function ( $oProvider ) {
84
  return $oProvider->getFormField();
85
  },
86
- $oIC->getProvidersForUser( Services::WpUsers()->getCurrentWpUser(), true )
87
  ) ),
88
  'time_remaining' => $nTimeRemaining,
89
  'message_type' => 'info',
@@ -96,7 +96,7 @@ class LoginIntentPage {
96
  ],
97
  'flags' => [
98
  'can_skip_mfa' => $opts->isMfaSkip(),
99
- 'show_branded_links' => !$mod->isEnabledWhitelabel(), // white label mitigation
100
  ]
101
  ];
102
 
@@ -137,7 +137,7 @@ class LoginIntentPage {
137
  'favicon' => $con->urls->forImage( 'pluginlogo_24x24.png' ),
138
  ],
139
  'flags' => [
140
- 'show_branded_links' => !$mod->isEnabledWhitelabel(), // white label mitigation
141
  'has_u2f' => isset( $oIC->getProvidersForUser(
142
  Services::WpUsers()->getCurrentWpUser(), true )[ LoginGuard\Lib\TwoFactor\Provider\U2F::SLUG ] )
143
  ],
@@ -154,7 +154,7 @@ class LoginIntentPage {
154
  'src' => $con->urls->forJs( 'u2f-bundle.js' ),
155
  ],
156
  [
157
- 'src' => $con->urls->forJs( 'u2f-frontend.js' ),
158
  ]
159
  ]
160
  ];
19
  * @return string
20
  */
21
  public function renderForm() {
22
+ $mfaCon = $this->getMfaCon();
23
  /** @var LoginGuard\ModCon $mod */
24
+ $mod = $mfaCon->getMod();
25
  /** @var LoginGuard\Options $opts */
26
+ $opts = $mfaCon->getOptions();
27
+ $con = $mfaCon->getCon();
28
  $req = Services::Request();
29
  $WP = Services::WpGeneral();
30
 
83
  function ( $oProvider ) {
84
  return $oProvider->getFormField();
85
  },
86
+ $mfaCon->getProvidersForUser( Services::WpUsers()->getCurrentWpUser(), true )
87
  ) ),
88
  'time_remaining' => $nTimeRemaining,
89
  'message_type' => 'info',
96
  ],
97
  'flags' => [
98
  'can_skip_mfa' => $opts->isMfaSkip(),
99
+ 'show_branded_links' => !$con->getModule_SecAdmin()->getWhiteLabelController()->isEnabled(),
100
  ]
101
  ];
102
 
137
  'favicon' => $con->urls->forImage( 'pluginlogo_24x24.png' ),
138
  ],
139
  'flags' => [
140
+ 'show_branded_links' => !$con->getModule_SecAdmin()->getWhiteLabelController()->isEnabled(),
141
  'has_u2f' => isset( $oIC->getProvidersForUser(
142
  Services::WpUsers()->getCurrentWpUser(), true )[ LoginGuard\Lib\TwoFactor\Provider\U2F::SLUG ] )
143
  ],
154
  'src' => $con->urls->forJs( 'u2f-bundle.js' ),
155
  ],
156
  [
157
+ 'src' => $con->urls->forJs( 'login/u2f.js' ),
158
  ]
159
  ]
160
  ];
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\Utilities\Logic\ExecOnce;
6
  use FernleafSystems\Wordpress\Plugin\Shield;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Session\Update;
@@ -18,7 +19,7 @@ class MfaController {
18
  /**
19
  * @var Provider\BaseProvider[]
20
  */
21
- private $aProviders;
22
 
23
  /**
24
  * @var LoginIntentPage
@@ -26,8 +27,8 @@ class MfaController {
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
  }
@@ -43,6 +44,7 @@ class MfaController {
43
  ( new UserProfile() )
44
  ->setMfaController( $this )
45
  ->run();
 
46
 
47
  add_shortcode( 'SHIELD_2FA_LOGIN', function () {
48
  return $this->getLoginIntentPageHandler()->renderForm();
@@ -59,7 +61,7 @@ class MfaController {
59
  if ( $this->isSubjectToLoginIntent( $user )
60
  && !Services::WpUsers()->isAppPasswordAuth() && !$this->canUserMfaSkip( $user ) ) {
61
 
62
- $providers = $this->getProvidersForUser( $user );
63
  if ( !empty( $providers ) ) {
64
  foreach ( $providers as $provider ) {
65
  $provider->captureLoginAttempt( $user );
@@ -87,16 +89,21 @@ class MfaController {
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' );
@@ -104,6 +111,7 @@ class MfaController {
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.' );
@@ -149,38 +157,43 @@ class MfaController {
149
  * @return Provider\BaseProvider[]
150
  */
151
  public function getProviders() :array {
152
- if ( !is_array( $this->aProviders ) ) {
153
- $this->aProviders = [
154
- Provider\Email::SLUG => ( new Provider\Email() )->setMod( $this->getMod() ),
155
- Provider\GoogleAuth::SLUG => ( new Provider\GoogleAuth() )->setMod( $this->getMod() ),
156
- Provider\Yubikey::SLUG => ( new Provider\Yubikey() )->setMod( $this->getMod() ),
157
- Provider\Backup::SLUG => ( new Provider\Backup() )->setMod( $this->getMod() ),
158
- Provider\U2F::SLUG => ( new Provider\U2F() )->setMod( $this->getMod() ),
159
- ];
 
 
 
 
 
160
  }
161
- return $this->aProviders;
162
  }
163
 
164
  /**
165
  * Ensures that BackupCode provider isn't supplied on its own, and the user profile is setup for each.
166
  * @param \WP_User $user
167
- * @param bool $bOnlyActiveProfiles
168
  * @return Provider\BaseProvider[]
169
  */
170
- public function getProvidersForUser( $user, $bOnlyActiveProfiles = false ) {
171
  $Ps = array_filter( $this->getProviders(),
172
- function ( $oProvider ) use ( $user, $bOnlyActiveProfiles ) {
173
- /** @var Provider\BaseProvider $oProvider */
174
- return $oProvider->isProviderAvailableToUser( $user )
175
- && ( !$bOnlyActiveProfiles || $oProvider->isProfileActive( $user ) );
176
  }
177
  );
178
 
179
  // Neither BackupCode NOR U2F should EVER be the only 1 provider available.
180
  if ( count( $Ps ) === 1 ) {
181
- /** @var Provider\BaseProvider $oFirst */
182
- $oFirst = reset( $Ps );
183
- if ( !$oFirst::STANDALONE ) {
184
  $Ps = [];
185
  }
186
  }
@@ -245,9 +258,8 @@ class MfaController {
245
 
246
  /**
247
  * assume that a user is logged in.
248
- * @return bool
249
  */
250
- private function validateLoginIntentRequest() {
251
  try {
252
  $valid = ( new ValidateLoginIntentRequest() )
253
  ->setMfaController( $this )
@@ -278,6 +290,27 @@ class MfaController {
278
  return count( $this->getProvidersForUser( $user, true ) ) > 0;
279
  }
280
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
281
  private function getLoginIntentExpiresAt() :int {
282
  return $this->getCon()
283
  ->getModule_Sessions()
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor;
4
 
5
+ use FernleafSystems\Utilities\Data\Response\StdResponse;
6
  use FernleafSystems\Utilities\Logic\ExecOnce;
7
  use FernleafSystems\Wordpress\Plugin\Shield;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Session\Update;
19
  /**
20
  * @var Provider\BaseProvider[]
21
  */
22
+ private $providers;
23
 
24
  /**
25
  * @var LoginIntentPage
27
  private $oLoginIntentPageHandler;
28
 
29
  protected function run() {
30
+ add_action( 'init', [ $this, 'onWpInit' ] );
31
+ add_action( 'wp_loaded', [ $this, 'onWpLoaded' ] );
32
  $this->setupLoginCaptureHooks();
33
  $this->handleLoginLink();
34
  }
44
  ( new UserProfile() )
45
  ->setMfaController( $this )
46
  ->run();
47
+ ( new MfaProfilesController() )->setMfaController( $this )->execute();
48
 
49
  add_shortcode( 'SHIELD_2FA_LOGIN', function () {
50
  return $this->getLoginIntentPageHandler()->renderForm();
61
  if ( $this->isSubjectToLoginIntent( $user )
62
  && !Services::WpUsers()->isAppPasswordAuth() && !$this->canUserMfaSkip( $user ) ) {
63
 
64
+ $providers = $this->getProvidersForUser( $user, true );
65
  if ( !empty( $providers ) ) {
66
  foreach ( $providers as $provider ) {
67
  $provider->captureLoginAttempt( $user );
89
  } );
90
  }
91
 
92
+ /**
93
+ * @throws \Exception
94
+ */
95
  private function processEmail2faLink() {
96
  $req = Services::Request();
97
  $user = sanitize_user( $req->query( 'user' ) );
98
  if ( empty( $user ) ) {
99
  throw new \Exception( 'Not valid data.' );
100
  }
101
+
102
  $user = Services::WpUsers()->getUserByUsername( $user );
103
  if ( !$user instanceof \WP_User ) {
104
  throw new \Exception( 'Not valid data.' );
105
  }
106
+
107
  $providers = $this->getProvidersForUser( $user, true );
108
  if ( !isset( $providers[ Provider\Email::SLUG ] ) ) {
109
  throw new \Exception( 'Not a support provider' );
111
  if ( !$providers[ Provider\Email::SLUG ]->validateLoginIntent( $user ) ) {
112
  throw new \Exception( 'Login validation failed.' );
113
  }
114
+
115
  $providers[ Provider\Email::SLUG ]->postSuccessActions( $user );
116
  if ( (int)$user->ID !== (int)Services::WpUsers()->getCurrentWpUserId() ) {
117
  throw new \Exception( 'Action completed successfully. Please refresh your browser where you logged-in.' );
157
  * @return Provider\BaseProvider[]
158
  */
159
  public function getProviders() :array {
160
+ if ( !is_array( $this->providers ) ) {
161
+ $this->providers = array_map(
162
+ function ( $provider ) {
163
+ return $provider->setMod( $this->getMod() );
164
+ },
165
+ [
166
+ Provider\Email::SLUG => new Provider\Email(),
167
+ Provider\GoogleAuth::SLUG => new Provider\GoogleAuth(),
168
+ Provider\Yubikey::SLUG => new Provider\Yubikey(),
169
+ Provider\BackupCodes::SLUG => new Provider\BackupCodes(),
170
+ Provider\U2F::SLUG => new Provider\U2F(),
171
+ ]
172
+ );
173
  }
174
+ return $this->providers;
175
  }
176
 
177
  /**
178
  * Ensures that BackupCode provider isn't supplied on its own, and the user profile is setup for each.
179
  * @param \WP_User $user
180
+ * @param bool $onlyActiveProfiles
181
  * @return Provider\BaseProvider[]
182
  */
183
+ public function getProvidersForUser( \WP_User $user, $onlyActiveProfiles = false ) :array {
184
  $Ps = array_filter( $this->getProviders(),
185
+ function ( $provider ) use ( $user, $onlyActiveProfiles ) {
186
+ /** @var Provider\BaseProvider $provider */
187
+ return $provider->isProviderAvailableToUser( $user )
188
+ && ( !$onlyActiveProfiles || $provider->isProfileActive( $user ) );
189
  }
190
  );
191
 
192
  // Neither BackupCode NOR U2F should EVER be the only 1 provider available.
193
  if ( count( $Ps ) === 1 ) {
194
+ /** @var Provider\BaseProvider $first */
195
+ $first = reset( $Ps );
196
+ if ( !$first::STANDALONE ) {
197
  $Ps = [];
198
  }
199
  }
258
 
259
  /**
260
  * assume that a user is logged in.
 
261
  */
262
+ private function validateLoginIntentRequest() :bool {
263
  try {
264
  $valid = ( new ValidateLoginIntentRequest() )
265
  ->setMfaController( $this )
290
  return count( $this->getProvidersForUser( $user, true ) ) > 0;
291
  }
292
 
293
+ public function removeAllFactorsForUser( int $userID ) :StdResponse {
294
+ $result = new StdResponse();
295
+
296
+ $user = Services::WpUsers()->getUserById( $userID );
297
+ if ( $user instanceof \WP_User ) {
298
+ foreach ( $this->getProvidersForUser( $user, true ) as $provider ) {
299
+ $provider->remove( $user );
300
+ }
301
+ $result->success = true;
302
+ $result->msg_text = sprintf( __( 'All MFA providers removed from user with ID %s.' ),
303
+ $userID );
304
+ }
305
+ else {
306
+ $result->success = false;
307
+ $result->error_text = sprintf( __( "User doesn't exist with ID %s." ),
308
+ $userID );
309
+ }
310
+
311
+ return $result;
312
+ }
313
+
314
  private function getLoginIntentExpiresAt() :int {
315
  return $this->getCon()
316
  ->getModule_Sessions()
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/MfaProfilesController.php ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
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\Controller\Assets\Enqueue;
8
+ use FernleafSystems\Wordpress\Services\Services;
9
+
10
+ class MfaProfilesController {
11
+
12
+ use MfaControllerConsumer;
13
+ use ExecOnce;
14
+
15
+ private $rendered = false;
16
+
17
+ private $isFrontend = false;
18
+
19
+ protected function run() {
20
+ $this->defineShortcodes();
21
+ if ( Services::WpUsers()->isUserLoggedIn() ) {
22
+ add_action( 'wp', function () {
23
+ $this->enqueueAssets( true );
24
+ } );
25
+ add_action( 'admin_init', function () {
26
+ $this->enqueueAssets( false );
27
+ } );
28
+ }
29
+ }
30
+
31
+ private function enqueueAssets( bool $isFrontend ) {
32
+ $this->isFrontend = $isFrontend;
33
+ add_filter( 'shield/custom_enqueues', function ( array $enqueues, $hook = '' ) {
34
+
35
+ if ( $this->isFrontend || in_array( $hook, [ 'profile.php', 'user-edit.php' ] ) ) {
36
+ $enqueues[ Enqueue::JS ][] = 'shield/userprofile';
37
+ $enqueues[ Enqueue::CSS ][] = 'shield/dialog';
38
+
39
+ if ( $this->isFrontend ) {
40
+ add_filter( 'shield/custom_dequeues', function ( $assets ) {
41
+ if ( !$this->rendered ) {
42
+ $assets[ Enqueue::JS ][] = 'shield/userprofile';
43
+ $assets[ Enqueue::CSS ][] = 'shield/dialog';
44
+ }
45
+ return $assets;
46
+ } );
47
+ }
48
+
49
+ add_filter( 'shield/custom_localisations', function ( array $localz ) {
50
+ $mfaCon = $this->getMfaCon();
51
+ $user = Services::WpUsers()->getCurrentWpUser();
52
+ $providers = $user instanceof \WP_User ? $mfaCon->getProvidersForUser( $user ) : [];
53
+ $localz[] = [
54
+ 'shield/userprofile',
55
+ 'shield_vars_userprofile',
56
+ [
57
+ 'ajax' => [
58
+ 'mfa_remove_all' => $mfaCon->getMod()->getAjaxActionData( 'mfa_remove_all' )
59
+ ],
60
+ 'vars' => [
61
+ 'providers' => array_map( function ( $provider ) {
62
+ return $provider->getJavascriptVars();
63
+ }, $providers )
64
+ ],
65
+ 'strings' => [
66
+ 'are_you_sure' => __( 'Are you sure?', 'wp-simple-firewall' )
67
+ ],
68
+ ]
69
+ ];
70
+ return $localz;
71
+ } );
72
+ }
73
+
74
+ return $enqueues;
75
+ }, 10, $this->isFrontend ? 1 : 2 );
76
+ }
77
+
78
+ private function loadUserProfileMFA( $attributes = [] ) :string {
79
+ $this->rendered = true;
80
+ return ( new Profiles\RenderCustomForms() )
81
+ ->setMfaController( $this->getMfaCon() )
82
+ ->setWpUser( Services::WpUsers()->getCurrentWpUser() )
83
+ ->render( is_array( $attributes ) ? $attributes : [] );
84
+ }
85
+
86
+ private function defineShortcodes() {
87
+ if ( $this->getMfaCon()->getCon()->isPremiumActive() ) {
88
+ add_shortcode( 'SHIELD_USER_PROFILE_MFA', function ( $attributes ) {
89
+ return $this->loadUserProfileMFA( $attributes );
90
+ } );
91
+ }
92
+ }
93
+ }
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Profiles/CustomForms.php DELETED
@@ -1,67 +0,0 @@
1
- <?php
2
-
3
- namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor\Profiles;
4
-
5
- use FernleafSystems\Utilities\Logic\ExecOnce;
6
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor\MfaControllerConsumer;
7
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor\Provider\BaseProvider;
8
- use FernleafSystems\Wordpress\Plugin\Shield\Utilities\Consumer\WpUserConsumer;
9
-
10
- class CustomForms {
11
-
12
- use ExecOnce;
13
- use MfaControllerConsumer;
14
- use WpUserConsumer;
15
-
16
- /**
17
- * @var BaseProvider[]
18
- */
19
- private $aWorkingProviders = [];
20
-
21
- public function run() {
22
- // Enqueue Javascript.
23
- add_action( 'wp_enqueue_scripts', function () {
24
- $this->enqueueAssets();
25
- }, 0 );
26
- add_action( 'wp_footer', function () {
27
- $this->maybeDequeueAssets();
28
- }, 0 );
29
- add_action( 'custom_profile_form_output', function ( array $aProviders ) {
30
- $this->renderCustomProfileFormOutput( $aProviders );
31
- } );
32
- }
33
-
34
- /**
35
- * @param string[] $aPs - list of limited provider slugs
36
- */
37
- private function renderCustomProfileFormOutput( array $aPs ) {
38
- $oMC = $this->getMfaCon();
39
- $user = $this->getWpUser();
40
-
41
- $aProviders = $oMC->getProvidersForUser( $user, true );
42
- if ( !empty( $aPs ) ) {
43
- $aProviders = array_filter(
44
- $aProviders,
45
- function ( $oP ) use ( $aPs ) {
46
- return in_array( $oP::SLUG, array_map( 'strtolower', $aPs ) );
47
- }
48
- );
49
- }
50
-
51
- if ( !empty( $aProviders ) ) {
52
- $this->aWorkingProviders = $aProviders;
53
- foreach ( $aProviders as $oP ) {
54
- }
55
- }
56
- }
57
-
58
- private function enqueueAssets() {
59
- //enqueue in footer
60
- }
61
-
62
- private function maybeDequeueAssets() {
63
- if ( empty( $this->aWorkingProviders ) ) {
64
- //dequeue
65
- }
66
- }
67
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Profiles/RenderCustomForms.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor\Profiles;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor\MfaControllerConsumer;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Utilities\Consumer\WpUserConsumer;
7
+
8
+ class RenderCustomForms {
9
+
10
+ use MfaControllerConsumer;
11
+ use WpUserConsumer;
12
+
13
+ private $attributes;
14
+
15
+ public function render( array $attributes ) :string {
16
+ $this->attributes = $attributes;
17
+ return $this->getMfaCon()
18
+ ->getMod()
19
+ ->renderTemplate( '/user/profile/mfa/main.twig', $this->buildRenderData() );
20
+ }
21
+
22
+ private function buildRenderData() :array {
23
+ $mfaCon = $this->getMfaCon();
24
+ $con = $mfaCon->getCon();
25
+ $pluginName = $con->getHumanName();
26
+
27
+ $user = $this->getWpUser();
28
+ $providers = $user instanceof \WP_User ? $mfaCon->getProvidersForUser( $user ) : [];
29
+ $providerRenders = $user instanceof \WP_User ?
30
+ array_map( function ( $provider ) {
31
+ return $provider->renderUserProfileCustomForm( $this->getWpUser() );
32
+ }, $providers )
33
+ : [];
34
+
35
+ $data = [
36
+ 'content' => [
37
+ 'providers' => $providerRenders,
38
+ ],
39
+ 'flags' => [
40
+ 'has_providers' => !empty( $providers ),
41
+ 'logged_in' => $user instanceof \WP_User,
42
+ ],
43
+ 'strings' => [
44
+ 'title' => sprintf( __( '%s MFA Options', 'wp-simple-firewall' ), $pluginName ),
45
+ 'not_logged_in' => __( 'Not currently logged-in.', 'wp-simple-firewall' ),
46
+ 'no_providers' => __( 'There are currently no 2FA providers available on your account.', 'wp-simple-firewall' ),
47
+ ],
48
+ 'vars' => [
49
+ 'provider_data' => ''
50
+ ],
51
+ ];
52
+
53
+ return apply_filters( 'shield/render_data_custom_profiles_mfa', $data );
54
+ }
55
+ }
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/{Backup.php → BackupCodes.php} RENAMED
@@ -5,15 +5,27 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFact
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
6
  use FernleafSystems\Wordpress\Services\Services;
7
 
8
- class Backup extends BaseProvider {
9
 
10
  const SLUG = 'backupcode';
11
  const STANDALONE = false;
12
 
13
- public function renderUserProfileOptions( \WP_User $user ) :string {
14
- $oCon = $this->getCon();
 
15
 
16
- $aData = [
 
 
 
 
 
 
 
 
 
 
 
17
  'strings' => [
18
  'button_gen_code' => __( 'Generate ONE-Time Backup 2FA Login Code', 'wp-simple-firewall' ),
19
  'button_del_code' => __( 'Delete Login Backup Code', 'wp-simple-firewall' ),
@@ -28,30 +40,17 @@ class Backup extends BaseProvider {
28
  'title' => __( 'Backup Login Code', 'wp-simple-firewall' ),
29
  'cant_add_other_user' => sprintf( __( "Sorry, %s may not be added to another user's account.", 'wp-simple-firewall' ), 'Backup Codes' ),
30
  'cant_remove_admins' => sprintf( __( "Sorry, %s may only be removed from another user's account by a Security Administrator.", 'wp-simple-firewall' ), __( 'Backup Codes', 'wp-simple-firewall' ) ),
31
- 'provided_by' => sprintf( __( 'Provided by %s', 'wp-simple-firewall' ), $oCon->getHumanName() ),
 
32
  'remove_more_info' => sprintf( __( 'Understand how to remove Google Authenticator', 'wp-simple-firewall' ) )
33
  ]
34
  ];
35
-
36
- return $this->getMod()
37
- ->renderTemplate(
38
- '/snippets/user/profile/mfa/mfa_backup.twig',
39
- Services::DataManipulation()->mergeArraysRecursive( $this->getCommonData( $user ), $aData ),
40
- true
41
- );
42
- }
43
-
44
- /**
45
- * @inheritDoc
46
- */
47
- public function renderUserEditProfileOptions( \WP_User $user ) {
48
- // Allow no actions to be taken on other user profiles
49
  }
50
 
51
  /**
52
  * @return array
53
  */
54
- public function getFormField() {
55
  return [
56
  'name' => $this->getLoginFormParameter(),
57
  'type' => 'text',
@@ -137,22 +136,23 @@ class Backup extends BaseProvider {
137
  * @param \WP_User $user
138
  */
139
  private function sendBackupCodeUsedEmail( \WP_User $user ) {
140
- $aEmailContent = [
141
- __( 'This is a quick notice to inform you that your Backup Login code was just used.', 'wp-simple-firewall' ),
142
- __( "Your WordPress account had only 1 backup login code.", 'wp-simple-firewall' )
143
- .' '.__( "You must go to your profile and regenerate a new code if you want to use this method again.", 'wp-simple-firewall' ),
144
- '',
145
- sprintf( '<strong>%s</strong>', __( 'Login Details', 'wp-simple-firewall' ) ),
146
- sprintf( '%s: %s', __( 'URL', 'wp-simple-firewall' ), Services::WpGeneral()->getHomeUrl() ),
147
- sprintf( '%s: %s', __( 'Username', 'wp-simple-firewall' ), $user->user_login ),
148
- sprintf( '%s: %s', __( 'IP Address', 'wp-simple-firewall' ), Services::IP()->getRequestIp() ),
149
- '',
150
- __( 'Thank You.', 'wp-simple-firewall' ),
151
- ];
152
-
153
- $sTitle = sprintf( __( "Notice: %s", 'wp-simple-firewall' ), __( "Backup Login Code Just Used", 'wp-simple-firewall' ) );
154
  $this->getMod()
155
  ->getEmailProcessor()
156
- ->sendEmailWithWrap( $user->user_email, $sTitle, $aEmailContent );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
  }
158
  }
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
6
  use FernleafSystems\Wordpress\Services\Services;
7
 
8
+ class BackupCodes extends BaseProvider {
9
 
10
  const SLUG = 'backupcode';
11
  const STANDALONE = false;
12
 
13
+ public function getProviderName() :string {
14
+ return 'Backup Codes';
15
+ }
16
 
17
+ public function getJavascriptVars() :array {
18
+ return [
19
+ 'ajax' => [
20
+ 'gen_backup_codes' => $this->getMod()->getAjaxActionData( 'gen_backup_codes' ),
21
+ 'del_backup_codes' => $this->getMod()->getAjaxActionData( 'del_backup_codes' ),
22
+ ],
23
+ ];
24
+ }
25
+
26
+ protected function getProviderSpecificRenderData( \WP_User $user ) :array {
27
+ error_log( var_export( $this->hasValidatedProfile( $user ), true ) );
28
+ return [
29
  'strings' => [
30
  'button_gen_code' => __( 'Generate ONE-Time Backup 2FA Login Code', 'wp-simple-firewall' ),
31
  'button_del_code' => __( 'Delete Login Backup Code', 'wp-simple-firewall' ),
40
  'title' => __( 'Backup Login Code', 'wp-simple-firewall' ),
41
  'cant_add_other_user' => sprintf( __( "Sorry, %s may not be added to another user's account.", 'wp-simple-firewall' ), 'Backup Codes' ),
42
  'cant_remove_admins' => sprintf( __( "Sorry, %s may only be removed from another user's account by a Security Administrator.", 'wp-simple-firewall' ), __( 'Backup Codes', 'wp-simple-firewall' ) ),
43
+ 'provided_by' => sprintf( __( 'Provided by %s', 'wp-simple-firewall' ), $this->getCon()
44
+ ->getHumanName() ),
45
  'remove_more_info' => sprintf( __( 'Understand how to remove Google Authenticator', 'wp-simple-firewall' ) )
46
  ]
47
  ];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  }
49
 
50
  /**
51
  * @return array
52
  */
53
+ public function getFormField() :array {
54
  return [
55
  'name' => $this->getLoginFormParameter(),
56
  'type' => 'text',
136
  * @param \WP_User $user
137
  */
138
  private function sendBackupCodeUsedEmail( \WP_User $user ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  $this->getMod()
140
  ->getEmailProcessor()
141
+ ->sendEmailWithWrap(
142
+ $user->user_email,
143
+ sprintf( __( "Notice: %s", 'wp-simple-firewall' ), __( "Backup Login Code Just Used", 'wp-simple-firewall' ) ),
144
+ [
145
+ __( 'This is a quick notice to inform you that your Backup Login code was just used.', 'wp-simple-firewall' ),
146
+ __( "Your WordPress account had only 1 backup login code.", 'wp-simple-firewall' )
147
+ .' '.__( "You must go to your profile and regenerate a new code if you want to use this method again.", 'wp-simple-firewall' ),
148
+ '',
149
+ sprintf( '<strong>%s</strong>', __( 'Login Details', 'wp-simple-firewall' ) ),
150
+ sprintf( '%s: %s', __( 'URL', 'wp-simple-firewall' ), Services::WpGeneral()->getHomeUrl() ),
151
+ sprintf( '%s: %s', __( 'Username', 'wp-simple-firewall' ), $user->user_login ),
152
+ sprintf( '%s: %s', __( 'IP Address', 'wp-simple-firewall' ), Services::IP()->getRequestIp() ),
153
+ '',
154
+ __( 'Thank You.', 'wp-simple-firewall' ),
155
+ ]
156
+ );
157
  }
158
  }
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/BaseProvider.php CHANGED
@@ -23,9 +23,12 @@ abstract class BaseProvider {
23
  public function __construct() {
24
  }
25
 
26
- public function setupProfile() {
 
27
  }
28
 
 
 
29
  /**
30
  * Assumes this is only called on active profiles
31
  * @param \WP_User $user
@@ -108,14 +111,20 @@ abstract class BaseProvider {
108
  return $sNewSecret;
109
  }
110
 
 
 
 
 
 
 
111
  /**
112
  * @param \WP_User $user
113
- * @param bool $bValidated set true for validated, false for invalidated
114
  * @return $this
115
  */
116
- public function setProfileValidated( $user, $bValidated = true ) {
117
  $this->getCon()
118
- ->getUserMeta( $user )->{static::SLUG.'_validated'} = $bValidated;
119
  return $this;
120
  }
121
 
@@ -156,16 +165,48 @@ abstract class BaseProvider {
156
  * @return string
157
  */
158
  public function renderUserProfileOptions( \WP_User $user ) :string {
159
- return '';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  }
161
 
162
  /**
163
  * ONLY TO BE HOOKED TO USER PROFILE EDIT
164
  * @param \WP_User $user
165
  * @return string
 
166
  */
167
  public function renderUserEditProfileOptions( \WP_User $user ) {
168
- return $this->renderUserProfileOptions( $user );
169
  }
170
 
171
  /**
@@ -191,10 +232,7 @@ abstract class BaseProvider {
191
  public function captureLoginAttempt( \WP_User $user ) {
192
  }
193
 
194
- /**
195
- * @return array
196
- */
197
- public function getFormField() {
198
  return [];
199
  }
200
 
@@ -224,25 +262,21 @@ abstract class BaseProvider {
224
  return trim( Services::Request()->request( $this->getLoginFormParameter(), false, '' ) );
225
  }
226
 
227
- /**
228
- * @param \WP_User $user
229
- * @return array
230
- */
231
- protected function getCommonData( \WP_User $user ) {
232
  return [
233
  'flags' => [
234
  'has_validated_profile' => $this->hasValidatedProfile( $user ),
235
  'is_enforced' => $this->isEnforced( $user ),
236
  'is_profile_active' => $this->isProfileActive( $user ),
237
- 'is_my_user_profile' => $user->ID == Services::WpUsers()->getCurrentWpUserId(),
238
- 'i_am_valid_admin' => $this->getCon()->isPluginAdmin(),
239
  'user_to_edit_is_admin' => Services::WpUsers()->isUserAdmin( $user ),
 
240
  ],
241
  'vars' => [
242
  'otp_field_name' => $this->getLoginFormParameter(),
243
  ],
244
  'strings' => [
245
- 'is_enforced' => __( 'This setting is enforced by your security administrator.', 'wp-simple-firewall' ),
 
246
  ],
247
  ];
248
  }
23
  public function __construct() {
24
  }
25
 
26
+ public function getJavascriptVars() :array {
27
+ return [];
28
  }
29
 
30
+ abstract public function getProviderName() :string;
31
+
32
  /**
33
  * Assumes this is only called on active profiles
34
  * @param \WP_User $user
111
  return $sNewSecret;
112
  }
113
 
114
+ public function remove( \WP_User $user ) {
115
+ $meta = $this->getCon()->getUserMeta( $user );
116
+ $meta->{static::SLUG.'_secret'} = null;
117
+ $this->setProfileValidated( $user, false );
118
+ }
119
+
120
  /**
121
  * @param \WP_User $user
122
+ * @param bool $validated set true for validated, false for invalidated
123
  * @return $this
124
  */
125
+ public function setProfileValidated( $user, $validated = true ) {
126
  $this->getCon()
127
+ ->getUserMeta( $user )->{static::SLUG.'_validated'} = $validated;
128
  return $this;
129
  }
130
 
165
  * @return string
166
  */
167
  public function renderUserProfileOptions( \WP_User $user ) :string {
168
+ return $this->getMod()
169
+ ->renderTemplate(
170
+ sprintf( '/admin/user/profile/mfa/mfa_%s.twig', static::SLUG ),
171
+ $this->getProfileRenderData( $user )
172
+ );
173
+ }
174
+
175
+ /**
176
+ * This MUST only ever be hooked into when the User is looking at their OWN profile, so we can use "current user"
177
+ * functions. Otherwise we need to be careful of mixing up users.
178
+ * @param \WP_User $user
179
+ * @return string
180
+ */
181
+ public function renderUserProfileCustomForm( \WP_User $user ) :string {
182
+ $data = $this->getProfileRenderData( $user );
183
+ $data[ 'flags' ][ 'show_explanatory_text' ] = false;
184
+ return $this->getMod()
185
+ ->renderTemplate(
186
+ sprintf( '/user/profile/mfa/provider_%s.twig', static::SLUG ),
187
+ $data
188
+ );
189
+ }
190
+
191
+ public function getProfileRenderData( \WP_User $user ) :array {
192
+ return Services::DataManipulation()->mergeArraysRecursive(
193
+ $this->getCommonData( $user ),
194
+ $this->getProviderSpecificRenderData( $user )
195
+ );
196
+ }
197
+
198
+ protected function getProviderSpecificRenderData( \WP_User $user ) :array {
199
+ return [];
200
  }
201
 
202
  /**
203
  * ONLY TO BE HOOKED TO USER PROFILE EDIT
204
  * @param \WP_User $user
205
  * @return string
206
+ * @deprecated 11.2
207
  */
208
  public function renderUserEditProfileOptions( \WP_User $user ) {
209
+ return '';
210
  }
211
 
212
  /**
232
  public function captureLoginAttempt( \WP_User $user ) {
233
  }
234
 
235
+ public function getFormField() :array {
 
 
 
236
  return [];
237
  }
238
 
262
  return trim( Services::Request()->request( $this->getLoginFormParameter(), false, '' ) );
263
  }
264
 
265
+ protected function getCommonData( \WP_User $user ) :array {
 
 
 
 
266
  return [
267
  'flags' => [
268
  'has_validated_profile' => $this->hasValidatedProfile( $user ),
269
  'is_enforced' => $this->isEnforced( $user ),
270
  'is_profile_active' => $this->isProfileActive( $user ),
 
 
271
  'user_to_edit_is_admin' => Services::WpUsers()->isUserAdmin( $user ),
272
+ 'show_explanatory_text' => true
273
  ],
274
  'vars' => [
275
  'otp_field_name' => $this->getLoginFormParameter(),
276
  ],
277
  'strings' => [
278
+ 'is_enforced' => __( 'This setting is enforced by your security administrator.', 'wp-simple-firewall' ),
279
+ 'provider_name' => $this->getProviderName()
280
  ],
281
  ];
282
  }
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/BaseProviderV2.php DELETED
@@ -1,279 +0,0 @@
1
- <?php
2
-
3
- namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor\Provider;
4
-
5
- use FernleafSystems\Wordpress\Plugin\Shield\Modules;
6
- use FernleafSystems\Wordpress\Plugin\Shield\Utilities\Consumer\WpUserConsumer;
7
- use FernleafSystems\Wordpress\Services\Services;
8
-
9
- abstract class BaseProviderV2 implements ProviderInterface {
10
-
11
- use Modules\ModConsumer;
12
- use WpUserConsumer;
13
-
14
- const SLUG = '';
15
- /**
16
- * Set to true if this provider can be used in isolation. False if there
17
- * must be at least 1 other 2FA provider active.
18
- */
19
- const STANDALONE = true;
20
- /**
21
- * Always a screen, but maybe an json-encoded string, e.g. '[]', like U2F
22
- */
23
- const DEFAULT_SECRET = '';
24
-
25
- public function __construct() {
26
- }
27
-
28
- public function setupProfile() {
29
- }
30
-
31
- /**
32
- * Assumes this is only called on active profiles
33
- * @return bool
34
- */
35
- public function validateLoginIntent() {
36
- $valid = false;
37
- $sReqOtpCode = $this->fetchCodeFromRequest();
38
- if ( !empty( $sReqOtpCode ) ) {
39
- $valid = $this->processOtp( $this->getWpUser(), $sReqOtpCode );
40
- $this->postOtpProcessAction( $this->getWpUser(), $valid );
41
- }
42
- return $valid;
43
- }
44
-
45
- /**
46
- * @return string
47
- */
48
- protected function getSecret() {
49
- $secret = $this->getMeta()->{static::SLUG.'_secret'};
50
- return empty( $secret ) ? static::DEFAULT_SECRET : $secret;
51
- }
52
-
53
- /**
54
- * @return bool
55
- */
56
- public function hasValidatedProfile() {
57
- return $this->getMeta()->{static::SLUG.'_validated'} === true;
58
- }
59
-
60
- /**
61
- * @return bool
62
- */
63
- protected function hasValidSecret() {
64
- return $this->isSecretValid( $this->getSecret() );
65
- }
66
-
67
- /**
68
- * @return bool
69
- */
70
- public function isEnforced() {
71
- return false;
72
- }
73
-
74
- /**
75
- * @param \WP_User $user
76
- * @return bool
77
- */
78
- public function isProfileActive() {
79
- return $this->hasValidSecret( $user );
80
- }
81
-
82
- /**
83
- * @return bool
84
- */
85
- public function isProviderAvailableToUser() {
86
- return $this->isProviderEnabled();
87
- }
88
-
89
- /**
90
- * @return bool
91
- */
92
- abstract public function isProviderEnabled();
93
-
94
- /**
95
- * @param string $secret
96
- * @return bool
97
- */
98
- protected function isSecretValid( $secret ) {
99
- return !empty( $secret ) && is_string( $secret );
100
- }
101
-
102
- /**
103
- * @param \WP_User $user
104
- * @return $this
105
- */
106
- public function deleteSecret( $user ) {
107
- $this->getCon()
108
- ->getUserMeta( $user )->{static::SLUG.'_secret'} = null;
109
- return $this;
110
- }
111
-
112
- /**
113
- * @param \WP_User $user
114
- * @return string
115
- */
116
- public function resetSecret( \WP_User $user ) {
117
- $sNewSecret = $this->genNewSecret( $user );
118
- $this->setSecret( $user, $sNewSecret );
119
- return $sNewSecret;
120
- }
121
-
122
- /**
123
- * @param \WP_User $user
124
- * @param bool $bValidated set true for validated, false for invalidated
125
- * @return $this
126
- */
127
- public function setProfileValidated( $user, $bValidated = true ) {
128
- $this->getCon()
129
- ->getUserMeta( $user )->{static::SLUG.'_validated'} = $bValidated;
130
- return $this;
131
- }
132
-
133
- /**
134
- * @param \WP_User $user
135
- * @param string $sNewSecret
136
- * @return $this
137
- */
138
- protected function setSecret( $user, $sNewSecret ) {
139
- $this->getCon()
140
- ->getUserMeta( $user )->{static::SLUG.'_secret'} = $sNewSecret;
141
- return $this;
142
- }
143
-
144
- /**
145
- * @param \WP_User $user
146
- * @return string|mixed
147
- */
148
- protected function genNewSecret( \WP_User $user ) {
149
- return '';
150
- }
151
-
152
- /**
153
- * @param \WP_User $user
154
- * @param string $otp
155
- * @return bool
156
- */
157
- abstract protected function processOtp( \WP_User $user, $otp );
158
-
159
- /**
160
- * Only to be fired if and when Login has been completely verified.
161
- * @param \WP_User $user
162
- * @return $this
163
- */
164
- public function postSuccessActions( \WP_User $user ) {
165
- return $this;
166
- }
167
-
168
- /**
169
- * This MUST only ever be hooked into when the User is looking at their OWN profile, so we can use "current user"
170
- * functions. Otherwise we need to be careful of mixing up users.
171
- * @param \WP_User $user
172
- * @return string
173
- */
174
- public function renderUserProfileOptions( \WP_User $user ) {
175
- return '';
176
- }
177
-
178
- /**
179
- * ONLY TO BE HOOKED TO USER PROFILE EDIT
180
- * @param \WP_User $user
181
- * @return string
182
- */
183
- public function renderUserEditProfileOptions( \WP_User $user ) {
184
- return $this->renderUserProfileOptions( $user );
185
- }
186
-
187
- /**
188
- * @param \WP_User $user
189
- */
190
- public function handleEditOtherUserProfileSubmit( \WP_User $user ) {
191
- }
192
-
193
- /**
194
- * @param \WP_User $user
195
- */
196
- protected function processRemovalFromAccount( $user ) {
197
- }
198
-
199
- /**
200
- * This MUST only ever be hooked into when the User is looking at their OWN profile,
201
- * so we can use "current user" functions. Otherwise we need to be careful of mixing up users.
202
- * @param \WP_User $user
203
- */
204
- public function handleUserProfileSubmit( \WP_User $user ) {
205
- }
206
-
207
- /**
208
- * @param \WP_User $user
209
- */
210
- public function captureLoginAttempt( $user ) {
211
- }
212
-
213
- /**
214
- * @return array
215
- */
216
- public function getFormField() {
217
- return [];
218
- }
219
-
220
- /**
221
- * @param \WP_User $user
222
- * @param bool $bIsSuccess
223
- */
224
- abstract protected function auditLogin( \WP_User $user, $bIsSuccess );
225
-
226
- /**
227
- * @param \WP_User $user
228
- * @param bool $bIsOtpSuccess
229
- * @return $this
230
- */
231
- protected function postOtpProcessAction( \WP_User $user, $bIsOtpSuccess ) {
232
- $this->auditLogin( $user, $bIsOtpSuccess );
233
- return $this;
234
- }
235
-
236
- /**
237
- * @return string
238
- */
239
- protected function getLoginFormParameter() {
240
- return $this->getCon()->prefixOption( static::SLUG.'_otp' );
241
- }
242
-
243
- /**
244
- * @return string
245
- */
246
- protected function fetchCodeFromRequest() {
247
- return trim( Services::Request()->request( $this->getLoginFormParameter(), false, '' ) );
248
- }
249
-
250
- /**
251
- * @param \WP_User $user
252
- * @return array
253
- */
254
- protected function getCommonData( \WP_User $user ) {
255
- return [
256
- 'flags' => [
257
- 'has_validated_profile' => $this->hasValidatedProfile( $user ),
258
- 'is_enforced' => $this->isEnforced( $user ),
259
- 'is_profile_active' => $this->isProfileActive( $user ),
260
- 'is_my_user_profile' => $user->ID == Services::WpUsers()->getCurrentWpUserId(),
261
- 'i_am_valid_admin' => $this->getCon()->isPluginAdmin(),
262
- 'user_to_edit_is_admin' => Services::WpUsers()->isUserAdmin( $user ),
263
- ],
264
- 'vars' => [
265
- 'otp_field_name' => $this->getLoginFormParameter(),
266
- ],
267
- 'strings' => [
268
- 'is_enforced' => __( 'This setting is enforced by your security administrator.', 'wp-simple-firewall' ),
269
- ],
270
- ];
271
- }
272
-
273
- /**
274
- * @return \FernleafSystems\Wordpress\Plugin\Shield\Users\ShieldUserMeta
275
- */
276
- protected function getMeta() {
277
- return $this->getCon()->getUserMeta( $this->getWpUser() );
278
- }
279
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Email.php CHANGED
@@ -16,6 +16,14 @@ class Email extends BaseProvider {
16
  $this->sendEmailTwoFactorVerify( $user );
17
  }
18
 
 
 
 
 
 
 
 
 
19
  /**
20
  * @param \WP_User $user
21
  * @param bool $bIsSuccess
@@ -60,7 +68,7 @@ class Email extends BaseProvider {
60
  /**
61
  * @return array
62
  */
63
- public function getFormField() {
64
  return [
65
  'name' => $this->getLoginFormParameter(),
66
  'type' => 'text',
@@ -79,25 +87,25 @@ class Email extends BaseProvider {
79
  $bWasEnabled = $this->isProfileActive( $user );
80
  $bToEnable = Services::Request()->post( 'shield_enable_mfaemail' ) === 'Y';
81
 
82
- $sMsg = null;
83
- $bError = false;
84
  if ( $bToEnable ) {
85
  $this->setProfileValidated( $user );
86
  if ( !$bWasEnabled ) {
87
- $sMsg = __( 'Email Two-Factor Authentication has been enabled.', 'wp-simple-firewall' );
88
  }
89
  }
90
  elseif ( $this->isEnforced( $user ) ) {
91
- $sMsg = __( "Email Two-Factor Authentication couldn't be disabled because it is enforced based on your user roles.", 'wp-simple-firewall' );
92
- $bError = true;
93
  }
94
  else {
95
  $this->setProfileValidated( $user, false );
96
- $sMsg = __( 'Email Two-Factor Authentication has been disabled.', 'wp-simple-firewall' );
97
  }
98
 
99
- if ( !empty( $sMsg ) ) {
100
- $this->getMod()->setFlashAdminNotice( $sMsg, $bError );
101
  }
102
  }
103
 
@@ -192,23 +200,16 @@ class Email extends BaseProvider {
192
  );
193
  }
194
 
195
- public function renderUserProfileOptions( \WP_User $user ) :string {
196
- $aData = [
197
  'strings' => [
198
  'label_email_authentication' => __( 'Email Authentication', 'wp-simple-firewall' ),
199
  'title' => __( 'Email Authentication', 'wp-simple-firewall' ),
200
- 'description_email_authentication_checkbox' => __( 'Check the box to enable email-based login authentication.', 'wp-simple-firewall' ),
201
  'provided_by' => sprintf( __( 'Provided by %s', 'wp-simple-firewall' ), $this->getCon()
202
  ->getHumanName() )
203
  ]
204
  ];
205
-
206
- return $this->getMod()
207
- ->renderTemplate(
208
- '/snippets/user/profile/mfa/mfa_email.twig',
209
- Services::DataManipulation()->mergeArraysRecursive( $this->getCommonData( $user ), $aData ),
210
- true
211
- );
212
  }
213
 
214
  public function isProviderEnabled() :bool {
@@ -234,7 +235,7 @@ class Email extends BaseProvider {
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
  );
@@ -280,4 +281,8 @@ class Email extends BaseProvider {
280
  private function storeCodes( \WP_User $user, array $codes ) {
281
  return $this->setSecret( $user, $codes );
282
  }
 
 
 
 
283
  }
16
  $this->sendEmailTwoFactorVerify( $user );
17
  }
18
 
19
+ public function getJavascriptVars() :array {
20
+ return [
21
+ 'ajax' => [
22
+ 'user_email2fa_toggle' => $this->getMod()->getAjaxActionData( 'user_email2fa_toggle' ),
23
+ ],
24
+ ];
25
+ }
26
+
27
  /**
28
  * @param \WP_User $user
29
  * @param bool $bIsSuccess
68
  /**
69
  * @return array
70
  */
71
+ public function getFormField() :array {
72
  return [
73
  'name' => $this->getLoginFormParameter(),
74
  'type' => 'text',
87
  $bWasEnabled = $this->isProfileActive( $user );
88
  $bToEnable = Services::Request()->post( 'shield_enable_mfaemail' ) === 'Y';
89
 
90
+ $msg = null;
91
+ $error = false;
92
  if ( $bToEnable ) {
93
  $this->setProfileValidated( $user );
94
  if ( !$bWasEnabled ) {
95
+ $msg = __( 'Email Two-Factor Authentication has been enabled.', 'wp-simple-firewall' );
96
  }
97
  }
98
  elseif ( $this->isEnforced( $user ) ) {
99
+ $msg = __( "Email Two-Factor Authentication couldn't be disabled because it is enforced based on your user roles.", 'wp-simple-firewall' );
100
+ $error = true;
101
  }
102
  else {
103
  $this->setProfileValidated( $user, false );
104
+ $msg = __( 'Email Two-Factor Authentication has been disabled.', 'wp-simple-firewall' );
105
  }
106
 
107
+ if ( !empty( $msg ) ) {
108
+ $this->getMod()->setFlashAdminNotice( $msg, $error );
109
  }
110
  }
111
 
200
  );
201
  }
202
 
203
+ protected function getProviderSpecificRenderData( \WP_User $user ) :array {
204
+ return [
205
  'strings' => [
206
  'label_email_authentication' => __( 'Email Authentication', 'wp-simple-firewall' ),
207
  'title' => __( 'Email Authentication', 'wp-simple-firewall' ),
208
+ 'description_email_authentication_checkbox' => __( 'Toggle the option to enable/disable email-based login authentication.', 'wp-simple-firewall' ),
209
  'provided_by' => sprintf( __( 'Provided by %s', 'wp-simple-firewall' ), $this->getCon()
210
  ->getHumanName() )
211
  ]
212
  ];
 
 
 
 
 
 
 
213
  }
214
 
215
  public function isProviderEnabled() :bool {
235
  $this->getLoginFormParameter() => $otp,
236
  'shield_nonce_action' => $action,
237
  'shield_nonce' => $this->getCon()
238
+ ->nonce_handler->create( $action, $opts->getLoginIntentMinutes()*60 ),
239
  ],
240
  Services::WpGeneral()->getHomeUrl()
241
  );
281
  private function storeCodes( \WP_User $user, array $codes ) {
282
  return $this->setSecret( $user, $codes );
283
  }
284
+
285
+ public function getProviderName() :string {
286
+ return 'Email';
287
+ }
288
  }
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/GoogleAuth.php CHANGED
@@ -3,6 +3,7 @@
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor\Provider;
4
 
5
  use Dolondro\GoogleAuthenticator;
 
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
7
  use FernleafSystems\Wordpress\Services\Services;
8
 
@@ -19,24 +20,31 @@ class GoogleAuth extends BaseProvider {
19
  return parent::isProfileActive( $user ) && $this->hasValidatedProfile( $user );
20
  }
21
 
22
- public function renderUserProfileOptions( \WP_User $user ) :string {
23
- $oCon = $this->getCon();
 
 
 
 
 
24
 
25
- $bValidatedProfile = $this->hasValidatedProfile( $user );
 
26
 
27
- $aData = [
 
28
  'hrefs' => [
29
- 'src_chart_url' => $bValidatedProfile ? '' : $this->getGaRegisterChartUrl( $user ),
30
  ],
31
  'vars' => [
32
- 'ga_secret' => $bValidatedProfile ? $this->getSecret( $user ) : $this->resetSecret( $user ),
33
  ],
34
  'strings' => [
35
- 'enter_auth_app_code' => __( 'Enter the 6-digit code from your Authenticator App', 'wp-simple-firewall' ),
36
  'description_otp_code' => __( 'Provide the current code generated by your Google Authenticator app.', 'wp-simple-firewall' ),
37
  'description_chart_url' => __( 'Use your Google Authenticator app to scan this QR code and enter the 6-digit one time password.', 'wp-simple-firewall' ),
38
  'description_ga_secret' => __( 'If you have a problem with scanning the QR code enter the long code manually into the app.', 'wp-simple-firewall' ),
39
- 'desc_remove' => __( 'Check the box to remove Google Authenticator login authentication.', 'wp-simple-firewall' ),
40
  'label_check_to_remove' => sprintf( __( 'Remove %s', 'wp-simple-firewall' ), __( 'Google Authenticator', 'wp-simple-firewall' ) ),
41
  'label_enter_code' => __( 'Google Authenticator Code', 'wp-simple-firewall' ),
42
  'label_ga_secret' => __( 'Manual Code', 'wp-simple-firewall' ),
@@ -44,17 +52,11 @@ class GoogleAuth extends BaseProvider {
44
  'title' => __( 'Google Authenticator', 'wp-simple-firewall' ),
45
  'cant_add_other_user' => sprintf( __( "Sorry, %s may not be added to another user's account.", 'wp-simple-firewall' ), 'Google Authenticator' ),
46
  'cant_remove_admins' => sprintf( __( "Sorry, %s may only be removed from another user's account by a Security Administrator.", 'wp-simple-firewall' ), __( 'Google Authenticator', 'wp-simple-firewall' ) ),
47
- 'provided_by' => sprintf( __( 'Provided by %s', 'wp-simple-firewall' ), $oCon->getHumanName() ),
48
- 'remove_more_info' => sprintf( __( 'Understand how to remove Google Authenticator', 'wp-simple-firewall' ) )
 
49
  ],
50
  ];
51
-
52
- return $this->getMod()
53
- ->renderTemplate(
54
- '/snippets/user/profile/mfa/mfa_ga.twig',
55
- Services::DataManipulation()->mergeArraysRecursive( $this->getCommonData( $user ), $aData ),
56
- true
57
- );
58
  }
59
 
60
  /**
@@ -62,10 +64,10 @@ class GoogleAuth extends BaseProvider {
62
  * @return string
63
  */
64
  public function getGaRegisterChartUrl( $user ) {
65
- $sUrl = '';
66
  if ( !empty( $user ) ) {
67
  try {
68
- $sUrl = ( new GoogleAuthenticator\QrImageGenerator\GoogleQrImageGenerator () )
69
  ->generateUri(
70
  $this->getGaSecret( $user )
71
  );
@@ -73,7 +75,7 @@ class GoogleAuth extends BaseProvider {
73
  catch ( \InvalidArgumentException $e ) {
74
  }
75
  }
76
- return $sUrl;
77
  }
78
 
79
  /**
@@ -86,11 +88,37 @@ class GoogleAuth extends BaseProvider {
86
  // Can only edit other users if you're admin/security-admin
87
  if ( $this->getCon()->isPluginAdmin() && Services::Request()->post( 'shield_turn_off_ga' ) === 'Y' ) {
88
  $this->processRemovalFromAccount( $user );
89
- $sMsg = __( 'Google Authenticator was successfully removed from the account.', 'wp-simple-firewall' );
90
- $this->getMod()->setFlashAdminNotice( $sMsg );
91
  }
92
  }
93
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  /**
95
  * @param \WP_User $user
96
  * @return $this
@@ -105,39 +133,39 @@ class GoogleAuth extends BaseProvider {
105
  * @inheritDoc
106
  */
107
  public function handleUserProfileSubmit( \WP_User $user ) {
108
- $sOtp = $this->fetchCodeFromRequest();
109
 
110
  if ( Services::Request()->post( 'shield_turn_off_ga' ) === 'Y' ) {
111
- $sFlash = __( 'Google Authenticator was successfully removed from the account.', 'wp-simple-firewall' );
112
  $this->processRemovalFromAccount( $user );
113
- $this->getMod()->setFlashAdminNotice( $sFlash );
114
  /**
115
- * $sFlash = __( 'An email has been sent to you in order to confirm Google Authenticator removal', 'wp-simple-firewall' );
116
- * $sFlash = __( 'We tried to send an email for you to confirm Google Authenticator removal but it failed.', 'wp-simple-firewall' );
117
  */
118
  }
119
- elseif ( !empty( $sOtp ) && !$this->hasValidatedProfile( $user ) ) { // Add GA to profile
120
- $bValidOtp = $this->processOtp( $user, $sOtp );
121
- if ( $bValidOtp ) {
122
  $this->setProfileValidated( $user );
123
- $sFlash = sprintf(
124
  __( '%s was successfully added to your account.', 'wp-simple-firewall' ),
125
  __( 'Google Authenticator', 'wp-simple-firewall' )
126
  );
127
  }
128
  else {
129
  $this->resetSecret( $user );
130
- $sFlash = __( 'One Time Password (OTP) was not valid.', 'wp-simple-firewall' )
131
- .' '.__( 'Please try again.', 'wp-simple-firewall' );
132
  }
133
- $this->getMod()->setFlashAdminNotice( $sFlash, !$bValidOtp );
134
  }
135
  }
136
 
137
  /**
138
  * @return array
139
  */
140
- public function getFormField() {
141
  return [
142
  'name' => $this->getLoginFormParameter(),
143
  'type' => 'text',
@@ -241,4 +269,8 @@ class GoogleAuth extends BaseProvider {
241
  $opts = $this->getOptions();
242
  return $opts->isEnabledGoogleAuthenticator();
243
  }
 
 
 
 
244
  }
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor\Provider;
4
 
5
  use Dolondro\GoogleAuthenticator;
6
+ use FernleafSystems\Utilities\Data\Response\StdResponse;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
8
  use FernleafSystems\Wordpress\Services\Services;
9
 
20
  return parent::isProfileActive( $user ) && $this->hasValidatedProfile( $user );
21
  }
22
 
23
+ public function getJavascriptVars() :array {
24
+ return [
25
+ 'ajax' => [
26
+ 'user_ga_toggle' => $this->getMod()->getAjaxActionData( 'user_ga_toggle' ),
27
+ ],
28
+ ];
29
+ }
30
 
31
+ protected function getProviderSpecificRenderData( \WP_User $user ) :array {
32
+ $con = $this->getCon();
33
 
34
+ $validatedProfile = $this->hasValidatedProfile( $user );
35
+ return [
36
  'hrefs' => [
37
+ 'src_chart_url' => $validatedProfile ? '' : $this->getGaRegisterChartUrl( $user ),
38
  ],
39
  'vars' => [
40
+ 'ga_secret' => $validatedProfile ? $this->getSecret( $user ) : $this->resetSecret( $user ),
41
  ],
42
  'strings' => [
43
+ 'enter_auth_app_code' => __( 'Enter 6-digit Code from App', 'wp-simple-firewall' ),
44
  'description_otp_code' => __( 'Provide the current code generated by your Google Authenticator app.', 'wp-simple-firewall' ),
45
  'description_chart_url' => __( 'Use your Google Authenticator app to scan this QR code and enter the 6-digit one time password.', 'wp-simple-firewall' ),
46
  'description_ga_secret' => __( 'If you have a problem with scanning the QR code enter the long code manually into the app.', 'wp-simple-firewall' ),
47
+ 'desc_remove' => __( 'Click to immediately remove Google Authenticator login authentication.', 'wp-simple-firewall' ),
48
  'label_check_to_remove' => sprintf( __( 'Remove %s', 'wp-simple-firewall' ), __( 'Google Authenticator', 'wp-simple-firewall' ) ),
49
  'label_enter_code' => __( 'Google Authenticator Code', 'wp-simple-firewall' ),
50
  'label_ga_secret' => __( 'Manual Code', 'wp-simple-firewall' ),
52
  'title' => __( 'Google Authenticator', 'wp-simple-firewall' ),
53
  'cant_add_other_user' => sprintf( __( "Sorry, %s may not be added to another user's account.", 'wp-simple-firewall' ), 'Google Authenticator' ),
54
  'cant_remove_admins' => sprintf( __( "Sorry, %s may only be removed from another user's account by a Security Administrator.", 'wp-simple-firewall' ), __( 'Google Authenticator', 'wp-simple-firewall' ) ),
55
+ 'provided_by' => sprintf( __( 'Provided by %s', 'wp-simple-firewall' ), $con->getHumanName() ),
56
+ 'remove_more_info' => __( 'Understand how to remove Google Authenticator', 'wp-simple-firewall' ),
57
+ 'remove_google_auth' => __( 'Remove Google Authenticator', 'wp-simple-firewall' )
58
  ],
59
  ];
 
 
 
 
 
 
 
60
  }
61
 
62
  /**
64
  * @return string
65
  */
66
  public function getGaRegisterChartUrl( $user ) {
67
+ $url = '';
68
  if ( !empty( $user ) ) {
69
  try {
70
+ $url = ( new GoogleAuthenticator\QrImageGenerator\EndroidQrImageGenerator() )
71
  ->generateUri(
72
  $this->getGaSecret( $user )
73
  );
75
  catch ( \InvalidArgumentException $e ) {
76
  }
77
  }
78
+ return $url;
79
  }
80
 
81
  /**
88
  // Can only edit other users if you're admin/security-admin
89
  if ( $this->getCon()->isPluginAdmin() && Services::Request()->post( 'shield_turn_off_ga' ) === 'Y' ) {
90
  $this->processRemovalFromAccount( $user );
91
+ $msg = __( 'Google Authenticator was successfully removed from the account.', 'wp-simple-firewall' );
92
+ $this->getMod()->setFlashAdminNotice( $msg );
93
  }
94
  }
95
 
96
+ public function removeGaOnAccount( \WP_User $user ) :StdResponse {
97
+ $this->processRemovalFromAccount( $user );
98
+ $response = new StdResponse();
99
+ $response->success = true;
100
+ $response->msg_text = __( 'Google Authenticator was successfully removed from the account.', 'wp-simple-firewall' );
101
+ return $response;
102
+ }
103
+
104
+ public function activateGaOnAccount( \WP_User $user, string $otp ) :StdResponse {
105
+ $response = new StdResponse();
106
+ $response->success = $this->processOtp( $user, $otp );
107
+ if ( $response->success ) {
108
+ $this->setProfileValidated( $user );
109
+ $response->msg_text = sprintf(
110
+ __( '%s was successfully added to your account.', 'wp-simple-firewall' ),
111
+ __( 'Google Authenticator', 'wp-simple-firewall' )
112
+ );
113
+ }
114
+ else {
115
+ $this->resetSecret( $user );
116
+ $response->error_text = __( 'One Time Password (OTP) was not valid.', 'wp-simple-firewall' )
117
+ .' '.__( 'Please try again.', 'wp-simple-firewall' );
118
+ }
119
+ return $response;
120
+ }
121
+
122
  /**
123
  * @param \WP_User $user
124
  * @return $this
133
  * @inheritDoc
134
  */
135
  public function handleUserProfileSubmit( \WP_User $user ) {
136
+ $otp = $this->fetchCodeFromRequest();
137
 
138
  if ( Services::Request()->post( 'shield_turn_off_ga' ) === 'Y' ) {
139
+ $flash = __( 'Google Authenticator was successfully removed from the account.', 'wp-simple-firewall' );
140
  $this->processRemovalFromAccount( $user );
141
+ $this->getMod()->setFlashAdminNotice( $flash );
142
  /**
143
+ * $flash = __( 'An email has been sent to you in order to confirm Google Authenticator removal', 'wp-simple-firewall' );
144
+ * $flash = __( 'We tried to send an email for you to confirm Google Authenticator removal but it failed.', 'wp-simple-firewall' );
145
  */
146
  }
147
+ elseif ( !empty( $otp ) && !$this->hasValidatedProfile( $user ) ) { // Add GA to profile
148
+ $validOTP = $this->processOtp( $user, $otp );
149
+ if ( $validOTP ) {
150
  $this->setProfileValidated( $user );
151
+ $flash = sprintf(
152
  __( '%s was successfully added to your account.', 'wp-simple-firewall' ),
153
  __( 'Google Authenticator', 'wp-simple-firewall' )
154
  );
155
  }
156
  else {
157
  $this->resetSecret( $user );
158
+ $flash = __( 'One Time Password (OTP) was not valid.', 'wp-simple-firewall' )
159
+ .' '.__( 'Please try again.', 'wp-simple-firewall' );
160
  }
161
+ $this->getMod()->setFlashAdminNotice( $flash, !$validOTP );
162
  }
163
  }
164
 
165
  /**
166
  * @return array
167
  */
168
+ public function getFormField() :array {
169
  return [
170
  'name' => $this->getLoginFormParameter(),
171
  'type' => 'text',
269
  $opts = $this->getOptions();
270
  return $opts->isEnabledGoogleAuthenticator();
271
  }
272
+
273
+ public function getProviderName() :string {
274
+ return 'Google Authenticator';
275
+ }
276
  }
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/ProviderInterface.php CHANGED
@@ -46,23 +46,10 @@ interface ProviderInterface {
46
  */
47
  public function handleUserProfileSubmit();
48
 
49
- /**
50
- * Process the edit of user profile that is not the current user
51
- * @return string
52
- */
53
- public function handleEditOtherUserProfileSubmit();
54
-
55
-
56
  /**
57
  * This MUST only ever be hooked into when the User is looking at their OWN profile, so we can use "current user"
58
  * functions. Otherwise we need to be careful of mixing up users.
59
  * @return string
60
  */
61
  public function renderUserProfileOptions();
62
-
63
- /**
64
- * ONLY TO BE HOOKED TO USER PROFILE EDIT
65
- * @return string
66
- */
67
- public function renderUserEditProfileOptions();
68
  }
46
  */
47
  public function handleUserProfileSubmit();
48
 
 
 
 
 
 
 
 
49
  /**
50
  * This MUST only ever be hooked into when the User is looking at their OWN profile, so we can use "current user"
51
  * functions. Otherwise we need to be careful of mixing up users.
52
  * @return string
53
  */
54
  public function renderUserProfileOptions();
 
 
 
 
 
 
55
  }
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/U2F.php CHANGED
@@ -2,6 +2,7 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor\Provider;
4
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Controller\Assets\Enqueue;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
7
  use FernleafSystems\Wordpress\Services\Services;
@@ -17,52 +18,37 @@ class U2F extends BaseProvider {
17
  return parent::isProfileActive( $user ) && $this->hasValidatedProfile( $user );
18
  }
19
 
20
- public function setupProfile() {
21
- add_filter( 'shield/custom_enqueues', function ( array $enqueues, $hook ) {
22
- if ( in_array( $hook, [ 'profile.php', ] ) ) {
23
-
24
- $enqueues[ Enqueue::JS ][] = 'shield/u2f-admin';
25
-
26
- add_filter( 'shield/custom_localisations', function ( array $localz ) {
27
- $user = Services::WpUsers()->getCurrentWpUser();
28
- list( $reg, $signs ) = $this->createNewU2fRegistrationRequest( $user );
29
- $localz[] = [
30
- 'shield/u2f-admin',
31
- 'icwp_wpsf_vars_u2f',
32
- [
33
- 'reg_request' => $reg,
34
- 'signs' => $signs,
35
- 'ajax' => [
36
- 'u2f_remove' => $this->getMod()->getAjaxActionData( 'u2f_remove' )
37
- ],
38
- 'flags' => [
39
- 'has_validated' => $this->hasValidatedProfile( $user )
40
- ],
41
- 'strings' => [
42
- 'not_supported' => __( 'U2F Security Key registration is not supported in this browser', 'wp-simple-firewall' ),
43
- 'failed' => __( 'Key registration failed.', 'wp-simple-firewall' )
44
- .' '.__( "Perhaps the device isn't supported, or you've already registered it.", 'wp-simple-firewall' )
45
- .' '.__( 'Please retry or refresh the page.', 'wp-simple-firewall' ),
46
- 'do_save' => __( 'Key registration was successful.', 'wp-simple-firewall' )
47
- .' '.__( 'Please now save your profile settings.', 'wp-simple-firewall' ),
48
- 'prompt_dialog' => __( 'Please provide a label to identify the new U2F device.', 'wp-simple-firewall' ),
49
- 'err_no_label' => __( 'Device registration may not proceed without a unique label.', 'wp-simple-firewall' ),
50
- 'err_invalid_label' => __( 'Device label must contain letters, numbers, underscore, or hypen, and be no more than 16 characters.', 'wp-simple-firewall' ),
51
- ]
52
- ]
53
- ];
54
- return $localz;
55
- } );
56
- }
57
-
58
- return $enqueues;
59
- }, 10, 2 );
60
  }
61
 
62
  /**
63
  * @return array
64
  */
65
- public function getFormField() {
66
  $user = Services::WpUsers()->getCurrentWpUser();
67
 
68
  $aFieldData = [];
@@ -101,11 +87,22 @@ class U2F extends BaseProvider {
101
  * @throws \u2flib_server\Error
102
  */
103
  private function createNewU2fRegistrationRequest( \WP_User $user ) {
104
- $oMeta = $this->getCon()->getUserMeta( $user );
105
- list( $oRegRequest, $aSignRequests ) = ( new \u2flib_server\U2F( $this->getU2fAppID() ) )
106
  ->getRegisterData( $this->getRegistrations( $user ) );
107
- $oMeta->u2f_regrequest = json_encode( $oRegRequest );
108
- return [ $oRegRequest, $aSignRequests ];
 
 
 
 
 
 
 
 
 
 
 
109
  }
110
 
111
  /**
@@ -113,12 +110,12 @@ class U2F extends BaseProvider {
113
  * @return \stdClass[]
114
  */
115
  private function getRegistrations( \WP_User $user ) {
116
- $aRegs = json_decode( $this->getSecret( $user ), true );
117
  return array_map(
118
- function ( $aReg ) {
119
- return (object)$aReg;
120
  },
121
- is_array( $aRegs ) ? $aRegs : []
122
  );
123
  }
124
 
@@ -132,18 +129,15 @@ class U2F extends BaseProvider {
132
  return sprintf( 'https://%s%s', $aPs[ 'host' ], $sPort );
133
  }
134
 
135
- public function renderUserProfileOptions( \WP_User $user ) :string {
136
-
137
- $bValidated = $this->hasValidatedProfile( $user );
138
-
139
- $aData = [
140
  'strings' => [
141
  'title' => __( 'U2F', 'wp-simple-firewall' ),
142
  'button_reg_key' => __( 'Register A New U2F Security Key', 'wp-simple-firewall' ),
143
  'prompt' => __( 'Click To Register A U2F Device.', 'wp-simple-firewall' ),
144
  ],
145
  'flags' => [
146
- 'is_validated' => $bValidated
147
  ],
148
  'vars' => [
149
  'registrations' => array_map(
@@ -163,67 +157,72 @@ class U2F extends BaseProvider {
163
  )
164
  ],
165
  ];
166
-
167
- return $this->getMod()
168
- ->renderTemplate(
169
- '/snippets/user/profile/mfa/mfa_u2f.twig',
170
- Services::DataManipulation()->mergeArraysRecursive( $this->getCommonData( $user ), $aData ),
171
- true
172
- );
173
  }
174
 
175
  /**
176
  * @inheritDoc
177
  */
178
- public function renderUserEditProfileOptions( \WP_User $user ) {
179
- // Allow no actions to be taken on other user profiles
 
 
 
 
 
180
  }
181
 
182
- /**
183
- * @inheritDoc
184
- */
185
- public function handleUserProfileSubmit( \WP_User $user ) {
186
- $isError = false;
187
- $msg = null;
188
-
189
- $sU2fResponse = Services::Request()->post( 'icwp_wpsf_new_u2f_response' );
190
- if ( !empty( $sU2fResponse ) ) {
191
- $oMeta = $this->getCon()->getUserMeta( $user );
192
-
193
- try {
194
- $oDecodedResponse = json_decode( $sU2fResponse );
195
- $sLabel = preg_replace( '#[^a-z0-9_-]#i', '', $oDecodedResponse->label );
196
- if ( strlen( $sLabel ) > 16 ) {
197
- throw new \Exception( 'U2F Device label is larger than 16 characters.' );
198
- }
199
- if ( array_key_exists( $sLabel, $this->getRegistrations( $user ) ) ) {
200
- throw new \Exception( 'U2F Device with this label already exists.' );
201
- }
202
 
203
- $oRegRequest = json_decode( $oMeta->u2f_regrequest );
204
- $oRegistration = ( new \u2flib_server\U2F( $this->getU2fAppID() ) )->doRegister(
205
- new RegisterRequest( $oRegRequest->challenge, $oRegRequest->appId ),
206
- $oDecodedResponse
207
- );
208
 
209
- // attach the device label
210
- $aConfirmedReg = get_object_vars( $oRegistration );
211
- $aConfirmedReg[ 'label' ] = $sLabel;
212
- $this->addRegistration( $user, $aConfirmedReg )
213
- ->setProfileValidated( $user );
 
 
 
 
214
 
215
- $msg = __( 'U2F Device was successfully registered on your profile.', 'wp-simple-firewall' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
216
  }
217
- catch ( \Exception $e ) {
218
- $isError = true;
219
- $msg = sprintf( __( 'U2F Device registration failed with the following error: %s', 'wp-simple-firewall' ),
220
- $e->getMessage() );
221
  }
222
- }
223
 
224
- if ( !empty( $msg ) ) {
225
- $this->getMod()->setFlashAdminNotice( $msg, $isError );
 
 
 
 
 
 
226
  }
 
 
 
 
 
 
 
227
  }
228
 
229
  protected function processOtp( \WP_User $user, string $otp ) :bool {
@@ -269,12 +268,12 @@ class U2F extends BaseProvider {
269
 
270
  /**
271
  * @param \WP_User $user
272
- * @param array $aRegs
273
  * @return $this
274
  */
275
- private function storeRegistrations( \WP_User $user, array $aRegs ) {
276
- return $this->setProfileValidated( $user, !empty( $aRegs ) )
277
- ->setSecret( $user, json_encode( $aRegs ) );
278
  }
279
 
280
  /**
@@ -331,4 +330,8 @@ class U2F extends BaseProvider {
331
  $opts = $this->getOptions();
332
  return $opts->isEnabledU2F();
333
  }
 
 
 
 
334
  }
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor\Provider;
4
 
5
+ use FernleafSystems\Utilities\Data\Response\StdResponse;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Controller\Assets\Enqueue;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
8
  use FernleafSystems\Wordpress\Services\Services;
18
  return parent::isProfileActive( $user ) && $this->hasValidatedProfile( $user );
19
  }
20
 
21
+ public function getJavascriptVars() :array {
22
+ $user = Services::WpUsers()->getCurrentWpUser();
23
+ list( $reg, $signs ) = $this->createNewU2fRegistrationRequest( $user );
24
+ return [
25
+ 'reg_request' => $reg,
26
+ 'signs' => $signs,
27
+ 'ajax' => [
28
+ 'u2f_add' => $this->getMod()->getAjaxActionData( 'u2f_add' ),
29
+ 'u2f_remove' => $this->getMod()->getAjaxActionData( 'u2f_remove' ),
30
+ ],
31
+ 'flags' => [
32
+ 'has_validated' => $this->hasValidatedProfile( $user )
33
+ ],
34
+ 'strings' => [
35
+ 'not_supported' => __( 'U2F Security Key registration is not supported in this browser', 'wp-simple-firewall' ),
36
+ 'failed' => __( 'Key registration failed.', 'wp-simple-firewall' )
37
+ .' '.__( "Perhaps the device isn't supported, or you've already registered it.", 'wp-simple-firewall' )
38
+ .' '.__( 'Please retry or refresh the page.', 'wp-simple-firewall' ),
39
+ 'do_save' => __( 'Key registration was successful.', 'wp-simple-firewall' )
40
+ .' '.__( 'Please now save your profile settings.', 'wp-simple-firewall' ),
41
+ 'prompt_dialog' => __( 'Please provide a label to identify the new U2F device.', 'wp-simple-firewall' ),
42
+ 'err_no_label' => __( 'Device registration may not proceed without a unique label.', 'wp-simple-firewall' ),
43
+ 'err_invalid_label' => __( 'Device label must contain letters, numbers, underscore, or hypen, and be no more than 16 characters.', 'wp-simple-firewall' ),
44
+ ]
45
+ ];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  }
47
 
48
  /**
49
  * @return array
50
  */
51
+ public function getFormField() :array {
52
  $user = Services::WpUsers()->getCurrentWpUser();
53
 
54
  $aFieldData = [];
87
  * @throws \u2flib_server\Error
88
  */
89
  private function createNewU2fRegistrationRequest( \WP_User $user ) {
90
+ $meta = $this->getCon()->getUserMeta( $user );
91
+ list( $newRegRequest, $signRequests ) = ( new \u2flib_server\U2F( $this->getU2fAppID() ) )
92
  ->getRegisterData( $this->getRegistrations( $user ) );
93
+
94
+ // Store requests as an array to allow for multiple requests to be kept
95
+ unset( $meta->u2f_regrequest ); // Old property
96
+ $userRegRequests = array_filter(
97
+ is_array( $meta->u2f_regrequests ) ? $meta->u2f_regrequests : [],
98
+ function ( $ts ) {
99
+ return Services::Request()->ts() - $ts < MINUTE_IN_SECONDS*10;
100
+ }
101
+ );
102
+ $userRegRequests[ json_encode( $newRegRequest ) ] = Services::Request()->ts();
103
+ $meta->u2f_regrequests = $userRegRequests;
104
+
105
+ return [ $newRegRequest, $signRequests ];
106
  }
107
 
108
  /**
110
  * @return \stdClass[]
111
  */
112
  private function getRegistrations( \WP_User $user ) {
113
+ $regs = json_decode( $this->getSecret( $user ), true );
114
  return array_map(
115
+ function ( $reg ) {
116
+ return (object)$reg;
117
  },
118
+ is_array( $regs ) ? $regs : []
119
  );
120
  }
121
 
129
  return sprintf( 'https://%s%s', $aPs[ 'host' ], $sPort );
130
  }
131
 
132
+ protected function getProviderSpecificRenderData( \WP_User $user ) :array {
133
+ return [
 
 
 
134
  'strings' => [
135
  'title' => __( 'U2F', 'wp-simple-firewall' ),
136
  'button_reg_key' => __( 'Register A New U2F Security Key', 'wp-simple-firewall' ),
137
  'prompt' => __( 'Click To Register A U2F Device.', 'wp-simple-firewall' ),
138
  ],
139
  'flags' => [
140
+ 'is_validated' => $this->hasValidatedProfile( $user )
141
  ],
142
  'vars' => [
143
  'registrations' => array_map(
157
  )
158
  ],
159
  ];
 
 
 
 
 
 
 
160
  }
161
 
162
  /**
163
  * @inheritDoc
164
  */
165
+ public function handleUserProfileSubmit( \WP_User $user ) {
166
+ $rawU2fResponse = Services::Request()->post( 'icwp_wpsf_new_u2f_response' );
167
+ if ( !empty( $rawU2fResponse ) ) {
168
+ $result = $this->addNewRegistration( $user, json_decode( $rawU2fResponse, true ) );
169
+ $this->getMod()
170
+ ->setFlashAdminNotice( $result->success ? $result->msg_text : $result->error_text, $result->failed );
171
+ }
172
  }
173
 
174
+ public function addNewRegistration( \WP_User $user, array $u2fResponse ) :StdResponse {
175
+ $response = new StdResponse();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
 
177
+ $meta = $this->getCon()->getUserMeta( $user );
 
 
 
 
178
 
179
+ try {
180
+ $u2fResponse = (object)$u2fResponse;
181
+ $label = preg_replace( '#[^a-z0-9_-]#i', '', $u2fResponse->label );
182
+ if ( strlen( $label ) > 16 ) {
183
+ throw new \Exception( 'U2F Device label is larger than 16 characters.' );
184
+ }
185
+ if ( array_key_exists( $label, $this->getRegistrations( $user ) ) ) {
186
+ throw new \Exception( 'U2F Device with this label already exists.' );
187
+ }
188
 
189
+ $U2FRegistration = null;
190
+ foreach ( $meta->u2f_regrequests as $u2fRequest => $ts ) {
191
+ try {
192
+ $regRequest = json_decode( $u2fRequest );
193
+ $U2FRegistration = ( new \u2flib_server\U2F( $this->getU2fAppID() ) )->doRegister(
194
+ new RegisterRequest( $regRequest->challenge, $regRequest->appId ),
195
+ $u2fResponse
196
+ );
197
+ $regReqs = $meta->u2f_regrequests;
198
+ unset( $regReqs[ $u2fRequest ] );
199
+ $meta->u2f_regrequests = $regReqs;
200
+ break;
201
+ }
202
+ catch ( \Exception $e ) {
203
+ }
204
  }
205
+
206
+ if ( empty( $U2FRegistration ) ) {
207
+ throw new \Exception( "Couldn't find a suitable U2F challenge to verify." );
 
208
  }
 
209
 
210
+ // attach the device label
211
+ $confirmedReg = get_object_vars( $U2FRegistration );
212
+ $confirmedReg[ 'label' ] = $label;
213
+ $this->addRegistration( $user, $confirmedReg )
214
+ ->setProfileValidated( $user );
215
+
216
+ $response->msg_text = __( 'U2F Device was successfully registered on your profile.', 'wp-simple-firewall' );
217
+ $response->success = true;
218
  }
219
+ catch ( \Exception $e ) {
220
+ $response->success = false;
221
+ $response->error_text = sprintf( __( 'U2F Device registration failed with the following error: %s', 'wp-simple-firewall' ),
222
+ $e->getMessage() );
223
+ }
224
+
225
+ return $response;
226
  }
227
 
228
  protected function processOtp( \WP_User $user, string $otp ) :bool {
268
 
269
  /**
270
  * @param \WP_User $user
271
+ * @param array $regs
272
  * @return $this
273
  */
274
+ private function storeRegistrations( \WP_User $user, array $regs ) {
275
+ return $this->setProfileValidated( $user, !empty( $regs ) )
276
+ ->setSecret( $user, json_encode( $regs ) );
277
  }
278
 
279
  /**
330
  $opts = $this->getOptions();
331
  return $opts->isEnabledU2F();
332
  }
333
+
334
+ public function getProviderName() :string {
335
+ return 'U2F';
336
+ }
337
  }
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Yubikey.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor\Provider;
4
 
5
- use FernleafSystems\Wordpress\Plugin\Shield\Controller\Assets\Enqueue;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
7
  use FernleafSystems\Wordpress\Services\Services;
8
 
@@ -12,56 +12,40 @@ class Yubikey extends BaseProvider {
12
  const OTP_LENGTH = 12;
13
  const URL_YUBIKEY_VERIFY = 'https://api.yubico.com/wsapi/2.0/verify';
14
 
15
- public function setupProfile() {
16
- add_filter( 'shield/custom_enqueues', function ( array $enqueues, $hook ) {
17
- if ( in_array( $hook, [ 'profile.php', ] ) ) {
18
- $enqueues[ Enqueue::JS ][] = 'shield/userprofile';
19
-
20
- add_filter( 'shield/custom_localisations', function ( array $localz ) {
21
- $localz[] = [
22
- 'shield/userprofile',
23
- 'icwp_wpsf_vars_profileyubikey',
24
- [ 'yubikey_remove' => $this->getMod()->getAjaxActionData( 'yubikey_remove' ) ]
25
- ];
26
- return $localz;
27
- } );
28
- }
29
- return $enqueues;
30
- }, 10, 2 );
31
  }
32
 
33
- public function renderUserProfileOptions( \WP_User $user ) :string {
34
  $con = $this->getCon();
35
-
36
- $aData = [
37
  'vars' => [
38
  'yubi_ids' => $this->getYubiIds( $user ),
39
  ],
40
  'strings' => [
41
- 'registered_yubi_ids' => __( 'Registered Yubikey devices', 'wp-simple-firewall' ),
42
- 'no_active_yubi_ids' => __( 'There are no registered Yubikey devices on this profile.', 'wp-simple-firewall' ),
43
- 'enter_otp' => __( 'To register a new Yubikey device, enter a One Time Password from the Yubikey.', 'wp-simple-firewall' ),
44
- 'to_remove_device' => __( 'To remove a Yubikey device, enter the registered device ID and save.', 'wp-simple-firewall' ),
45
- 'multiple_for_pro' => sprintf( '[%s] %s', __( 'Pro Only', 'wp-simple-firewall' ),
 
46
  __( 'You may add as many Yubikey devices to your profile as you need to.', 'wp-simple-firewall' ) ),
47
- 'description_otp_code' => __( 'This is your unique Yubikey Device ID.', 'wp-simple-firewall' ),
48
- 'description_otp' => __( 'Provide a One Time Password from your Yubikey.', 'wp-simple-firewall' ),
49
- 'label_enter_code' => __( 'Yubikey ID', 'wp-simple-firewall' ),
50
- 'label_enter_otp' => __( 'Yubikey OTP', 'wp-simple-firewall' ),
51
- 'title' => __( 'Yubikey Authentication', 'wp-simple-firewall' ),
52
- 'cant_add_other_user' => sprintf( __( "Sorry, %s may not be added to another user's account.", 'wp-simple-firewall' ), 'Yubikey' ),
53
- 'cant_remove_admins' => sprintf( __( "Sorry, %s may only be removed from another user's account by a Security Administrator.", 'wp-simple-firewall' ), __( 'Yubikey', 'wp-simple-firewall' ) ),
54
- 'provided_by' => sprintf( __( 'Provided by %s', 'wp-simple-firewall' ), $con->getHumanName() ),
55
- 'remove_more_info' => sprintf( __( 'Understand how to remove Google Authenticator', 'wp-simple-firewall' ) )
56
  ],
57
  ];
58
-
59
- return $this->getMod()
60
- ->renderTemplate(
61
- '/snippets/user/profile/mfa/mfa_yubikey.twig',
62
- Services::DataManipulation()->mergeArraysRecursive( $this->getCommonData( $user ), $aData ),
63
- true
64
- );
65
  }
66
 
67
  /**
@@ -148,56 +132,88 @@ class Yubikey extends BaseProvider {
148
  }
149
 
150
  /**
151
- * @param string $sOTP
152
  * @return bool
153
  */
154
- private function sendYubiOtpRequest( $sOTP ) {
155
- /** @var LoginGuard\Options $oOpts */
156
- $oOpts = $this->getOptions();
157
- $sOTP = trim( $sOTP );
158
- $bSuccess = false;
159
-
160
- if ( preg_match( '#^[a-z]{44}$#', $sOTP ) ) {
161
- $aParts = [
162
- 'otp' => $sOTP,
163
  'nonce' => md5( uniqid( $this->getCon()->getUniqueRequestId() ) ),
164
- 'id' => $oOpts->getYubikeyAppId()
165
  ];
166
 
167
- $sResp = Services::HttpRequest()->getContent(
168
- add_query_arg( $aParts, self::URL_YUBIKEY_VERIFY )
169
- );
170
 
171
- unset( $aParts[ 'id' ] );
172
- $aParts[ 'status' ] = 'OK';
173
 
174
- $bSuccess = true;
175
- foreach ( $aParts as $sKey => $mVal ) {
176
- if ( !preg_match( sprintf( '#%s=%s#', $sKey, $mVal ), $sResp ) ) {
177
- $bSuccess = false;
178
  break;
179
  }
180
  }
181
  }
182
 
183
- return $bSuccess;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
  }
185
 
186
  /**
187
  * @param \WP_User $user
188
- * @param string $sKey
189
- * @param bool $bAdd - true to add; false to remove
190
  * @return $this
191
  */
192
- public function addRemoveRegisteredYubiId( \WP_User $user, $sKey, $bAdd = true ) {
193
- $aIDs = $this->getYubiIds( $user );
194
- if ( $bAdd ) {
195
- $aIDs[] = $sKey;
 
 
 
 
 
196
  }
197
  else {
198
- $aIDs = Services::DataManipulation()->removeFromArrayByValue( $aIDs, $sKey );
199
  }
200
- return $this->setSecret( $user, implode( ',', array_unique( array_filter( $aIDs ) ) ) );
201
  }
202
 
203
  /**
@@ -219,7 +235,7 @@ class Yubikey extends BaseProvider {
219
  /**
220
  * @return array
221
  */
222
- public function getFormField() {
223
  return [
224
  'name' => $this->getLoginFormParameter(),
225
  'type' => 'text',
@@ -250,4 +266,8 @@ class Yubikey extends BaseProvider {
250
  }
251
  return $bValid;
252
  }
 
 
 
 
253
  }
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor\Provider;
4
 
5
+ use FernleafSystems\Utilities\Data\Response\StdResponse;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
7
  use FernleafSystems\Wordpress\Services\Services;
8
 
12
  const OTP_LENGTH = 12;
13
  const URL_YUBIKEY_VERIFY = 'https://api.yubico.com/wsapi/2.0/verify';
14
 
15
+ public function getJavascriptVars() :array {
16
+ return [
17
+ 'ajax' => [
18
+ 'user_yubikey_toggle' => $this->getMod()->getAjaxActionData( 'user_yubikey_toggle' ),
19
+ 'user_yubikey_remove' => $this->getMod()->getAjaxActionData( 'user_yubikey_remove' )
20
+ ],
21
+ ];
 
 
 
 
 
 
 
 
 
22
  }
23
 
24
+ protected function getProviderSpecificRenderData( \WP_User $user ) :array {
25
  $con = $this->getCon();
26
+ return [
 
27
  'vars' => [
28
  'yubi_ids' => $this->getYubiIds( $user ),
29
  ],
30
  'strings' => [
31
+ 'registered_yubi_ids' => __( 'Registered Yubikey devices', 'wp-simple-firewall' ),
32
+ 'no_active_yubi_ids' => __( 'There are no registered Yubikey devices on this profile.', 'wp-simple-firewall' ),
33
+ 'placeholder_enter_otp' => __( 'Enter One Time Password From Yubikey', 'wp-simple-firewall' ),
34
+ 'enter_otp' => __( 'To register a new Yubikey device, enter a One Time Password from the Yubikey.', 'wp-simple-firewall' ),
35
+ 'to_remove_device' => __( 'To remove a Yubikey device, enter the registered device ID and save.', 'wp-simple-firewall' ),
36
+ 'multiple_for_pro' => sprintf( '[%s] %s', __( 'Pro Only', 'wp-simple-firewall' ),
37
  __( 'You may add as many Yubikey devices to your profile as you need to.', 'wp-simple-firewall' ) ),
38
+ 'description_otp_code' => __( 'This is your unique Yubikey Device ID.', 'wp-simple-firewall' ),
39
+ 'description_otp' => __( 'Provide a One Time Password from your Yubikey.', 'wp-simple-firewall' ),
40
+ 'label_enter_code' => __( 'Yubikey ID', 'wp-simple-firewall' ),
41
+ 'label_enter_otp' => __( 'Yubikey OTP', 'wp-simple-firewall' ),
42
+ 'title' => __( 'Yubikey Authentication', 'wp-simple-firewall' ),
43
+ 'cant_add_other_user' => sprintf( __( "Sorry, %s may not be added to another user's account.", 'wp-simple-firewall' ), 'Yubikey' ),
44
+ 'cant_remove_admins' => sprintf( __( "Sorry, %s may only be removed from another user's account by a Security Administrator.", 'wp-simple-firewall' ), __( 'Yubikey', 'wp-simple-firewall' ) ),
45
+ 'provided_by' => sprintf( __( 'Provided by %s', 'wp-simple-firewall' ), $con->getHumanName() ),
46
+ 'remove_more_info' => sprintf( __( 'Understand how to remove Google Authenticator', 'wp-simple-firewall' ) )
47
  ],
48
  ];
 
 
 
 
 
 
 
49
  }
50
 
51
  /**
132
  }
133
 
134
  /**
135
+ * @param string $otp
136
  * @return bool
137
  */
138
+ private function sendYubiOtpRequest( $otp ) {
139
+ /** @var LoginGuard\Options $opts */
140
+ $opts = $this->getOptions();
141
+ $otp = trim( $otp );
142
+ $success = false;
143
+
144
+ if ( preg_match( '#^[a-z]{44}$#', $otp ) ) {
145
+ $parts = [
146
+ 'otp' => $otp,
147
  'nonce' => md5( uniqid( $this->getCon()->getUniqueRequestId() ) ),
148
+ 'id' => $opts->getYubikeyAppId()
149
  ];
150
 
151
+ $response = Services::HttpRequest()->getContent( add_query_arg( $parts, self::URL_YUBIKEY_VERIFY ) );
 
 
152
 
153
+ unset( $parts[ 'id' ] );
154
+ $parts[ 'status' ] = 'OK';
155
 
156
+ $success = true;
157
+ foreach ( $parts as $key => $value ) {
158
+ if ( !preg_match( sprintf( '#%s=%s#', $key, $value ), $response ) ) {
159
+ $success = false;
160
  break;
161
  }
162
  }
163
  }
164
 
165
+ return $success;
166
+ }
167
+
168
+ public function toggleRegisteredYubiID( \WP_User $user, string $key ) :StdResponse {
169
+ $response = new StdResponse();
170
+ $response->success = true;
171
+
172
+ if ( strlen( $key ) > self::OTP_LENGTH ) {
173
+ $key = substr( $key, 0, self::OTP_LENGTH );
174
+ }
175
+ $IDs = $this->getYubiIds( $user );
176
+
177
+ if ( in_array( $key, $IDs ) ) {
178
+ $IDs = Services::DataManipulation()->removeFromArrayByValue( $IDs, $key );
179
+ $response->msg_text = sprintf(
180
+ __( '%s was removed from your profile.', 'wp-simple-firewall' ),
181
+ __( 'Yubikey Device', 'wp-simple-firewall' ).sprintf( ' (%s)', $key )
182
+ );
183
+ }
184
+ else {
185
+ $IDs[] = $key;
186
+ $response->msg_text = sprintf(
187
+ __( '%s was added to your profile.', 'wp-simple-firewall' ),
188
+ __( 'Yubikey Device', 'wp-simple-firewall' ).sprintf( ' (%s)', $key )
189
+ );
190
+ }
191
+
192
+ $this->setSecret( $user, implode( ',', array_unique( array_filter( $IDs ) ) ) );
193
+
194
+ return $response;
195
  }
196
 
197
  /**
198
  * @param \WP_User $user
199
+ * @param string $key
200
+ * @param bool $add - true to add; false to remove
201
  * @return $this
202
  */
203
+ public function addRemoveRegisteredYubiId( \WP_User $user, string $key, $add = true ) {
204
+ $IDs = $this->getYubiIds( $user );
205
+
206
+ if ( strlen( $key ) > self::OTP_LENGTH ) {
207
+ $key = substr( $key, 0, self::OTP_LENGTH );
208
+ }
209
+
210
+ if ( $add ) {
211
+ $IDs[] = $key;
212
  }
213
  else {
214
+ $IDs = Services::DataManipulation()->removeFromArrayByValue( $IDs, $key );
215
  }
216
+ return $this->setSecret( $user, implode( ',', array_unique( array_filter( $IDs ) ) ) );
217
  }
218
 
219
  /**
235
  /**
236
  * @return array
237
  */
238
+ public function getFormField() :array {
239
  return [
240
  'name' => $this->getLoginFormParameter(),
241
  'type' => 'text',
266
  }
267
  return $bValid;
268
  }
269
+
270
+ public function getProviderName() :string {
271
+ return 'Yubikey';
272
+ }
273
  }
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/UserProfile.php CHANGED
@@ -10,89 +10,89 @@ class UserProfile {
10
  use MfaControllerConsumer;
11
 
12
  public function run() {
13
- if ( is_admin() ) { // TODO: standalone UI based on shortcodes
14
  add_action( 'show_user_profile', [ $this, 'addOptionsToUserProfile' ] );
15
- add_action( 'personal_options_update', [ $this, 'handleUserProfileSubmit' ] );
16
- if ( $this->getMfaCon()->getCon()->isPluginAdmin() ) {
17
- add_action( 'edit_user_profile', [ $this, 'addOptionsToUserEditProfile' ] );
18
- add_action( 'edit_user_profile_update', [ $this, 'handleEditOtherUserProfileSubmit' ] );
19
- }
20
-
21
- $oWpUsers = Services::WpUsers();
22
- if ( $oWpUsers->isUserLoggedIn() ) {
23
- $oMC = $this->getMfaCon();
24
- foreach ( $oMC->getProvidersForUser( $oWpUsers->getCurrentWpUser(), false ) as $oP ) {
25
- $oP->setupProfile();
26
- }
27
- }
28
  }
29
  }
30
 
31
  /**
32
  * This MUST only ever be hooked into when the User is looking at their OWN profile, so we can use "current user"
33
  * functions. Otherwise we need to be careful of mixing up users.
34
- * @param \WP_User $oUser
35
  */
36
- public function addOptionsToUserProfile( $oUser ) {
37
  $oMC = $this->getMfaCon();
38
- $oWpUsers = Services::WpUsers();
39
- $aProviders = $oMC->getProvidersForUser( $oUser );
40
- if ( count( $aProviders ) > 0 ) {
41
- $aRows = [];
42
- foreach ( $aProviders as $oProvider ) {
43
- $aRows[ $oProvider::SLUG ] = $oProvider->renderUserProfileOptions( $oUser );
44
  }
45
 
46
- $aData = [
47
- 'is_my_user_profile' => ( $oUser->ID == $oWpUsers->getCurrentWpUserId() ),
48
- 'i_am_valid_admin' => $oMC->getCon()->isPluginAdmin(),
49
- 'user_to_edit_is_admin' => $oWpUsers->isUserAdmin( $oUser ),
50
- 'strings' => [
51
- 'title' => __( 'Multi-Factor Authentication', 'wp-simple-firewall' ),
52
- 'provided_by' => sprintf( __( 'Provided by %s', 'wp-simple-firewall' ), $oMC->getCon()
53
- ->getHumanName() )
54
- ],
55
- 'mfa_rows' => $aRows,
56
- ];
57
-
58
  echo $oMC->getMod()
59
  ->renderTemplate(
60
- '/snippets/user/profile/mfa/mfa_container.twig',
61
- $aData,
 
 
 
 
 
 
 
 
62
  true
63
  );
64
  }
65
  }
66
 
67
- /**
68
- * This MUST only ever be hooked into when the User is looking at their OWN profile,
69
- * so we can use "current user" functions. Otherwise we need to be careful of mixing up users.
70
- * @param int $nSavingUserId
71
- */
72
- public function handleUserProfileSubmit( $nSavingUserId ) {
73
- $oUser = Services::WpUsers()->getUserById( $nSavingUserId );
74
- foreach ( $this->getMfaCon()->getProvidersForUser( $oUser ) as $oProvider ) {
75
- $oProvider->handleUserProfileSubmit( $oUser );
76
- }
77
- }
78
-
79
  /**
80
  * ONLY TO BE HOOKED TO USER PROFILE EDIT
81
- * @param \WP_User $oUser
82
  */
83
- public function addOptionsToUserEditProfile( $oUser ) {
84
- $this->addOptionsToUserProfile( $oUser );
85
- }
 
 
86
 
87
- /**
88
- * The only thing we can do is REMOVE Google Authenticator from an account that is not our own
89
- * But, only admins can do this. If Security Admin feature is enabled, then only they can do it.
90
- * @param int $nSavingUserId
91
- */
92
- public function handleEditOtherUserProfileSubmit( $nSavingUserId ) {
93
- $oUser = Services::WpUsers()->getUserById( $nSavingUserId );
94
- foreach ( $this->getMfaCon()->getProvidersForUser( $oUser ) as $oProvider ) {
95
- $oProvider->handleEditOtherUserProfileSubmit( $oUser );
96
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  }
98
  }
10
  use MfaControllerConsumer;
11
 
12
  public function run() {
13
+ if ( is_admin() ) {
14
  add_action( 'show_user_profile', [ $this, 'addOptionsToUserProfile' ] );
15
+ add_action( 'edit_user_profile', [ $this, 'addOptionsToUserEditProfile' ] );
 
 
 
 
 
 
 
 
 
 
 
 
16
  }
17
  }
18
 
19
  /**
20
  * This MUST only ever be hooked into when the User is looking at their OWN profile, so we can use "current user"
21
  * functions. Otherwise we need to be careful of mixing up users.
22
+ * @param \WP_User $user
23
  */
24
+ public function addOptionsToUserProfile( $user ) {
25
  $oMC = $this->getMfaCon();
26
+ $WPU = Services::WpUsers();
27
+ $providers = $oMC->getProvidersForUser( $user );
28
+ if ( count( $providers ) > 0 ) {
29
+ $rows = [];
30
+ foreach ( $providers as $provider ) {
31
+ $rows[ $provider::SLUG ] = $provider->renderUserProfileOptions( $user );
32
  }
33
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  echo $oMC->getMod()
35
  ->renderTemplate(
36
+ '/admin/user/profile/mfa/mfa_container.twig',
37
+ [
38
+ 'user_to_edit_is_admin' => $WPU->isUserAdmin( $user ),
39
+ 'strings' => [
40
+ 'title' => __( 'Multi-Factor Authentication', 'wp-simple-firewall' ),
41
+ 'provided_by' => sprintf( __( 'Provided by %s', 'wp-simple-firewall' ), $oMC->getCon()
42
+ ->getHumanName() )
43
+ ],
44
+ 'mfa_rows' => $rows,
45
+ ],
46
  true
47
  );
48
  }
49
  }
50
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  /**
52
  * ONLY TO BE HOOKED TO USER PROFILE EDIT
53
+ * @param \WP_User $user
54
  */
55
+ public function addOptionsToUserEditProfile( $user ) {
56
+ $mfaCon = $this->getMfaCon();
57
+ $con = $mfaCon->getCon();
58
+ $WPU = Services::WpUsers();
59
+ $pluginName = $con->getHumanName();
60
 
61
+ $providers = array_map(
62
+ function ( $provider ) {
63
+ return $provider->getProviderName();
64
+ },
65
+ $mfaCon->getProvidersForUser( $user, true )
66
+ );
67
+
68
+ echo $mfaCon->getMod()
69
+ ->renderTemplate(
70
+ '/admin/user/profile/mfa/remove_for_other_user.twig',
71
+ [
72
+ 'flags' => [
73
+ 'has_factors' => count( $providers ) > 0,
74
+ 'is_admin_profile' => $WPU->isUserAdmin( $user ),
75
+ 'can_remove' => $con->isPluginAdmin() || !$WPU->isUserAdmin( $user ),
76
+ ],
77
+ 'vars' => [
78
+ 'user_id' => $user->ID,
79
+ 'mfa_factor_names' => $providers,
80
+ ],
81
+ 'strings' => [
82
+ 'title' => __( 'Multi-Factor Authentication', 'wp-simple-firewall' ),
83
+ 'provided_by' => sprintf( __( 'Provided by %s', 'wp-simple-firewall' ), $pluginName ),
84
+ 'currently_active' => __( 'Currently active MFA Providers on this profile are' ),
85
+ 'remove_all' => __( 'Remove All MFA Providers' ),
86
+ 'remove_all_from' => __( 'Remove All MFA Providers From This User Profile' ),
87
+ 'remove_warning' => __( "Certain providers may not be removed if they're enforced." ),
88
+ 'no_providers' => __( 'There are no MFA providers active on this user account.' ),
89
+ 'only_secadmin' => sprintf( __( 'Only %s Security Admins may modify the MFA settings of another admin account.' ),
90
+ $pluginName ),
91
+ 'authenticate' => sprintf( __( 'You may authenticate with the %s Security Admin system and return here.' ),
92
+ $pluginName ),
93
+ ],
94
+ ],
95
+ true
96
+ );
97
  }
98
  }
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/ValidateLoginIntentRequest.php CHANGED
@@ -33,12 +33,12 @@ class ValidateLoginIntentRequest {
33
 
34
  $validated = false;
35
  { // Backup code is special case
36
- if ( isset( $providers[ Provider\Backup::SLUG ] ) ) {
37
- if ( $providers[ Provider\Backup::SLUG ]->validateLoginIntent( $user ) ) {
38
  $validated = true;
39
- $aSuccessfulProviders[] = $providers[ Provider\Backup::SLUG ];
40
  }
41
- unset( $providers[ Provider\Backup::SLUG ] );
42
  }
43
  }
44
 
33
 
34
  $validated = false;
35
  { // Backup code is special case
36
+ if ( isset( $providers[ Provider\BackupCodes::SLUG ] ) ) {
37
+ if ( $providers[ Provider\BackupCodes::SLUG ]->validateLoginIntent( $user ) ) {
38
  $validated = true;
39
+ $aSuccessfulProviders[] = $providers[ Provider\BackupCodes::SLUG ];
40
  }
41
+ unset( $providers[ Provider\BackupCodes::SLUG ] );
42
  }
43
  }
44
 
src/lib/src/Modules/LoginGuard/ModCon.php CHANGED
@@ -266,8 +266,8 @@ class ModCon extends BaseShield\ModCon {
266
  return $text;
267
  }
268
 
269
- public function setEnabledGaspCheck( bool $enable ) {
270
- $this->getOptions()->setOpt( 'enable_login_gasp_check', $enable ? 'Y' : 'N' );
271
  }
272
 
273
  public function getScriptLocalisations() :array {
@@ -276,8 +276,10 @@ class ModCon extends BaseShield\ModCon {
276
  'global-plugin',
277
  'icwp_wpsf_vars_lg',
278
  [
279
- 'ajax_gen_backup_codes' => $this->getAjaxActionData( 'gen_backup_codes' ),
280
- 'ajax_del_backup_codes' => $this->getAjaxActionData( 'del_backup_codes' ),
 
 
281
  ]
282
  ];
283
  return $locals;
266
  return $text;
267
  }
268
 
269
+ public function setEnabledAntiBotDetection( bool $enable ) {
270
+ $this->getOptions()->setOpt( 'enable_antibot_check', $enable ? 'Y' : 'N' );
271
  }
272
 
273
  public function getScriptLocalisations() :array {
276
  'global-plugin',
277
  'icwp_wpsf_vars_lg',
278
  [
279
+ 'ajax' => [
280
+ 'gen_backup_codes' => $this->getAjaxActionData( 'gen_backup_codes' ),
281
+ 'del_backup_codes' => $this->getAjaxActionData( 'del_backup_codes' ),
282
+ ],
283
  ]
284
  ];
285
  return $locals;
src/lib/src/Modules/LoginGuard/Options.php CHANGED
@@ -6,6 +6,10 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
6
 
7
  class Options extends BaseShield\Options {
8
 
 
 
 
 
9
  public function getLoginIntentMinutes() :int {
10
  return (int)max( 1, apply_filters(
11
  $this->getCon()->prefix( 'login_intent_timeout' ),
6
 
7
  class Options extends BaseShield\Options {
8
 
9
+ public function getBotProtectionLocations() :array {
10
+ return is_array( $this->getOpt( 'bot_protection_locations' ) ) ? $this->getOpt( 'bot_protection_locations' ) : [];
11
+ }
12
+
13
  public function getLoginIntentMinutes() :int {
14
  return (int)max( 1, apply_filters(
15
  $this->getCon()->prefix( 'login_intent_timeout' ),
src/lib/src/Modules/LoginGuard/Strings.php CHANGED
@@ -144,6 +144,7 @@ class Strings extends Base\Strings {
144
  * @throws \Exception
145
  */
146
  public function getOptionStrings( string $key ) :array {
 
147
  /** @var ModCon $mod */
148
  $mod = $this->getMod();
149
  $modName = $mod->getMainFeatureName();
@@ -211,7 +212,10 @@ class Strings extends Base\Strings {
211
 
212
  case 'enable_google_recaptcha_login' :
213
  $name = __( 'CAPTCHA', 'wp-simple-firewall' );
214
- $summary = __( 'Protect WordPress Account Access Requests With CAPTCHA', 'wp-simple-firewall' );
 
 
 
215
  $desc = __( 'Use CAPTCHA on the user account forms such as login, register, etc.', 'wp-simple-firewall' ).'<br />'
216
  .sprintf( __( 'Use of any theme other than "%s", requires a Pro license.', 'wp-simple-firewall' ), __( 'Light Theme', 'wp-simple-firewall' ) )
217
  .'<br/>'.sprintf( '%s - %s', __( 'Note', 'wp-simple-firewall' ), __( "You'll need to setup your CAPTCHA API Keys in 'General' settings.", 'wp-simple-firewall' ) )
@@ -219,11 +223,11 @@ class Strings extends Base\Strings {
219
  break;
220
 
221
  case 'enable_antibot_check' :
222
- $name = __( 'AntiBot Detection Engine', 'wp-simple-firewall' );
223
- $summary = __( "Use AntiBot Detection Engine To Detect Bots", 'wp-simple-firewall' );
224
  $desc = [
225
  sprintf( __( "AntiBot Detection Engine is %s's exclusive bot-detection technology that removes the needs for CAPTCHA and other challenges.", 'wp-simple-firewall' ),
226
- $this->getCon()->getHumanName() ),
227
  __( 'This feature is designed to replace the CAPTCHA and Bot Protection options.', 'wp-simple-firewall' ),
228
  sprintf( '%s - %s', __( 'Important', 'wp-simple-firewall' ),
229
  __( "Switching on this feature will disable the CAPTCHA and Bot Protection settings.", 'wp-simple-firewall' ) )
@@ -233,22 +237,35 @@ class Strings extends Base\Strings {
233
  case 'bot_protection_locations' :
234
  $name = __( 'Protection Locations', 'wp-simple-firewall' );
235
  $summary = __( 'Which Forms Should Be Protected', 'wp-simple-firewall' );
236
- $desc = __( 'Choose the forms for which bot protection measures will be deployed.', 'wp-simple-firewall' ).'<br />'
237
- .sprintf( '%s - %s', __( 'Note', 'wp-simple-firewall' ), sprintf( __( "Use with 3rd party systems such as %s, requires a Pro license.", 'wp-simple-firewall' ), 'WooCommerce' ) );
 
 
 
 
 
238
  break;
239
 
240
  case 'enable_login_gasp_check' :
241
  $name = __( 'Bot Protection', 'wp-simple-firewall' );
242
- $summary = __( 'Protect WP Login From Automated Login Attempts By Bots', 'wp-simple-firewall' );
243
- $desc = __( 'Adds a dynamically (Javascript) generated checkbox to the login form that prevents bots using automated login techniques.', 'wp-simple-firewall' )
244
- .'<br />'.sprintf( '%s: %s', __( 'Recommendation', 'wp-simple-firewall' ), __( 'ON', 'wp-simple-firewall' ) );
 
 
 
 
 
245
  break;
246
 
247
  case 'antibot_form_ids' :
248
  $name = __( 'AntiBot Forms', 'wp-simple-firewall' );
249
- $summary = __( 'Enter The Selectors Of The 3rd Party Login Forms For Use With AntiBot JS', 'wp-simple-firewall' );
 
 
 
250
  $desc = [
251
- __( 'Provide DOM selectors to attached AntiBot protection to any form.', 'wp-simple-firewall' ),
252
  __( 'IDs are prefixed with "#".', 'wp-simple-firewall' ),
253
  __( 'Classes are prefixed with ".".', 'wp-simple-firewall' ),
254
  __( 'IDs are preferred over classes.', 'wp-simple-firewall' )
@@ -276,7 +293,6 @@ class Strings extends Base\Strings {
276
  $desc = [
277
  __( 'Allow users to register U2F devices to complete their login.', 'wp-simple-firewall' ),
278
  __( "Currently only U2F keys are supported. Built-in fingerprint scanners aren't supported (yet).", 'wp-simple-firewall' ),
279
- __( "Beta! This may only be used when at least 1 other 2FA option is enabled on a user account.", 'wp-simple-firewall' ),
280
  ];
281
  break;
282
 
144
  * @throws \Exception
145
  */
146
  public function getOptionStrings( string $key ) :array {
147
+ $con = $this->getCon();
148
  /** @var ModCon $mod */
149
  $mod = $this->getMod();
150
  $modName = $mod->getMainFeatureName();
212
 
213
  case 'enable_google_recaptcha_login' :
214
  $name = __( 'CAPTCHA', 'wp-simple-firewall' );
215
+ $summary = sprintf( '[DEPRECATED - %s] : %s',
216
+ 'Please use the newer AntiBot setting above',
217
+ __( 'Protect WordPress Account Access Requests With CAPTCHA', 'wp-simple-firewall' )
218
+ );
219
  $desc = __( 'Use CAPTCHA on the user account forms such as login, register, etc.', 'wp-simple-firewall' ).'<br />'
220
  .sprintf( __( 'Use of any theme other than "%s", requires a Pro license.', 'wp-simple-firewall' ), __( 'Light Theme', 'wp-simple-firewall' ) )
221
  .'<br/>'.sprintf( '%s - %s', __( 'Note', 'wp-simple-firewall' ), __( "You'll need to setup your CAPTCHA API Keys in 'General' settings.", 'wp-simple-firewall' ) )
223
  break;
224
 
225
  case 'enable_antibot_check' :
226
+ $name = __( 'AntiBot Detection Engine (ADE)', 'wp-simple-firewall' );
227
+ $summary = __( 'Use ADE To Detect Bots And Block Brute Force Logins', 'wp-simple-firewall' );
228
  $desc = [
229
  sprintf( __( "AntiBot Detection Engine is %s's exclusive bot-detection technology that removes the needs for CAPTCHA and other challenges.", 'wp-simple-firewall' ),
230
+ $con->getHumanName() ),
231
  __( 'This feature is designed to replace the CAPTCHA and Bot Protection options.', 'wp-simple-firewall' ),
232
  sprintf( '%s - %s', __( 'Important', 'wp-simple-firewall' ),
233
  __( "Switching on this feature will disable the CAPTCHA and Bot Protection settings.", 'wp-simple-firewall' ) )
237
  case 'bot_protection_locations' :
238
  $name = __( 'Protection Locations', 'wp-simple-firewall' );
239
  $summary = __( 'Which Forms Should Be Protected', 'wp-simple-firewall' );
240
+ $desc = [
241
+ __( 'Choose the forms for which bot protection measures will be deployed.', 'wp-simple-firewall' ),
242
+ sprintf( '%s - %s', __( 'Note', 'wp-simple-firewall' ), sprintf( __( "Use with 3rd party systems such as %s, requires a Pro license.", 'wp-simple-firewall' ), 'WooCommerce' ) ),
243
+ sprintf( '<a href="%s">%s</a>', $con->getModule_Integrations()
244
+ ->getUrl_DirectLinkToSection( 'section_user_forms' ),
245
+ sprintf( __( "Choose the 3rd party plugins you want %s to also integrate with.", 'wp-simple-firewall' ), $con->getHumanName() ) )
246
+ ];
247
  break;
248
 
249
  case 'enable_login_gasp_check' :
250
  $name = __( 'Bot Protection', 'wp-simple-firewall' );
251
+ $summary = sprintf( '[DEPRECATED - %s] %s',
252
+ 'Please use the newer AntiBot setting above',
253
+ __( 'Protect WP Login From Automated Login Attempts By Bots', 'wp-simple-firewall' )
254
+ );
255
+ $desc = [
256
+ __( 'Adds a dynamically (Javascript) generated checkbox to the login form that prevents bots using automated login techniques.', 'wp-simple-firewall' ),
257
+ sprintf( '%s: %s', __( 'Recommendation', 'wp-simple-firewall' ), __( 'ON', 'wp-simple-firewall' ) )
258
+ ];
259
  break;
260
 
261
  case 'antibot_form_ids' :
262
  $name = __( 'AntiBot Forms', 'wp-simple-firewall' );
263
+ $summary = sprintf( '%s %s',
264
+ '[DEPRECATED - Please use the newer AntiBot setting above]',
265
+ __( 'Enter The Selectors Of The 3rd Party Login Forms For Use With AntiBot JS', 'wp-simple-firewall' )
266
+ );
267
  $desc = [
268
+ __( 'Provide DOM selectors to attach AntiBot protection to any form.', 'wp-simple-firewall' ),
269
  __( 'IDs are prefixed with "#".', 'wp-simple-firewall' ),
270
  __( 'Classes are prefixed with ".".', 'wp-simple-firewall' ),
271
  __( 'IDs are preferred over classes.', 'wp-simple-firewall' )
293
  $desc = [
294
  __( 'Allow users to register U2F devices to complete their login.', 'wp-simple-firewall' ),
295
  __( "Currently only U2F keys are supported. Built-in fingerprint scanners aren't supported (yet).", 'wp-simple-firewall' ),
 
296
  ];
297
  break;
298
 
src/lib/src/Modules/LoginGuard/UI.php CHANGED
@@ -8,12 +8,34 @@ use FernleafSystems\Wordpress\Plugin\Shield\Utilities\Time\WorldTimeApi;
8
  class UI extends BaseShield\UI {
9
 
10
  protected function getSectionWarnings( string $section ) :array {
 
 
 
 
11
  $warnings = [];
12
 
13
- if ( $section == 'section_brute_force_login_protection' && !$this->getCon()->isPremiumActive() ) {
14
- $sIntegration = $this->getPremiumOnlyIntegration();
15
- if ( !empty( $sIntegration ) ) {
16
- $warnings[] = sprintf( __( 'Support for login protection with %s is a Pro-only feature.', 'wp-simple-firewall' ), $sIntegration );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  }
18
  }
19
 
@@ -37,24 +59,4 @@ class UI extends BaseShield\UI {
37
 
38
  return $warnings;
39
  }
40
-
41
- /**
42
- * @return string
43
- */
44
- private function getPremiumOnlyIntegration() {
45
- $aIntegrations = [
46
- 'WooCommerce' => 'WooCommerce',
47
- 'Easy_Digital_Downloads' => 'Easy Digital Downloads',
48
- 'BuddyPress' => 'BuddyPress',
49
- ];
50
-
51
- $sIntegration = '';
52
- foreach ( $aIntegrations as $classToIntegrate => $sName ) {
53
- if ( class_exists( $classToIntegrate ) ) {
54
- $sIntegration = $sName;
55
- break;
56
- }
57
- }
58
- return $sIntegration;
59
- }
60
  }
8
  class UI extends BaseShield\UI {
9
 
10
  protected function getSectionWarnings( string $section ) :array {
11
+ $con = $this->getCon();
12
+ /** @var Options $opts */
13
+ $opts = $this->getOptions();
14
+
15
  $warnings = [];
16
 
17
+ if ( $section == 'section_brute_force_login_protection' ) {
18
+
19
+ if ( empty( $opts->getBotProtectionLocations() ) ) {
20
+ $warnings[] = __( "AntiBot detection isn't being applied to your site because you haven't selected any forms to protect, such as Login or Register.", 'wp-simple-firewall' );
21
+ }
22
+
23
+ $installedButNotEnabledProviders = array_filter(
24
+ $con->getModule_Integrations()
25
+ ->getController_UserForms()
26
+ ->getInstalledProviders(),
27
+ function ( $provider ) {
28
+ return !$provider->isEnabled();
29
+ }
30
+ );
31
+ if ( !empty( $installedButNotEnabledProviders ) ) {
32
+ $warnings[] = sprintf( __( "%s has an integration available to protect the login forms of a 3rd party plugin you're using: %s", 'wp-simple-firewall' ),
33
+ $con->getHumanName(),
34
+ sprintf( '<a href="%s">%s</a>',
35
+ $con->getModule_Integrations()->getUrl_DirectLinkToSection( 'section_user_forms' ),
36
+ sprintf( __( "View the available integrations.", 'wp-simple-firewall' ), $con->getHumanName() )
37
+ )
38
+ );
39
  }
40
  }
41
 
59
 
60
  return $warnings;
61
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  }
src/lib/src/Modules/Plugin/AdminNotices.php CHANGED
@@ -249,13 +249,16 @@ class AdminNotices extends Shield\Modules\Base\AdminNotices {
249
 
250
  private function buildNotice_WelcomeWizard( NoticeVO $notice ) {
251
  $name = $this->getCon()->getHumanName();
 
252
  $notice->render_data = [
253
- 'notice_attributes' => [],
 
 
254
  'strings' => [
255
  'dismiss' => __( "I don't need the setup wizard just now", 'wp-simple-firewall' ),
256
  'title' => sprintf( __( 'Get started quickly with the %s Setup Wizard', 'wp-simple-firewall' ), $name ),
257
  'setup' => sprintf( __( 'The welcome wizard will help you get setup quickly and become familiar with some of the core %s features', 'wp-simple-firewall' ), $name ),
258
- 'launch' => sprintf( __( "Launch the welcome wizard", 'wp-simple-firewall' ), $name ),
259
  ],
260
  'hrefs' => [
261
  'wizard' => $this->getMod()->getUrl_Wizard( 'welcome' ),
@@ -311,11 +314,15 @@ class AdminNotices extends Shield\Modules\Base\AdminNotices {
311
 
312
  protected function isDisplayNeeded( NoticeVO $notice ) :bool {
313
  $con = $this->getCon();
314
- /** @var Options $oOpts */
315
- $oOpts = $this->getOptions();
316
 
317
  switch ( $notice->id ) {
318
 
 
 
 
 
319
  case 'plugin-too-old':
320
  $needed = $this->isNeeded_PluginTooOld();
321
  break;
@@ -329,7 +336,7 @@ class AdminNotices extends Shield\Modules\Base\AdminNotices {
329
  break;
330
 
331
  case 'plugin-disabled':
332
- $needed = $oOpts->isPluginGloballyDisabled();
333
  break;
334
 
335
  case 'update-available':
@@ -341,7 +348,7 @@ class AdminNotices extends Shield\Modules\Base\AdminNotices {
341
  break;
342
 
343
  case 'allow-tracking':
344
- $needed = !$oOpts->isTrackingPermissionSet();
345
  break;
346
 
347
  default:
249
 
250
  private function buildNotice_WelcomeWizard( NoticeVO $notice ) {
251
  $name = $this->getCon()->getHumanName();
252
+ $insideWizard = Services::Request()->query( 'wizard', false ) === 'welcome';
253
  $notice->render_data = [
254
+ 'notice_attributes' => [
255
+ 'insideWizard' => $insideWizard ? 1 : 0,
256
+ ],
257
  'strings' => [
258
  'dismiss' => __( "I don't need the setup wizard just now", 'wp-simple-firewall' ),
259
  'title' => sprintf( __( 'Get started quickly with the %s Setup Wizard', 'wp-simple-firewall' ), $name ),
260
  'setup' => sprintf( __( 'The welcome wizard will help you get setup quickly and become familiar with some of the core %s features', 'wp-simple-firewall' ), $name ),
261
+ 'launch' => sprintf( __( "Launch the welcome wizard", 'wp-simple-firewall' ), $name ),
262
  ],
263
  'hrefs' => [
264
  'wizard' => $this->getMod()->getUrl_Wizard( 'welcome' ),
314
 
315
  protected function isDisplayNeeded( NoticeVO $notice ) :bool {
316
  $con = $this->getCon();
317
+ /** @var Options $opts */
318
+ $opts = $this->getOptions();
319
 
320
  switch ( $notice->id ) {
321
 
322
+ case 'wizard_welcome':
323
+ $needed = false;
324
+ break;
325
+
326
  case 'plugin-too-old':
327
  $needed = $this->isNeeded_PluginTooOld();
328
  break;
336
  break;
337
 
338
  case 'plugin-disabled':
339
+ $needed = $opts->isPluginGloballyDisabled();
340
  break;
341
 
342
  case 'update-available':
348
  break;
349
 
350
  case 'allow-tracking':
351
+ $needed = !$opts->isTrackingPermissionSet();
352
  break;
353
 
354
  default:
src/lib/src/Modules/Plugin/AjaxHandler.php CHANGED
@@ -56,6 +56,9 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
56
  $response = $this->ajaxExec_MarkTourFinished();
57
  break;
58
 
 
 
 
59
  default:
60
  $response = parent::processAjaxAction( $action );
61
  }
@@ -63,6 +66,18 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
63
  return $response;
64
  }
65
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  private function ajaxExec_PluginBadgeClose() :array {
67
  /** @var ModCon $mod */
68
  $mod = $this->getMod();
56
  $response = $this->ajaxExec_MarkTourFinished();
57
  break;
58
 
59
+ case 'wizard_step':
60
+ $response = $this->ajaxExec_Wizard();
61
+ break;
62
  default:
63
  $response = parent::processAjaxAction( $action );
64
  }
66
  return $response;
67
  }
68
 
69
+ private function ajaxExec_Wizard() {
70
+ $params = FormParams::Retrieve();
71
+ // step will be step1, step2 etc.
72
+ $currentStep = intval( str_replace( 'step', '', $params[ 'step' ] ) );
73
+ $data = $params[ $params[ 'step' ] ];
74
+ return [
75
+ 'success' => true,
76
+ 'message' => $currentStep < 3 ? $data : 'done done done',
77
+ 'next' => $currentStep < 3 ? 'step'.++$currentStep : 'done',
78
+ ];
79
+ }
80
+
81
  private function ajaxExec_PluginBadgeClose() :array {
82
  /** @var ModCon $mod */
83
  $mod = $this->getMod();
src/lib/src/Modules/Plugin/Components/PluginBadge.php CHANGED
@@ -17,8 +17,12 @@ class PluginBadge {
17
  public function run() {
18
  /** @var Plugin\Options $opts */
19
  $opts = $this->getOptions();
20
- $display = $opts->isOpt( 'display_plugin_badge', 'Y' )
21
- && ( Services::Request()->cookie( $this->getCookieIdBadgeState() ) != 'closed' );
 
 
 
 
22
  if ( $display ) {
23
  add_action( 'wp_enqueue_scripts', [ $this, 'includeJquery' ] );
24
  add_action( 'login_enqueue_scripts', [ $this, 'includeJquery' ] );
@@ -63,10 +67,11 @@ class PluginBadge {
63
  */
64
  public function render( $isFloating = false ) {
65
  $con = $this->getCon();
66
- /** @var Modules\SecurityAdmin\Options $secAdminOpts */
67
- $secAdminOpts = $con->getModule_SecAdmin()->getOptions();
68
 
69
- if ( $secAdminOpts->isEnabledWhitelabel() && $secAdminOpts->isReplacePluginBadge() ) {
 
 
70
  $badgeUrl = $secAdminOpts->getOpt( 'wl_homeurl' );
71
  $name = $secAdminOpts->getOpt( 'wl_pluginnamemain' );
72
  $logo = $secAdminOpts->getOpt( 'wl_dashboardlogourl' );
17
  public function run() {
18
  /** @var Plugin\Options $opts */
19
  $opts = $this->getOptions();
20
+ $req = Services::Request();
21
+
22
+ $display = apply_filters( 'shield/show_security_badge',
23
+ $opts->isOpt( 'display_plugin_badge', 'Y' ) && ( $req->cookie( $this->getCookieIdBadgeState() ) != 'closed' )
24
+ );
25
+
26
  if ( $display ) {
27
  add_action( 'wp_enqueue_scripts', [ $this, 'includeJquery' ] );
28
  add_action( 'login_enqueue_scripts', [ $this, 'includeJquery' ] );
67
  */
68
  public function render( $isFloating = false ) {
69
  $con = $this->getCon();
70
+ $wlCon = $con->getModule_SecAdmin()->getWhiteLabelController();
 
71
 
72
+ if ( $wlCon->isEnabled() && $wlCon->isReplacePluginBadge() ) {
73
+ /** @var Modules\SecurityAdmin\Options $secAdminOpts */
74
+ $secAdminOpts = $con->getModule_SecAdmin()->getOptions();
75
  $badgeUrl = $secAdminOpts->getOpt( 'wl_homeurl' );
76
  $name = $secAdminOpts->getOpt( 'wl_pluginnamemain' );
77
  $logo = $secAdminOpts->getOpt( 'wl_dashboardlogourl' );
src/lib/src/Modules/Plugin/Insights/OverviewCards.php CHANGED
@@ -9,29 +9,19 @@ use FernleafSystems\Wordpress\Services\Utilities\Ssl;
9
 
10
  class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
11
 
12
- public function build() :array {
13
  /** @var Plugin\ModCon $mod */
14
  $mod = $this->getMod();
15
  /** @var Plugin\Options $opts */
16
  $opts = $this->getOptions();
17
 
18
- $cardSection = [
19
- 'title' => __( 'General Settings', 'wp-simple-firewall' ),
20
- 'subtitle' => sprintf( __( 'General %s Settings', 'wp-simple-firewall' ),
21
- $this->getCon()->getHumanName() ),
22
- 'href_options' => $mod->getUrl_AdminPage()
23
- ];
24
-
25
  $cards = [];
26
 
27
- if ( !$mod->isModuleEnabled() ) {
28
- $cards[] = $this->getModDisabledCard();
29
- }
30
- else {
31
  $bHasSupportEmail = Services::Data()->validEmail( $opts->getOpt( 'block_send_email_address' ) );
32
  $cards[ 'reports' ] = [
33
  'name' => __( 'Reporting Email', 'wp-simple-firewall' ),
34
- 'state' => $bHasSupportEmail ? 1 : -1,
35
  'summary' => $bHasSupportEmail ?
36
  sprintf( __( 'Email address for reports set to: %s', 'wp-simple-firewall' ), $mod->getPluginReportEmail() )
37
  : sprintf( __( 'No reporting address provided - defaulting to: %s', 'wp-simple-firewall' ), $mod->getPluginReportEmail() ),
@@ -57,14 +47,20 @@ class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
57
  ];
58
  }
59
 
60
- $cards = array_merge(
61
  $cards,
62
  $this->getNoticesSsl(),
63
  $this->getNoticesDb()
64
  );
 
 
 
 
 
65
 
66
- $cardSection[ 'cards' ] = $cards;
67
- return [ 'plugin' => $cardSection ];
 
68
  }
69
 
70
  private function getNoticesDb() :array {
9
 
10
  class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
11
 
12
+ protected function buildModCards() :array {
13
  /** @var Plugin\ModCon $mod */
14
  $mod = $this->getMod();
15
  /** @var Plugin\Options $opts */
16
  $opts = $this->getOptions();
17
 
 
 
 
 
 
 
 
18
  $cards = [];
19
 
20
+ if ( $mod->isModOptEnabled() ) {
 
 
 
21
  $bHasSupportEmail = Services::Data()->validEmail( $opts->getOpt( 'block_send_email_address' ) );
22
  $cards[ 'reports' ] = [
23
  'name' => __( 'Reporting Email', 'wp-simple-firewall' ),
24
+ 'state' => $bHasSupportEmail ? 1 : 0,
25
  'summary' => $bHasSupportEmail ?
26
  sprintf( __( 'Email address for reports set to: %s', 'wp-simple-firewall' ), $mod->getPluginReportEmail() )
27
  : sprintf( __( 'No reporting address provided - defaulting to: %s', 'wp-simple-firewall' ), $mod->getPluginReportEmail() ),
47
  ];
48
  }
49
 
50
+ return array_merge(
51
  $cards,
52
  $this->getNoticesSsl(),
53
  $this->getNoticesDb()
54
  );
55
+ }
56
+
57
+ protected function getSectionTitle() :string {
58
+ return __( 'General Settings', 'wp-simple-firewall' );
59
+ }
60
 
61
+ protected function getSectionSubTitle() :string {
62
+ return sprintf( __( 'General %s Settings', 'wp-simple-firewall' ),
63
+ $this->getCon()->getHumanName() );
64
  }
65
 
66
  private function getNoticesDb() :array {
src/lib/src/Modules/Plugin/Lib/PluginTelemetry.php CHANGED
@@ -2,21 +2,18 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Lib;
4
 
5
- use FernleafSystems\Utilities\Logic\ExecOnce;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Crons\PluginCronsConsumer;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Events\Select;
 
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\ModCon;
9
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
10
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin;
11
  use FernleafSystems\Wordpress\Services\Services;
12
 
13
- class PluginTelemetry {
14
 
15
- use ModConsumer;
16
- use ExecOnce;
17
  use PluginCronsConsumer;
18
 
19
- protected function canRun() :bool {
20
  /** @var Plugin\Options $opts */
21
  $opts = $this->getOptions();
22
  return $opts->isTrackingEnabled() || !$opts->isTrackingPermissionSet();
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Lib;
4
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Crons\PluginCronsConsumer;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Events\Select;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\ModCon;
 
9
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin;
10
  use FernleafSystems\Wordpress\Services\Services;
11
 
12
+ class PluginTelemetry extends ExecOnceModConsumer {
13
 
 
 
14
  use PluginCronsConsumer;
15
 
16
+ protected function canRun() :bool {
17
  /** @var Plugin\Options $opts */
18
  $opts = $this->getOptions();
19
  return $opts->isTrackingEnabled() || !$opts->isTrackingPermissionSet();
src/lib/src/Modules/Plugin/Strings.php CHANGED
@@ -235,7 +235,7 @@ class Strings extends Base\Strings {
235
 
236
  case 'display_plugin_badge' :
237
  $name = __( 'Show Plugin Badge', 'wp-simple-firewall' );
238
- $summary = __( 'Display Plugin Badge On Your Site', 'wp-simple-firewall' );
239
  $desc = [
240
  __( 'Enabling this option helps support the plugin by spreading the word about it on your website.', 'wp-simple-firewall' )
241
  .' '.__( 'The plugin badge also lets visitors know your are taking your website security seriously.', 'wp-simple-firewall' ),
235
 
236
  case 'display_plugin_badge' :
237
  $name = __( 'Show Plugin Badge', 'wp-simple-firewall' );
238
+ $summary = __( 'Display Plugin Security Badge To Your Visitors', 'wp-simple-firewall' );
239
  $desc = [
240
  __( 'Enabling this option helps support the plugin by spreading the word about it on your website.', 'wp-simple-firewall' )
241
  .' '.__( 'The plugin badge also lets visitors know your are taking your website security seriously.', 'wp-simple-firewall' ),
src/lib/src/Modules/Plugin/UI.php CHANGED
@@ -38,6 +38,33 @@ class UI extends BaseShield\UI {
38
  ];
39
  }
40
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  /**
42
  * @param array $aOptParams
43
  * @return array
38
  ];
39
  }
40
 
41
+ public function buildInsightsVars_Wizard( $wizard, $step ) :array {
42
+ $data = [];
43
+ switch ( $wizard ) {
44
+ case 'welcome':
45
+ $data = [
46
+ 'steps' => [
47
+ 'step1' => 'content for step1',
48
+ 'step2' => 'content for step2',
49
+ 'step3' => 'content for step3',
50
+ ],
51
+ 'currentStep' => 'step'.$step,
52
+ 'ajax' => [
53
+ 'wizard_step' => $this->getMod()->getAjaxActionData( 'wizard_step', true ),
54
+ ],
55
+ 'strings' => [
56
+ 'hohoho' => sprintf( __( '%s %s Page' ), $wizard, $this->getCon()->getHumanName() ),
57
+ ],
58
+ 'showSideNav' => 0,
59
+ ];
60
+ break;
61
+ default:
62
+ break;
63
+ }
64
+
65
+ return $data;
66
+ }
67
+
68
  /**
69
  * @param array $aOptParams
70
  * @return array
src/lib/src/Modules/Reporting/Lib/ReportingController.php CHANGED
@@ -44,6 +44,7 @@ class ReportingController {
44
  }
45
  }
46
  catch ( \Exception $e ) {
 
47
  }
48
  }
49
 
@@ -56,6 +57,7 @@ class ReportingController {
56
  }
57
  }
58
  catch ( \Exception $e ) {
 
59
  }
60
  }
61
 
44
  }
45
  }
46
  catch ( \Exception $e ) {
47
+ var_dump( $e->getMessage() );
48
  }
49
  }
50
 
57
  }
58
  }
59
  catch ( \Exception $e ) {
60
+ var_dump( $e->getMessage() );
61
  }
62
  }
63
 
src/lib/src/Modules/Reporting/Lib/Reports/CreateReportVO.php CHANGED
@@ -77,52 +77,65 @@ class CreateReportVO {
77
  * @throws \Exception
78
  */
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;
 
117
  default:
118
  throw new \Exception( 'Not a supported frequency' );
119
  }
120
 
121
- if ( $this->rep->previous instanceof Reports\EntryVO
122
- && $end <= $this->rep->previous->interval_end_at ) {
123
  throw new \Exception( 'Attempting to create a duplicate report based on interval.' );
124
  }
125
 
 
 
 
 
126
  $this->rep->interval_start_at = $start;
127
  $this->rep->interval_end_at = $end;
128
 
@@ -142,12 +155,4 @@ class CreateReportVO {
142
  $this->rep->rid = is_numeric( $prevID ) ? $prevID + 1 : 1;
143
  return $this;
144
  }
145
-
146
- /**
147
- * TODO
148
- * @return bool
149
- */
150
- private function isOnDemandReport() {
151
- return !Services::WpGeneral()->isCron();
152
- }
153
  }
77
  * @throws \Exception
78
  */
79
  private function setIntervalBoundaries() {
80
+ $req = Services::Request();
81
 
82
+ $intervalToReport = $req->carbon( true );
83
+ $currentIntervalStart = $req->carbon( true );
84
 
85
  switch ( $this->rep->interval ) {
86
  // case 'realtime':
87
  // break;
88
  case 'lifetime': // TODO
89
  $start = 0;
90
+ $end = $intervalToReport->timestamp;
91
  break;
92
  case 'hourly':
93
+ $currentIntervalStart->startOfHour();
94
+ $intervalToReport->subHour();
95
+ $start = $intervalToReport->startOfHour()->timestamp;
96
+ $end = $intervalToReport->endOfHour()->timestamp;
97
  break;
98
+
99
  case 'daily':
100
+ $currentIntervalStart->startOfDay();
101
+ $intervalToReport->subDay();
102
+ $start = $intervalToReport->startOfDay()->timestamp;
103
+ $end = $intervalToReport->endOfDay()->timestamp;
104
  break;
105
+
106
  case 'weekly':
107
+ $currentIntervalStart->startOfWeek();
108
+ $intervalToReport->subWeek();
109
+ $start = $intervalToReport->startOfWeek()->timestamp;
110
+ $end = $intervalToReport->endOfWeek()->timestamp;
111
  break;
112
+
113
  case 'monthly':
114
+ $currentIntervalStart->startOfMonth();
115
+ $intervalToReport->day( 15 )->subMonth();
116
+ $start = $intervalToReport->startOfMonth()->timestamp;
117
+ $end = $intervalToReport->endOfMonth()->timestamp;
118
  break;
119
+
120
  case 'yearly':
121
+ $currentIntervalStart->startOfYear();
122
+ $intervalToReport->subYear();
123
+ $start = $intervalToReport->startOfYear()->timestamp;
124
+ $end = $intervalToReport->endOfYear()->timestamp;
125
  break;
126
+
127
  default:
128
  throw new \Exception( 'Not a supported frequency' );
129
  }
130
 
131
+ if ( $this->rep->previous instanceof Reports\EntryVO && $end <= $this->rep->previous->interval_end_at ) {
 
132
  throw new \Exception( 'Attempting to create a duplicate report based on interval.' );
133
  }
134
 
135
+ if ( $end > $currentIntervalStart->timestamp ) { // sanity check
136
+ throw new \Exception( 'Attempting to create for an interval greater than the current interval.' );
137
+ }
138
+
139
  $this->rep->interval_start_at = $start;
140
  $this->rep->interval_end_at = $end;
141
 
155
  $this->rep->rid = is_numeric( $prevID ) ? $prevID + 1 : 1;
156
  return $this;
157
  }
 
 
 
 
 
 
 
 
158
  }
src/lib/src/Modules/SecurityAdmin/Insights/OverviewCards.php CHANGED
@@ -6,19 +6,12 @@ use FernleafSystems\Wordpress\Plugin\Shield;
6
 
7
  class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
8
 
9
- public function build() :array {
10
  /** @var Shield\Modules\SecurityAdmin\ModCon $mod */
11
  $mod = $this->getMod();
12
  /** @var Shield\Modules\SecurityAdmin\Options $opts */
13
  $opts = $this->getOptions();
14
 
15
- $cardSection = [
16
- 'title' => __( 'Security Admin', 'wp-simple-firewall' ),
17
- 'subtitle' => sprintf( __( 'Prevent Tampering With %s Settings', 'wp-simple-firewall' ),
18
- $this->getCon()->getHumanName() ),
19
- 'href_options' => $mod->getUrl_AdminPage()
20
- ];
21
-
22
  $cards = [];
23
 
24
  $enabled = $mod->getSecurityAdminController()->isEnabledSecAdmin();
@@ -59,7 +52,15 @@ class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
59
  ];
60
  }
61
 
62
- $cardSection[ 'cards' ] = $cards;
63
- return [ 'sec_admin' => $cardSection ];
 
 
 
 
 
 
 
 
64
  }
65
  }
6
 
7
  class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
8
 
9
+ protected function buildModCards() :array {
10
  /** @var Shield\Modules\SecurityAdmin\ModCon $mod */
11
  $mod = $this->getMod();
12
  /** @var Shield\Modules\SecurityAdmin\Options $opts */
13
  $opts = $this->getOptions();
14
 
 
 
 
 
 
 
 
15
  $cards = [];
16
 
17
  $enabled = $mod->getSecurityAdminController()->isEnabledSecAdmin();
52
  ];
53
  }
54
 
55
+ return $cards;
56
+ }
57
+
58
+ protected function getSectionTitle() :string {
59
+ return __( 'Security Admin', 'wp-simple-firewall' );
60
+ }
61
+
62
+ protected function getSectionSubTitle() :string {
63
+ return sprintf( __( 'Prevent Tampering With %s Settings', 'wp-simple-firewall' ),
64
+ $this->getCon()->getHumanName() );
65
  }
66
  }
src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/Base.php CHANGED
@@ -2,11 +2,8 @@
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
  }
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Lib\SecurityAdmin\Restrictions;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
 
6
 
7
+ class Base extends ExecOnceModConsumer {
8
 
 
 
9
  }
src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/WpOptions.php CHANGED
@@ -28,7 +28,6 @@ class WpOptions extends Base {
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 */
28
  * @param string $key
29
  * @param mixed $oldValue
30
  * @return mixed
 
31
  */
32
  public function blockOptionsSaves( $newValue, $key, $oldValue ) {
33
  /** @var Options $opts */
src/lib/src/Modules/SecurityAdmin/Lib/SecurityAdmin/SecurityAdminController.php CHANGED
@@ -2,17 +2,13 @@
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
 
@@ -28,21 +24,10 @@ class SecurityAdminController {
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' ] );
@@ -51,6 +36,19 @@ class SecurityAdminController {
51
  } );
52
  }
53
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  public function isEnabledSecAdmin() :bool {
55
  /** @var Options $opts */
56
  $opts = $this->getOptions();
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Lib\SecurityAdmin;
4
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Controller\Assets\Enqueue;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\ModCon;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Options;
9
  use FernleafSystems\Wordpress\Services\Services;
10
 
11
+ class SecurityAdminController extends ExecOnceModConsumer {
 
 
 
12
 
13
  private $validPinRequest;
14
 
24
  } );
25
  add_action( 'init', function () {
26
  if ( !$this->getCon()->isPluginAdmin() ) {
27
+
28
+ foreach ( $this->getAllRestrictionZones() as $zone ) {
29
+ $zone->setMod( $this->getMod() )->execute();
30
+ }
 
 
 
 
 
 
 
 
 
 
 
31
 
32
  if ( !$this->getCon()->isThisPluginModuleRequest() ) {
33
  add_action( 'admin_footer', [ $this, 'printPinLoginForm' ] );
36
  } );
37
  }
38
 
39
+ /**
40
+ * @return Restrictions\Base[]
41
+ */
42
+ private function getAllRestrictionZones() :array {
43
+ return [
44
+ new Restrictions\WpOptions(),
45
+ new Restrictions\Plugins(),
46
+ new Restrictions\Themes(),
47
+ new Restrictions\Posts(),
48
+ new Restrictions\Users(),
49
+ ];
50
+ }
51
+
52
  public function isEnabledSecAdmin() :bool {
53
  /** @var Options $opts */
54
  $opts = $this->getOptions();
src/lib/src/Modules/SecurityAdmin/Lib/WhiteLabel/BuildOptions.php CHANGED
@@ -37,7 +37,7 @@ class BuildOptions {
37
  * @param string $key
38
  * @return string
39
  */
40
- private function buildWlImageUrl( string $key ) {
41
  $opts = $this->getOptions();
42
 
43
  $url = $opts->getOpt( $key );
37
  * @param string $key
38
  * @return string
39
  */
40
+ public function buildWlImageUrl( string $key ) {
41
  $opts = $this->getOptions();
42
 
43
  $url = $opts->getOpt( $key );
src/lib/src/Modules/SecurityAdmin/Lib/WhiteLabel/{ApplyLabels.php → WhitelabelController.php} RENAMED
@@ -1,21 +1,23 @@
1
- <?php
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Lib\WhiteLabel;
4
 
5
- use FernleafSystems\Utilities\Logic\ExecOnce;
6
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin;
8
  use FernleafSystems\Wordpress\Services\Services;
9
 
10
- class ApplyLabels {
11
 
12
- use ModConsumer;
13
- use ExecOnce;
 
 
 
 
 
14
 
15
  protected function canRun() :bool {
16
- /** @var SecurityAdmin\Options $opts */
17
- $opts = $this->getOptions();
18
- return $opts->isEnabledWhitelabel();
19
  }
20
 
21
  protected function run() {
@@ -30,7 +32,8 @@ class ApplyLabels {
30
  public function onWpInit() {
31
  /** @var SecurityAdmin\Options $opts */
32
  $opts = $this->getOptions();
33
- if ( $opts->isWlHideUpdates() && $this->isNeedToHideUpdates() && !$this->getCon()->isPluginAdmin() ) {
 
34
  $this->hideUpdates();
35
  }
36
  }
@@ -72,7 +75,7 @@ class ApplyLabels {
72
  * @param array $pluginLabels
73
  * @return array
74
  */
75
- public function applyPluginLabels( $pluginLabels ) {
76
  $labels = ( new BuildOptions() )
77
  ->setMod( $this->getMod() )
78
  ->build();
@@ -114,18 +117,33 @@ class ApplyLabels {
114
  return array_merge( $labels, $pluginLabels );
115
  }
116
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  /**
118
  * @filter
119
- * @param array $aPluginMeta
120
  * @param string $pluginBaseFile
121
  * @return array
122
  */
123
- public function removePluginMetaLinks( $aPluginMeta, $pluginBaseFile ) {
124
  if ( $pluginBaseFile == $this->getCon()->base_file ) {
125
- unset( $aPluginMeta[ 2 ] ); // View details
126
- unset( $aPluginMeta[ 3 ] ); // Rate 5*
127
  }
128
- return $aPluginMeta;
129
  }
130
 
131
  /**
@@ -134,10 +152,7 @@ class ApplyLabels {
134
  * @return \stdClass
135
  */
136
  public function hidePluginUpdatesFromUI( $plugins ) {
137
- $file = $this->getCon()->base_file;
138
- if ( isset( $plugins->response[ $file ] ) ) {
139
- unset( $plugins->response[ $file ] );
140
- }
141
  return $plugins;
142
  }
143
 
1
+ <?php declare( strict_types=1 );
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Lib\WhiteLabel;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
 
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin;
7
  use FernleafSystems\Wordpress\Services\Services;
8
 
9
+ class WhitelabelController extends ExecOnceModConsumer {
10
 
11
+ public function isEnabled() :bool {
12
+ /** @var SecurityAdmin\ModCon $mod */
13
+ $mod = $this->getMod();
14
+ return $this->getCon()->isPremiumActive()
15
+ && $this->getOptions()->isOpt( 'whitelabel_enable', 'Y' )
16
+ && $mod->getSecurityAdminController()->isEnabledSecAdmin();
17
+ }
18
 
19
  protected function canRun() :bool {
20
+ return $this->isEnabled();
 
 
21
  }
22
 
23
  protected function run() {
32
  public function onWpInit() {
33
  /** @var SecurityAdmin\Options $opts */
34
  $opts = $this->getOptions();
35
+ if ( $opts->isOpt( 'wl_hide_updates', 'Y' ) && $this->isNeedToHideUpdates() && !$this->getCon()
36
+ ->isPluginAdmin() ) {
37
  $this->hideUpdates();
38
  }
39
  }
75
  * @param array $pluginLabels
76
  * @return array
77
  */
78
+ public function applyPluginLabels( array $pluginLabels ) :array {
79
  $labels = ( new BuildOptions() )
80
  ->setMod( $this->getMod() )
81
  ->build();
117
  return array_merge( $labels, $pluginLabels );
118
  }
119
 
120
+ public function isReplacePluginBadge() :bool {
121
+ return $this->getOptions()->isOpt( 'wl_replace_badge_url', 'Y' );
122
+ }
123
+
124
+ public function verifyUrls() {
125
+ $DP = Services::Data();
126
+ $opts = $this->getOptions();
127
+ $optsBuilder = ( new BuildOptions() )->setMod( $this->getMod() );
128
+ foreach ( [ 'wl_menuiconurl', 'wl_dashboardlogourl', 'wl_login2fa_logourl' ] as $key ) {
129
+ if ( $opts->isOptChanged( $key ) && !$DP->isValidWebUrl( $optsBuilder->buildWlImageUrl( $key ) ) ) {
130
+ $opts->resetOptToDefault( $key );
131
+ }
132
+ }
133
+ }
134
+
135
  /**
136
  * @filter
137
+ * @param array $pluginMeta
138
  * @param string $pluginBaseFile
139
  * @return array
140
  */
141
+ public function removePluginMetaLinks( $pluginMeta, $pluginBaseFile ) {
142
  if ( $pluginBaseFile == $this->getCon()->base_file ) {
143
+ unset( $pluginMeta[ 2 ] ); // View details
144
+ unset( $pluginMeta[ 3 ] ); // Rate 5*
145
  }
146
+ return $pluginMeta;
147
  }
148
 
149
  /**
152
  * @return \stdClass
153
  */
154
  public function hidePluginUpdatesFromUI( $plugins ) {
155
+ unset( $plugins->response[ $this->getCon()->base_file ] );
 
 
 
156
  return $plugins;
157
  }
158
 
src/lib/src/Modules/SecurityAdmin/ModCon.php CHANGED
@@ -11,12 +11,7 @@ class ModCon extends BaseShield\ModCon {
11
  const HASH_DELETE = '32f68a60cef40faedbc6af20298c1a1e';
12
 
13
  /**
14
- * @var bool
15
- */
16
- private $bValidSecAdminRequest;
17
-
18
- /**
19
- * @var Lib\WhiteLabel\ApplyLabels
20
  */
21
  private $whitelabelCon;
22
 
@@ -29,9 +24,9 @@ class ModCon extends BaseShield\ModCon {
29
  add_action( $this->prefix( 'pre_deactivate_plugin' ), [ $this, 'preDeactivatePlugin' ] );
30
  }
31
 
32
- public function getWhiteLabelController() :Lib\WhiteLabel\ApplyLabels {
33
- if ( !$this->whitelabelCon instanceof Lib\WhiteLabel\ApplyLabels ) {
34
- $this->whitelabelCon = ( new Lib\WhiteLabel\ApplyLabels() )
35
  ->setMod( $this );
36
  }
37
  return $this->whitelabelCon;
@@ -54,13 +49,7 @@ class ModCon extends BaseShield\ModCon {
54
  $opts = $this->getOptions();
55
 
56
  // Verify whitelabel images
57
- if ( $opts->isEnabledWhitelabel() ) {
58
- foreach ( [ 'wl_menuiconurl', 'wl_dashboardlogourl', 'wl_login2fa_logourl' ] as $key ) {
59
- if ( !Services::Data()->isValidWebUrl( $this->buildWlImageUrl( $key ) ) ) {
60
- $opts->resetOptToDefault( $key );
61
- }
62
- }
63
- }
64
 
65
  $opts->setOpt( 'sec_admin_users',
66
  ( new Lib\SecurityAdmin\VerifySecurityAdminList() )
@@ -91,30 +80,6 @@ class ModCon extends BaseShield\ModCon {
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' );
101
- $menu = $opts->getOpt( 'wl_namemenu' );
102
- if ( empty( $menu ) ) {
103
- $menu = $main;
104
- }
105
-
106
- return [
107
- 'name_main' => $main,
108
- 'name_menu' => $menu,
109
- 'name_company' => $opts->getOpt( 'wl_companyname' ),
110
- 'description' => $opts->getOpt( 'wl_description' ),
111
- 'url_home' => $opts->getOpt( 'wl_homeurl' ),
112
- 'url_icon' => $this->buildWlImageUrl( 'wl_menuiconurl' ),
113
- 'url_dashboardlogourl' => $this->buildWlImageUrl( 'wl_dashboardlogourl' ),
114
- 'url_login2fa_logourl' => $this->buildWlImageUrl( 'wl_login2fa_logourl' ),
115
- ];
116
- }
117
-
118
  /**
119
  * We cater for 3 options:
120
  * Full URL
@@ -122,6 +87,7 @@ class ModCon extends BaseShield\ModCon {
122
  * Or Plugin image URL i.e. doesn't start with HTTP or /
123
  * @param string $key
124
  * @return string
 
125
  */
126
  private function buildWlImageUrl( $key ) {
127
  $opts = $this->getOptions();
@@ -142,19 +108,6 @@ class ModCon extends BaseShield\ModCon {
142
  return $url;
143
  }
144
 
145
- /**
146
- * @deprecated 11.0
147
- */
148
- public function isWlEnabled() :bool {
149
- /** @var Options $opts */
150
- $opts = $this->getOptions();
151
- return $opts->isEnabledWhitelabel() && $this->isPremium();
152
- }
153
-
154
- public function isWlHideUpdates() :bool {
155
- return $this->isEnabledWhitelabel() && $this->getOptions()->isOpt( 'wl_hide_updates', 'Y' );
156
- }
157
-
158
  /**
159
  * Used by Wizard. TODO: sort out the wizard requests!
160
  * @param string $pin
@@ -231,116 +184,4 @@ class ModCon extends BaseShield\ModCon {
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
  }
11
  const HASH_DELETE = '32f68a60cef40faedbc6af20298c1a1e';
12
 
13
  /**
14
+ * @var Lib\WhiteLabel\WhitelabelController
 
 
 
 
 
15
  */
16
  private $whitelabelCon;
17
 
24
  add_action( $this->prefix( 'pre_deactivate_plugin' ), [ $this, 'preDeactivatePlugin' ] );
25
  }
26
 
27
+ public function getWhiteLabelController() :Lib\WhiteLabel\WhitelabelController {
28
+ if ( !$this->whitelabelCon instanceof Lib\WhiteLabel\WhitelabelController ) {
29
+ $this->whitelabelCon = ( new Lib\WhiteLabel\WhitelabelController() )
30
  ->setMod( $this );
31
  }
32
  return $this->whitelabelCon;
49
  $opts = $this->getOptions();
50
 
51
  // Verify whitelabel images
52
+ $this->getWhiteLabelController()->verifyUrls();
 
 
 
 
 
 
53
 
54
  $opts->setOpt( 'sec_admin_users',
55
  ( new Lib\SecurityAdmin\VerifySecurityAdminList() )
80
  }
81
  }
82
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  /**
84
  * We cater for 3 options:
85
  * Full URL
87
  * Or Plugin image URL i.e. doesn't start with HTTP or /
88
  * @param string $key
89
  * @return string
90
+ * @deprecated 11.2
91
  */
92
  private function buildWlImageUrl( $key ) {
93
  $opts = $this->getOptions();
108
  return $url;
109
  }
110
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  /**
112
  * Used by Wizard. TODO: sort out the wizard requests!
113
  * @param string $pin
184
  );
185
  }
186
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  }
src/lib/src/Modules/SecurityAdmin/Options.php CHANGED
@@ -86,6 +86,10 @@ class Options extends BaseShield\Options {
86
  return strlen( $this->getSecurityPIN() ) == 32;
87
  }
88
 
 
 
 
 
89
  public function isEnabledWhitelabel() :bool {
90
  return $this->isOpt( 'whitelabel_enable', 'Y' ) && $this->isPremium();
91
  }
@@ -98,11 +102,19 @@ class Options extends BaseShield\Options {
98
  return $this->isOpt( 'admin_access_restrict_admin_users', 'Y' );
99
  }
100
 
101
- public function isWlHideUpdates() :bool {
102
- return $this->isEnabledWhitelabel() && $this->isOpt( 'wl_hide_updates', 'Y' );
103
- }
104
-
105
  public function isReplacePluginBadge() :bool {
106
  return $this->isOpt( 'wl_replace_badge_url', 'Y' );
107
  }
 
 
 
 
 
 
 
 
108
  }
86
  return strlen( $this->getSecurityPIN() ) == 32;
87
  }
88
 
89
+ /**
90
+ * @return bool
91
+ * @deprecated 11.2
92
+ */
93
  public function isEnabledWhitelabel() :bool {
94
  return $this->isOpt( 'whitelabel_enable', 'Y' ) && $this->isPremium();
95
  }
102
  return $this->isOpt( 'admin_access_restrict_admin_users', 'Y' );
103
  }
104
 
105
+ /**
106
+ * @return bool
107
+ * @deprecated 11.2
108
+ */
109
  public function isReplacePluginBadge() :bool {
110
  return $this->isOpt( 'wl_replace_badge_url', 'Y' );
111
  }
112
+
113
+ /**
114
+ * @return bool
115
+ * @deprecated 11.2
116
+ */
117
+ public function isWlHideUpdates() :bool {
118
+ return false;
119
+ }
120
  }
src/lib/src/Modules/SecurityAdmin/Processor.php CHANGED
@@ -1,4 +1,4 @@
1
- <?php
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin;
4
 
@@ -9,164 +9,7 @@ class Processor extends BaseShield\Processor {
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
-
75
- /**
76
- * This hooked function captures the attempts to modify the user role using the standard
77
- * WordPress profile edit pages. It doesn't sufficiently capture the AJAX request to
78
- * modify user roles. (see user role hooks)
79
- * @param array $allCaps
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();
109
- return $opts->getAdminAccessArea_Options()
110
- && in_array( $key, $opts->getOptionsToRestrict() );
111
- }
112
-
113
- /**
114
- * @param array $aAllCaps
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
-
124
- /**
125
- * @param array $aAllCaps
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
133
- if ( $this->getCon()->isPluginAdmin() ) {
134
- return $aAllCaps;
135
- }
136
-
137
- return $aAllCaps;
138
- }
139
-
140
- /**
141
- * @param array $aAllCaps
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
  }
1
+ <?php declare( strict_types=1 );
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin;
4
 
9
  protected function run() {
10
  /** @var ModCon $mod */
11
  $mod = $this->getMod();
12
+ $mod->getWhiteLabelController()->execute();
 
 
 
 
 
 
13
  $mod->getSecurityAdminController()->execute();
14
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  }
src/lib/src/Modules/Sessions/Lib/Ops/Retrieve.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Sessions\Lib\Ops;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Databases\Session\{
6
+ EntryVO,
7
+ Select
8
+ };
9
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
10
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Sessions\ModCon;
11
+
12
+ /**
13
+ * Class Retrieve
14
+ * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Sessions\Lib\Ops
15
+ * @deprecated 11.2
16
+ */
17
+ class Retrieve {
18
+
19
+ use ModConsumer;
20
+
21
+ /**
22
+ * @param string $ip
23
+ * @return EntryVO|null
24
+ */
25
+ public function byIP( string $ip ) {
26
+ return $this->getSelector()->filterByIp( $ip )->first();
27
+ }
28
+
29
+ public function byUsername( string $username ) :bool {
30
+ return $this->getSelector()->filterByUsername( $username )->first();
31
+ }
32
+
33
+ private function getSelector() :Select {
34
+ /** @var ModCon $mod */
35
+ $mod = $this->getMod();
36
+ return $mod->getDbHandler_Sessions()->getQuerySelector();
37
+ }
38
+ }
src/lib/src/Modules/Sessions/Lib/Ops/Terminate.php CHANGED
@@ -3,8 +3,8 @@
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Sessions\Lib\Ops;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Session\Delete;
6
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\Sessions\ModCon;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
 
8
 
9
  class Terminate {
10
 
@@ -20,16 +20,20 @@ class Terminate {
20
  }
21
 
22
  /**
23
- * @param int $nId
24
  * @return bool
25
  */
26
- public function byRecordId( $nId ) {
27
  $this->getCon()->fireEvent( 'session_terminate' );
28
- return $this->getDeleter()->deleteById( (int)$nId );
 
 
29
  }
30
 
31
  public function byUsername( string $username ) :bool {
32
- return $this->getDeleter()->forUsername( $username ) !== false;
 
 
33
  }
34
 
35
  private function getDeleter() :Delete {
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Sessions\Lib\Ops;
4
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Session\Delete;
 
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Sessions\ModCon;
8
 
9
  class Terminate {
10
 
20
  }
21
 
22
  /**
23
+ * @param int $id
24
  * @return bool
25
  */
26
+ public function byRecordId( int $id ) {
27
  $this->getCon()->fireEvent( 'session_terminate' );
28
+ return $this->getDeleter()
29
+ ->setIsSoftDelete()
30
+ ->deleteById( $id );
31
  }
32
 
33
  public function byUsername( string $username ) :bool {
34
+ return $this->getDeleter()
35
+ ->setIsSoftDelete()
36
+ ->forUsername( $username ) !== false;
37
  }
38
 
39
  private function getDeleter() :Delete {
src/lib/src/Modules/Sessions/Lib/SessionController.php CHANGED
@@ -5,6 +5,7 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Sessions\Lib;
5
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Session;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Sessions\ModCon;
 
8
 
9
  class SessionController {
10
 
@@ -15,13 +16,28 @@ class SessionController {
15
  */
16
  private $current;
17
 
 
 
 
 
 
18
  /**
19
  * @return Session\EntryVO|null
20
  */
21
  public function getCurrent() {
22
  $con = $this->getCon();
23
- if ( empty( $this->current ) && did_action( 'init' ) && $con->hasSessionId() ) {
24
- $this->current = $this->queryGetSession( $con->getSessionId() );
 
 
 
 
 
 
 
 
 
 
25
  }
26
  return $this->current;
27
  }
@@ -45,6 +61,46 @@ class SessionController {
45
  return $success;
46
  }
47
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  public function queryCreateSession( string $sessionID, \WP_User $user ) :bool {
49
  /** @var ModCon $mod */
50
  $mod = $this->getMod();
@@ -69,6 +125,6 @@ class SessionController {
69
  $mod = $this->getMod();
70
  /** @var Session\Select $sel */
71
  $sel = $mod->getDbHandler_Sessions()->getQuerySelector();
72
- return $sel->retrieveUserSession( $sessionID, $username );
73
  }
74
  }
5
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Session;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Sessions\ModCon;
8
+ use FernleafSystems\Wordpress\Services\Services;
9
 
10
  class SessionController {
11
 
16
  */
17
  private $current;
18
 
19
+ /**
20
+ * @var ?string
21
+ */
22
+ private $sessionID;
23
+
24
  /**
25
  * @return Session\EntryVO|null
26
  */
27
  public function getCurrent() {
28
  $con = $this->getCon();
29
+ if ( empty( $this->current ) && did_action( 'init' ) ) {
30
+ if ( $this->hasSessionID() ) {
31
+ $this->current = $this->queryGetSession( $this->getSessionID() );
32
+ }
33
+ if ( $con->hasSessionId() ) {
34
+ if ( empty( $this->current ) ) {
35
+ $this->current = $this->queryGetSession( $con->getSessionId() );
36
+ }
37
+ else {
38
+ $con->clearSession();
39
+ }
40
+ }
41
  }
42
  return $this->current;
43
  }
61
  return $success;
62
  }
63
 
64
+ public function createSession( \WP_User $user, string $sessionID = '' ) :bool {
65
+ /** @var ModCon $mod */
66
+ $mod = $this->getMod();
67
+
68
+ $success = false;
69
+ if ( empty( $sessionID ) ) {
70
+ $sessionID = $this->getSessionID();
71
+ }
72
+
73
+ if ( !empty( $sessionID ) && !empty( $user->user_login ) ) {
74
+
75
+ if ( !preg_match( '#^[a-z0-9]{32}$#i', $sessionID ) ) {
76
+ $sessionID = md5( $sessionID );
77
+ }
78
+
79
+ $this->sessionID = $sessionID;
80
+
81
+ /** @var Session\Insert $insert */
82
+ $insert = $mod->getDbHandler_Sessions()->getQueryInserter();
83
+ $success = $insert->create( $sessionID, $user->user_login );
84
+
85
+ $this->getCon()->fireEvent( 'session_start' );
86
+ }
87
+ return $success;
88
+ }
89
+
90
+ public function hasSessionID() :bool {
91
+ return !empty( $this->getSessionID() );
92
+ }
93
+
94
+ public function getSessionID() :string {
95
+ if ( empty( $this->sessionID ) ) {
96
+ $cookie = Services::Request()->cookie( LOGGED_IN_COOKIE );
97
+ if ( !empty( $cookie ) ) {
98
+ $this->sessionID = md5( $cookie );
99
+ }
100
+ }
101
+ return (string)$this->sessionID;
102
+ }
103
+
104
  public function queryCreateSession( string $sessionID, \WP_User $user ) :bool {
105
  /** @var ModCon $mod */
106
  $mod = $this->getMod();
125
  $mod = $this->getMod();
126
  /** @var Session\Select $sel */
127
  $sel = $mod->getDbHandler_Sessions()->getQuerySelector();
128
+ return $sel->retrieveUserSession( $sessionID, (string)$username );
129
  }
130
  }
src/lib/src/Modules/Sessions/Processor.php CHANGED
@@ -32,8 +32,12 @@ class Processor extends BaseShield\Processor {
32
  }
33
 
34
  protected function captureLogin( \WP_User $user ) {
35
- $this->activateUserSession( $user );
36
- $this->getCon()->fireEvent( 'login_success' );
 
 
 
 
37
  }
38
 
39
  public function onWpLoaded() {
@@ -49,9 +53,9 @@ class Processor extends BaseShield\Processor {
49
  if ( !Services::Rest()->isRest() && !$this->getCon()->plugin_deleting ) {
50
  $session = $mod->getSessionCon()->getCurrent();
51
  if ( $session instanceof Session\EntryVO ) {
52
- /** @var Session\Update $oUpd */
53
- $oUpd = $mod->getDbHandler_Sessions()->getQueryUpdater();
54
- $oUpd->updateLastActivity( $session );
55
  }
56
  }
57
 
@@ -65,7 +69,7 @@ class Processor extends BaseShield\Processor {
65
  if ( !$sessCon->hasSession() && $mod->isAutoAddSessions() ) {
66
  $user = Services::WpUsers()->getCurrentWpUser();
67
  if ( $user instanceof \WP_User ) {
68
- $sessCon->queryCreateSession( $this->getCon()->getSessionId( true ), $user );
69
  }
70
  }
71
  }
@@ -93,11 +97,19 @@ class Processor extends BaseShield\Processor {
93
  return $msg;
94
  }
95
 
 
 
 
 
96
  private function activateUserSession( \WP_User $user ) {
97
  /** @var ModCon $mod */
98
  $mod = $this->getMod();
99
  // If they have a currently active session, terminate it (i.e. we replace it)
100
  $mod->getSessionCon()->terminateCurrentSession();
101
- $mod->getSessionCon()->queryCreateSession( $this->getCon()->getSessionId( true ), $user );
 
 
 
 
102
  }
103
  }
32
  }
33
 
34
  protected function captureLogin( \WP_User $user ) {
35
+ if ( !empty( $this->getLoggedInCookie() ) ) {
36
+ $sessonCon = $this->getCon()->getModule_Sessions()->getSessionCon();
37
+ $sessonCon->terminateCurrentSession();
38
+ $sessonCon->createSession( $user, $this->getLoggedInCookie() );
39
+ $this->getCon()->fireEvent( 'login_success' );
40
+ }
41
  }
42
 
43
  public function onWpLoaded() {
53
  if ( !Services::Rest()->isRest() && !$this->getCon()->plugin_deleting ) {
54
  $session = $mod->getSessionCon()->getCurrent();
55
  if ( $session instanceof Session\EntryVO ) {
56
+ /** @var Session\Update $update */
57
+ $update = $mod->getDbHandler_Sessions()->getQueryUpdater();
58
+ $update->updateLastActivity( $session );
59
  }
60
  }
61
 
69
  if ( !$sessCon->hasSession() && $mod->isAutoAddSessions() ) {
70
  $user = Services::WpUsers()->getCurrentWpUser();
71
  if ( $user instanceof \WP_User ) {
72
+ $sessCon->createSession( $user );
73
  }
74
  }
75
  }
97
  return $msg;
98
  }
99
 
100
+ /**
101
+ * @param \WP_User $user
102
+ * @deprecated 11.2
103
+ */
104
  private function activateUserSession( \WP_User $user ) {
105
  /** @var ModCon $mod */
106
  $mod = $this->getMod();
107
  // If they have a currently active session, terminate it (i.e. we replace it)
108
  $mod->getSessionCon()->terminateCurrentSession();
109
+ $mod->getSessionCon()->createSession( $user );
110
+ }
111
+
112
+ protected function getHookPriority() :int {
113
+ return 100;
114
  }
115
  }
src/lib/src/Modules/Traffic/Strings.php CHANGED
@@ -94,8 +94,11 @@ class Strings extends Base\Strings {
94
  case 'type_exclusions' :
95
  $name = __( 'Traffic Log Exclusions', 'wp-simple-firewall' );
96
  $summary = __( 'Select Which Types Of Requests To Exclude', 'wp-simple-firewall' );
97
- $desc = __( "Select request types that you don't want to appear in the traffic viewer.", 'wp-simple-firewall' )
98
- .'<br/>'.__( 'If a request matches any exclusion rule, it will not show on the traffic viewer.', 'wp-simple-firewall' );
 
 
 
99
  break;
100
 
101
  case 'custom_exclusions' :
94
  case 'type_exclusions' :
95
  $name = __( 'Traffic Log Exclusions', 'wp-simple-firewall' );
96
  $summary = __( 'Select Which Types Of Requests To Exclude', 'wp-simple-firewall' );
97
+ $desc = [
98
+ __( "There's no need to have unnecessary traffic noise in your logs, so we automatically exclude certain types of requests.", 'wp-simple-firewall' ),
99
+ __( "Select request types that you don't want to appear in the traffic viewer.", 'wp-simple-firewall' ),
100
+ __( 'If a request matches any exclusion rule, it wont show in the traffic logs.', 'wp-simple-firewall' )
101
+ ];
102
  break;
103
 
104
  case 'custom_exclusions' :
src/lib/src/Modules/UserManagement/AjaxHandler.php CHANGED
@@ -59,43 +59,43 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
59
  $mod = $this->getMod();
60
  $req = Services::Request();
61
 
62
- $bSuccess = false;
63
 
64
- $aIds = $req->post( 'ids' );
65
- if ( empty( $aIds ) || !is_array( $aIds ) ) {
66
- $bSuccess = false;
67
- $sMessage = __( 'No items selected.', 'wp-simple-firewall' );
68
  }
69
  elseif ( !in_array( $req->post( 'bulk_action' ), [ 'delete' ] ) ) {
70
- $sMessage = __( 'Not a supported action.', 'wp-simple-firewall' );
71
  }
72
  else {
73
- $nYourId = $mod->getSession()->id;
74
- $bIncludesYourSession = in_array( $nYourId, $aIds );
75
 
76
- if ( $bIncludesYourSession && ( count( $aIds ) == 1 ) ) {
77
- $sMessage = __( 'Please logout if you want to delete your own session.', 'wp-simple-firewall' );
78
  }
79
  else {
80
- $bSuccess = true;
81
 
82
- $oTerminator = ( new Sessions\Lib\Ops\Terminate() )
83
  ->setMod( $this->getCon()->getModule_Sessions() );
84
- foreach ( $aIds as $nId ) {
85
- if ( is_numeric( $nId ) && ( $nId != $nYourId ) ) {
86
- $oTerminator->byRecordId( $nId );
87
  }
88
  }
89
- $sMessage = __( 'Selected items were deleted.', 'wp-simple-firewall' );
90
  if ( $bIncludesYourSession ) {
91
- $sMessage .= ' *'.__( 'Your session was retained', 'wp-simple-firewall' );
92
  }
93
  }
94
  }
95
 
96
  return [
97
- 'success' => $bSuccess,
98
- 'message' => $sMessage,
99
  ];
100
  }
101
 
59
  $mod = $this->getMod();
60
  $req = Services::Request();
61
 
62
+ $success = false;
63
 
64
+ $IDs = $req->post( 'ids' );
65
+ if ( empty( $IDs ) || !is_array( $IDs ) ) {
66
+ $success = false;
67
+ $msg = __( 'No items selected.', 'wp-simple-firewall' );
68
  }
69
  elseif ( !in_array( $req->post( 'bulk_action' ), [ 'delete' ] ) ) {
70
+ $msg = __( 'Not a supported action.', 'wp-simple-firewall' );
71
  }
72
  else {
73
+ $yourId = $mod->getSession()->id;
74
+ $bIncludesYourSession = in_array( $yourId, $IDs );
75
 
76
+ if ( $bIncludesYourSession && ( count( $IDs ) == 1 ) ) {
77
+ $msg = __( 'Please logout if you want to delete your own session.', 'wp-simple-firewall' );
78
  }
79
  else {
80
+ $success = true;
81
 
82
+ $terminator = ( new Sessions\Lib\Ops\Terminate() )
83
  ->setMod( $this->getCon()->getModule_Sessions() );
84
+ foreach ( $IDs as $id ) {
85
+ if ( is_numeric( $id ) && ( $id != $yourId ) ) {
86
+ $terminator->byRecordId( (int)$id );
87
  }
88
  }
89
+ $msg = __( 'Selected items were deleted.', 'wp-simple-firewall' );
90
  if ( $bIncludesYourSession ) {
91
+ $msg .= ' *'.__( 'Your session was retained', 'wp-simple-firewall' );
92
  }
93
  }
94
  }
95
 
96
  return [
97
+ 'success' => $success,
98
+ 'message' => $msg,
99
  ];
100
  }
101
 
src/lib/src/Modules/UserManagement/Insights/OverviewCards.php CHANGED
@@ -8,24 +8,15 @@ use FernleafSystems\Wordpress\Services\Services;
8
 
9
  class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
10
 
11
- public function build() :array {
12
  /** @var UserManagement\ModCon $mod */
13
  $mod = $this->getMod();
14
  /** @var UserManagement\Options $opts */
15
  $opts = $this->getOptions();
16
 
17
- $cardSection = [
18
- 'title' => __( 'User Management', 'wp-simple-firewall' ),
19
- 'subtitle' => __( 'Sessions Control & Password Policies', 'wp-simple-firewall' ),
20
- 'href_options' => $mod->getUrl_AdminPage()
21
- ];
22
-
23
  $cards = [];
24
 
25
- if ( !$mod->isModOptEnabled() ) {
26
- $cards[] = $this->getModDisabledCard();
27
- }
28
- else {
29
  $bHasIdle = $opts->hasSessionIdleTimeout();
30
  $cards[ 'idle' ] = [
31
  'name' => __( 'Idle Users', 'wp-simple-firewall' ),
@@ -81,7 +72,14 @@ class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
81
  'help' => __( "The default 'admin' user should be deleted or demoted.", 'wp-simple-firewall' )
82
  ];
83
 
84
- $cardSection[ 'cards' ] = $cards;
85
- return [ 'user_management' => $cardSection ];
 
 
 
 
 
 
 
86
  }
87
  }
8
 
9
  class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
10
 
11
+ protected function buildModCards() :array {
12
  /** @var UserManagement\ModCon $mod */
13
  $mod = $this->getMod();
14
  /** @var UserManagement\Options $opts */
15
  $opts = $this->getOptions();
16
 
 
 
 
 
 
 
17
  $cards = [];
18
 
19
+ if ( $mod->isModOptEnabled() ) {
 
 
 
20
  $bHasIdle = $opts->hasSessionIdleTimeout();
21
  $cards[ 'idle' ] = [
22
  'name' => __( 'Idle Users', 'wp-simple-firewall' ),
72
  'help' => __( "The default 'admin' user should be deleted or demoted.", 'wp-simple-firewall' )
73
  ];
74
 
75
+ return $cards;
76
+ }
77
+
78
+ protected function getSectionTitle() :string {
79
+ return __( 'User Management', 'wp-simple-firewall' );
80
+ }
81
+
82
+ protected function getSectionSubTitle() :string {
83
+ return __( 'Sessions Control & Password Policies', 'wp-simple-firewall' );
84
  }
85
  }
src/lib/src/Modules/UserManagement/Lib/Password/UserPasswordHandler.php CHANGED
@@ -2,8 +2,7 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\UserManagement\Lib\Password;
4
 
5
- use FernleafSystems\Utilities\Logic\ExecOnce;
6
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\UserManagement;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Utilities\Consumer\WpLoginCapture;
9
  use FernleafSystems\Wordpress\Services\Services;
@@ -13,10 +12,8 @@ use FernleafSystems\Wordpress\Services\Services;
13
  * Class UserPasswordController
14
  * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\UserManagement\Lib\Password
15
  */
16
- class UserPasswordHandler {
17
 
18
- use ModConsumer;
19
- use ExecOnce;
20
  use WpLoginCapture;
21
 
22
  protected function canRun() :bool {
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\UserManagement\Lib\Password;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
 
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\UserManagement;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Utilities\Consumer\WpLoginCapture;
8
  use FernleafSystems\Wordpress\Services\Services;
12
  * Class UserPasswordController
13
  * @package FernleafSystems\Wordpress\Plugin\Shield\Modules\UserManagement\Lib\Password
14
  */
15
+ class UserPasswordHandler extends ExecOnceModConsumer {
16
 
 
 
17
  use WpLoginCapture;
18
 
19
  protected function canRun() :bool {
src/lib/src/Modules/UserManagement/Lib/Session/UserSessionHandler.php CHANGED
@@ -2,17 +2,14 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\UserManagement\Lib\Session;
4
 
5
- use FernleafSystems\Utilities\Logic\ExecOnce;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Session\EntryVO;
7
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\UserManagement;
9
  use FernleafSystems\Wordpress\Plugin\Shield\Utilities\Consumer\WpLoginCapture;
10
  use FernleafSystems\Wordpress\Services\Services;
11
 
12
- class UserSessionHandler {
13
 
14
- use ModConsumer;
15
- use ExecOnce;
16
  use WpLoginCapture;
17
 
18
  protected function canRun() :bool {
@@ -106,9 +103,6 @@ class UserSessionHandler {
106
  return $opts->hasMaxSessionTimeout() ? min( $timeout, $opts->getMaxSessionTime() ) : $timeout;
107
  }
108
 
109
- /**
110
- * @param \WP_User $user
111
- */
112
  private function enforceSessionLimits( \WP_User $user ) {
113
  /** @var UserManagement\Options $opts */
114
  $opts = $this->getOptions();
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\UserManagement\Lib\Session;
4
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Databases\Session\EntryVO;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\UserManagement;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Utilities\Consumer\WpLoginCapture;
9
  use FernleafSystems\Wordpress\Services\Services;
10
 
11
+ class UserSessionHandler extends ExecOnceModConsumer {
12
 
 
 
13
  use WpLoginCapture;
14
 
15
  protected function canRun() :bool {
103
  return $opts->hasMaxSessionTimeout() ? min( $timeout, $opts->getMaxSessionTime() ) : $timeout;
104
  }
105
 
 
 
 
106
  private function enforceSessionLimits( \WP_User $user ) {
107
  /** @var UserManagement\Options $opts */
108
  $opts = $this->getOptions();
src/lib/src/Modules/UserManagement/Lib/Suspend/UserSuspendController.php CHANGED
@@ -3,15 +3,13 @@
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\UserManagement\Lib\Suspend;
4
 
5
  use FernleafSystems\Utilities\Logic\ExecOnce;
 
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Sessions\Lib\Ops\Terminate;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\UserManagement;
9
  use FernleafSystems\Wordpress\Services\Services;
10
 
11
- class UserSuspendController {
12
-
13
- use ModConsumer;
14
- use ExecOnce;
15
 
16
  protected function canRun() :bool {
17
  /** @var UserManagement\Options $opts */
@@ -147,7 +145,7 @@ class UserSuspendController {
147
  'form_field' => 'shield_suspend_user',
148
  ]
149
  ];
150
- echo $this->getMod()->renderTemplate( '/snippets/user/profile/suspend.twig', $aData, true );
151
  }
152
 
153
  public function handleUserSuspendOptionSubmit( int $uid ) {
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\UserManagement\Lib\Suspend;
4
 
5
  use FernleafSystems\Utilities\Logic\ExecOnce;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\Common\ExecOnceModConsumer;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
8
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\Sessions\Lib\Ops\Terminate;
9
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\UserManagement;
10
  use FernleafSystems\Wordpress\Services\Services;
11
 
12
+ class UserSuspendController extends ExecOnceModConsumer {
 
 
 
13
 
14
  protected function canRun() :bool {
15
  /** @var UserManagement\Options $opts */
145
  'form_field' => 'shield_suspend_user',
146
  ]
147
  ];
148
+ echo $this->getMod()->renderTemplate( '/admin/user/profile/suspend.twig', $aData, true );
149
  }
150
 
151
  public function handleUserSuspendOptionSubmit( int $uid ) {
src/lib/src/Modules/UserManagement/ModCon.php CHANGED
@@ -11,28 +11,28 @@ class ModCon extends BaseShield\ModCon {
11
  * Should have no default email. If no email is set, no notification is sent.
12
  * @return string[]
13
  */
14
- public function getAdminLoginNotificationEmails() {
15
- $aEmails = [];
16
 
17
- $sEmails = $this->getOptions()->getOpt( 'enable_admin_login_email_notification', '' );
18
- if ( !empty( $sEmails ) ) {
19
- $aEmails = array_values( array_unique( array_filter(
20
  array_map(
21
  function ( $sEmail ) {
22
  return trim( strtolower( $sEmail ) );
23
  },
24
- explode( ',', $sEmails )
25
  ),
26
- function ( $sEmail ) {
27
- return Services::Data()->validEmail( $sEmail );
28
  }
29
  ) ) );
30
- if ( !$this->isPremium() && !empty( $aEmails ) ) {
31
- $aEmails = array_slice( $aEmails, 0, 1 );
32
  }
33
  }
34
 
35
- return $aEmails;
36
  }
37
 
38
  protected function preProcessOptions() {
@@ -54,11 +54,11 @@ class ModCon extends BaseShield\ModCon {
54
  ) ) )
55
  );
56
 
57
- $aChecks = $opts->getEmailValidationChecks();
58
- if ( !empty( $aChecks ) ) {
59
- $aChecks[] = 'syntax';
60
  }
61
- $opts->setOpt( 'email_checks', array_unique( $aChecks ) );
62
  }
63
 
64
  public function isSendUserEmailLoginNotification() :bool {
11
  * Should have no default email. If no email is set, no notification is sent.
12
  * @return string[]
13
  */
14
+ public function getAdminLoginNotificationEmails() :array {
15
+ $emails = [];
16
 
17
+ $rawEmails = $this->getOptions()->getOpt( 'enable_admin_login_email_notification', '' );
18
+ if ( !empty( $rawEmails ) ) {
19
+ $emails = array_values( array_unique( array_filter(
20
  array_map(
21
  function ( $sEmail ) {
22
  return trim( strtolower( $sEmail ) );
23
  },
24
+ explode( ',', $rawEmails )
25
  ),
26
+ function ( $email ) {
27
+ return Services::Data()->validEmail( $email );
28
  }
29
  ) ) );
30
+ if ( count( $emails ) > 1 && !$this->isPremium() ) {
31
+ $emails = array_slice( $emails, 0, 1 );
32
  }
33
  }
34
 
35
+ return $emails;
36
  }
37
 
38
  protected function preProcessOptions() {
54
  ) ) )
55
  );
56
 
57
+ $checks = $opts->getEmailValidationChecks();
58
+ if ( !empty( $checks ) ) {
59
+ $checks[] = 'syntax';
60
  }
61
+ $opts->setOpt( 'email_checks', array_unique( $checks ) );
62
  }
63
 
64
  public function isSendUserEmailLoginNotification() :bool {
src/lib/src/Modules/UserManagement/Processor.php CHANGED
@@ -83,20 +83,20 @@ class Processor extends BaseShield\Processor {
83
  private function sendLoginNotifications( \WP_User $user ) {
84
  /** @var ModCon $mod */
85
  $mod = $this->getMod();
86
- $aAdminEmails = $mod->getAdminLoginNotificationEmails();
87
- $bAdmin = count( $aAdminEmails ) > 0;
88
- $bUser = $mod->isSendUserEmailLoginNotification();
89
 
90
  // do some magic logic so we don't send both to the same person (the assumption being that the admin
91
  // email recipient is actually an admin (or they'll maybe not get any).
92
- if ( $bAdmin && $bUser && in_array( strtolower( $user->user_email ), $aAdminEmails ) ) {
93
- $bUser = false;
94
  }
95
 
96
- if ( $bAdmin ) {
97
  $this->sendAdminLoginEmailNotification( $user );
98
  }
99
- if ( $bUser ) {
100
  $hasLoginIntent = $this->getCon()
101
  ->getModule_LoginGuard()
102
  ->getLoginIntentController()
@@ -134,25 +134,25 @@ class Processor extends BaseShield\Processor {
134
  }
135
 
136
  add_filter( 'manage_users_custom_column',
137
- function ( $sContent, $sColumnName, $nUserId ) use ( $sCustomColumnName ) {
138
 
139
  if ( $sColumnName == $sCustomColumnName ) {
140
- $sValue = __( 'Not Recorded', 'wp-simple-firewall' );
141
- $oUser = Services::WpUsers()->getUserById( $nUserId );
142
- if ( $oUser instanceof \WP_User ) {
143
- $nLastLoginTime = $this->getCon()->getUserMeta( $oUser )->last_login_at;
144
  if ( $nLastLoginTime > 0 ) {
145
- $sValue = Services::Request()
146
- ->carbon()
147
- ->setTimestamp( $nLastLoginTime )
148
- ->diffForHumans();
149
  }
150
  }
151
- $sNewContent = sprintf( '%s: %s', __( 'Last Login', 'wp-simple-firewall' ), $sValue );
152
- $sContent = empty( $sContent ) ? $sNewContent : $sContent.'<br/>'.$sNewContent;
153
  }
154
 
155
- return $sContent;
156
  },
157
  10, 3
158
  );
83
  private function sendLoginNotifications( \WP_User $user ) {
84
  /** @var ModCon $mod */
85
  $mod = $this->getMod();
86
+ $adminEmails = $mod->getAdminLoginNotificationEmails();
87
+ $sendAdmin = count( $adminEmails ) > 0;
88
+ $sendUser = $mod->isSendUserEmailLoginNotification();
89
 
90
  // do some magic logic so we don't send both to the same person (the assumption being that the admin
91
  // email recipient is actually an admin (or they'll maybe not get any).
92
+ if ( $sendAdmin && $sendUser && in_array( strtolower( $user->user_email ), $adminEmails ) ) {
93
+ $sendUser = false;
94
  }
95
 
96
+ if ( $sendAdmin ) {
97
  $this->sendAdminLoginEmailNotification( $user );
98
  }
99
+ if ( $sendUser ) {
100
  $hasLoginIntent = $this->getCon()
101
  ->getModule_LoginGuard()
102
  ->getLoginIntentController()
134
  }
135
 
136
  add_filter( 'manage_users_custom_column',
137
+ function ( $content, $sColumnName, $userID ) use ( $sCustomColumnName ) {
138
 
139
  if ( $sColumnName == $sCustomColumnName ) {
140
+ $value = __( 'Not Recorded', 'wp-simple-firewall' );
141
+ $user = Services::WpUsers()->getUserById( $userID );
142
+ if ( $user instanceof \WP_User ) {
143
+ $nLastLoginTime = $this->getCon()->getUserMeta( $user )->last_login_at;
144
  if ( $nLastLoginTime > 0 ) {
145
+ $value = Services::Request()
146
+ ->carbon()
147
+ ->setTimestamp( $nLastLoginTime )
148
+ ->diffForHumans();
149
  }
150
  }
151
+ $sNewContent = sprintf( '%s: %s', __( 'Last Login', 'wp-simple-firewall' ), $value );
152
+ $content = empty( $content ) ? $sNewContent : $content.'<br/>'.$sNewContent;
153
  }
154
 
155
+ return $content;
156
  },
157
  10, 3
158
  );
src/lib/src/Tables/Build/Traffic.php CHANGED
@@ -145,8 +145,8 @@ class Traffic extends BaseBuild {
145
  }
146
  else {
147
  $country = sprintf(
148
- '<img class="icon-flag" src="%s" alt="%s"/> %s',
149
- sprintf( 'https://www.countryflags.io/%s/flat/16.png', strtolower( $countryISO ) ),
150
  $countryISO,
151
  $geoIP->getCountryName()
152
  );
145
  }
146
  else {
147
  $country = sprintf(
148
+ '<img class="icon-flag" src="%s" alt="%s" width="24px"/> %s',
149
+ sprintf( 'https://api.aptoweb.com/api/v1/country/flag/%s.svg', strtolower( $countryISO ) ),
150
  $countryISO,
151
  $geoIP->getCountryName()
152
  );
src/lib/src/Tables/Render/Common/BaseTable.php ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Tables\Render\Common;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Scans;
7
+
8
+ class BaseTable {
9
+
10
+ use ModConsumer;
11
+
12
+ const DEFAULT_PER_PAGE = 25;
13
+
14
+ /**
15
+ * @var int
16
+ */
17
+ protected $pageSize;
18
+
19
+ /**
20
+ * @var int
21
+ */
22
+ protected $totalRecords = -1;
23
+
24
+ /**
25
+ * @var array
26
+ */
27
+ protected $records = [];
28
+
29
+ protected function extra_tablenav( $which ) {
30
+ echo sprintf( '<a href="#" data-tableaction="refresh" class="btn btn-sm btn-outline-dark ml-3 tableActionRefresh">%s</a>', __( 'Refresh', 'wp-simple-firewall' ) );
31
+ }
32
+
33
+ /**
34
+ * @param object $item
35
+ * @param string $colName
36
+ * @return string
37
+ */
38
+ public function column_default( $item, $colName ) {
39
+ return $item[ $colName ];
40
+ }
41
+
42
+ /**
43
+ * @param array $aItem
44
+ * @return string
45
+ */
46
+ public function column_cb( $aItem ) {
47
+ return sprintf( '<input type="checkbox" name="ids" value="%s" />', $aItem[ 'id' ] );
48
+ }
49
+
50
+ /**
51
+ * @return array
52
+ */
53
+ public function get_sortable_columns() {
54
+ return [];
55
+ // $aCols = $this->get_columns();
56
+ // foreach ( $aCols as $sCol => $sName ) {
57
+ // $aCols[ $sCol ] = array( $sCol, false );
58
+ // }
59
+ // return $aCols;
60
+ }
61
+
62
+ /**
63
+ * @return string[]
64
+ */
65
+ protected function get_table_classes() {
66
+ return array_merge( parent::get_table_classes(), [ 'odp-table' ] );
67
+ }
68
+
69
+ /**
70
+ * @return \FernleafSystems\Wordpress\Plugin\Shield\Tables\Render\WpListTable\Base
71
+ */
72
+ public function prepare_items() {
73
+ $aCols = $this->get_columns();
74
+ $aHidden = [];
75
+ $this->_column_headers = [ $aCols, $aHidden, $this->get_sortable_columns() ];
76
+ $this->items = $this->getRecords();
77
+
78
+ $this->set_pagination_args(
79
+ [
80
+ 'total_items' => $this->getTotalRecords(),
81
+ 'per_page' => $this->getPageSize()
82
+ ]
83
+ );
84
+ return $this;
85
+ }
86
+
87
+ /**
88
+ * @param string $option
89
+ * @param int $default
90
+ * @return int
91
+ */
92
+ protected function get_items_per_page( $option, $default = 20 ) {
93
+ return $this->getPageSize();
94
+ }
95
+
96
+ public function single_row( $item ) {
97
+ if ( empty( $item[ 'custom_row' ] ) ) { // it's a normal row so render as always
98
+ parent::single_row( $item );
99
+ }
100
+ else {
101
+ $this->single_row_custom( $item );
102
+ }
103
+ }
104
+
105
+ /**
106
+ * override this in order to display a custom row
107
+ * @param $aItem
108
+ */
109
+ public function single_row_custom( $aItem ) {
110
+ parent::single_row( $aItem );
111
+ }
112
+
113
+ public function getPageSize() :int {
114
+ return empty( $this->pageSize ) ? self::DEFAULT_PER_PAGE : $this->pageSize;
115
+ }
116
+
117
+ public function getRecords() :array {
118
+ return $this->records;
119
+ }
120
+
121
+ public function getTotalRecords() {
122
+ return $this->totalRecords;
123
+ }
124
+
125
+ /**
126
+ * @param array $records
127
+ * @return $this
128
+ */
129
+ public function setRecords( array $records ) {
130
+ $this->records = $records;
131
+ return $this;
132
+ }
133
+
134
+ /**
135
+ * @param int $size
136
+ * @return $this
137
+ */
138
+ public function setPageSize( $size ) {
139
+ $this->pageSize = $size;
140
+ return $this;
141
+ }
142
+
143
+ /**
144
+ * @param int $total
145
+ * @return $this
146
+ */
147
+ public function setTotalRecords( int $total ) {
148
+ $this->totalRecords = $total;
149
+ return $this;
150
+ }
151
+ }
src/lib/src/Tables/Render/DataTable/Base.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Tables\Render\DataTable;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Scans;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Tables\Render\Common\BaseTable;
7
+
8
+ class Base extends BaseTable {
9
+
10
+ }
src/lib/src/Tables/Render/DataTable/ScanBase.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Tables\Render\DataTable;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Scans;
6
+
7
+ class ScanBase extends Base {
8
+
9
+ }
src/lib/src/Tables/Render/DataTable/ScanWcf.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Tables\Render\DataTable;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Scans;
6
+
7
+ class ScanWcf extends ScanBase {
8
+
9
+ }
src/lib/src/Tables/Render/WpListTable/ScanBase.php CHANGED
@@ -11,14 +11,14 @@ class ScanBase extends Base {
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
  }
23
 
24
  //.implode( '; ', $aItem[ 'asset_description' ] )
11
  * @return string
12
  */
13
  public function column_path( $item ) {
14
+ $output = 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
+ $output .= '<p class="mb-0">'.implode( '; ', $item[ 'path_details' ] ).'</p>';
20
  }
21
+ return $output;
22
  }
23
 
24
  //.implode( '; ', $aItem[ 'asset_description' ] )
src/lib/src/Users/ShieldUserMeta.php CHANGED
@@ -7,28 +7,28 @@ use FernleafSystems\Wordpress\Services\Services;
7
  /**
8
  * Class UserMeta
9
  * @package FernleafSystems\Wordpress\Plugin\Shield\Users
10
- * @property array $email_secret
11
- * @property bool $email_validated
12
- * @property string $backupcode_secret
13
- * @property string $backupcode_validated
14
- * @property string $ga_secret
15
- * @property bool $ga_validated
16
- * @property string $u2f_secret
17
- * @property bool $u2f_validated
18
- * @property string $u2f_regrequest
19
- * @property array $hash_loginmfa
20
- * @property string $pass_hash
21
- * @property int $first_seen_at
22
- * @property int $last_verified_at
23
- * @property int $pass_started_at
24
- * @property int $pass_reset_last_redirect_at
25
- * @property int $pass_check_failed_at
26
- * @property string $yubi_secret
27
- * @property bool $yubi_validated
28
- * @property int $last_login_at
29
- * @property bool $wc_social_login_valid
30
- * @property bool $hard_suspended_at
31
- * @property array $tours
32
  */
33
  class ShieldUserMeta extends \FernleafSystems\Wordpress\Services\Utilities\PluginUserMeta {
34
 
7
  /**
8
  * Class UserMeta
9
  * @package FernleafSystems\Wordpress\Plugin\Shield\Users
10
+ * @property array $email_secret
11
+ * @property bool $email_validated
12
+ * @property string $backupcode_secret
13
+ * @property string $backupcode_validated
14
+ * @property string $ga_secret
15
+ * @property bool $ga_validated
16
+ * @property string $u2f_secret
17
+ * @property bool $u2f_validated
18
+ * @property string[] $u2f_regrequests
19
+ * @property array $hash_loginmfa
20
+ * @property string $pass_hash
21
+ * @property int $first_seen_at
22
+ * @property int $last_verified_at
23
+ * @property int $pass_started_at
24
+ * @property int $pass_reset_last_redirect_at
25
+ * @property int $pass_check_failed_at
26
+ * @property string $yubi_secret
27
+ * @property bool $yubi_validated
28
+ * @property int $last_login_at
29
+ * @property bool $wc_social_login_valid
30
+ * @property bool $hard_suspended_at
31
+ * @property array $tours
32
  */
33
  class ShieldUserMeta extends \FernleafSystems\Wordpress\Services\Utilities\PluginUserMeta {
34
 
src/lib/src/Utilities/Consumer/WpLoginCapture.php CHANGED
@@ -16,6 +16,11 @@ trait WpLoginCapture {
16
  */
17
  private $isCaptureApplicationLogin = false;
18
 
 
 
 
 
 
19
  abstract protected function captureLogin( \WP_User $user );
20
 
21
  protected function getLoginPassword() :string {
@@ -30,6 +35,12 @@ trait WpLoginCapture {
30
  return $pass;
31
  }
32
 
 
 
 
 
 
 
33
  protected function isCaptureApplicationLogin() :bool {
34
  return $this->isCaptureApplicationLogin;
35
  }
@@ -51,13 +62,18 @@ trait WpLoginCapture {
51
  return $this;
52
  }
53
 
 
 
 
 
 
54
  protected function setToCaptureApplicationLogin( bool $capture = true ) :self {
55
  $this->isCaptureApplicationLogin = $capture;
56
  return $this;
57
  }
58
 
59
  protected function setupLoginCaptureHooks() {
60
- add_action( 'wp_login', [ $this, 'onWpLogin' ], 10, 2 );
61
  if ( !Services::WpUsers()->isProfilePage() ) { // Ignore firing during profile update.
62
  add_action( 'set_logged_in_cookie', [ $this, 'onWpSetLoggedInCookie' ], 5, 4 );
63
  }
@@ -71,6 +87,9 @@ trait WpLoginCapture {
71
  */
72
  public function onWpSetLoggedInCookie( $cookie, $expire, $expiration, $userID ) {
73
  $user = Services::WpUsers()->getUserById( $userID );
 
 
 
74
  if ( $this->isLoginToBeCaptured() && !$this->isLoginCaptured() && $user instanceof \WP_User ) {
75
  $this->setLoginCaptured();
76
  $this->captureLogin( $user );
@@ -87,4 +106,8 @@ trait WpLoginCapture {
87
  $this->captureLogin( $user );
88
  }
89
  }
 
 
 
 
90
  }
16
  */
17
  private $isCaptureApplicationLogin = false;
18
 
19
+ /**
20
+ * @var string
21
+ */
22
+ private $loggedInCookie = '';
23
+
24
  abstract protected function captureLogin( \WP_User $user );
25
 
26
  protected function getLoginPassword() :string {
35
  return $pass;
36
  }
37
 
38
+ protected function getLoggedInCookie() :string {
39
+ $cookie = empty( $this->loggedInCookie ) ?
40
+ Services::Request()->cookie( LOGGED_IN_COOKIE ) : $this->loggedInCookie;
41
+ return is_string( $cookie ) ? $cookie : '';
42
+ }
43
+
44
  protected function isCaptureApplicationLogin() :bool {
45
  return $this->isCaptureApplicationLogin;
46
  }
62
  return $this;
63
  }
64
 
65
+ protected function setLoggedInCookie( string $cookieValue ) :self {
66
+ $this->loggedInCookie = $cookieValue;
67
+ return $this;
68
+ }
69
+
70
  protected function setToCaptureApplicationLogin( bool $capture = true ) :self {
71
  $this->isCaptureApplicationLogin = $capture;
72
  return $this;
73
  }
74
 
75
  protected function setupLoginCaptureHooks() {
76
+ add_action( 'wp_login', [ $this, 'onWpLogin' ], $this->getHookPriority(), 2 );
77
  if ( !Services::WpUsers()->isProfilePage() ) { // Ignore firing during profile update.
78
  add_action( 'set_logged_in_cookie', [ $this, 'onWpSetLoggedInCookie' ], 5, 4 );
79
  }
87
  */
88
  public function onWpSetLoggedInCookie( $cookie, $expire, $expiration, $userID ) {
89
  $user = Services::WpUsers()->getUserById( $userID );
90
+ if ( is_string( $cookie ) ) {
91
+ $this->setLoggedInCookie( $cookie );
92
+ }
93
  if ( $this->isLoginToBeCaptured() && !$this->isLoginCaptured() && $user instanceof \WP_User ) {
94
  $this->setLoginCaptured();
95
  $this->captureLogin( $user );
106
  $this->captureLogin( $user );
107
  }
108
  }
109
+
110
+ protected function getHookPriority() :int {
111
+ return 10;
112
+ }
113
  }
src/lib/src/Utilities/Consumer/WpUserConsumer.php CHANGED
@@ -7,21 +7,21 @@ trait WpUserConsumer {
7
  /**
8
  * @var \WP_User
9
  */
10
- private $oWpUser;
11
 
12
  /**
13
- * @return \WP_User
14
  */
15
  public function getWpUser() {
16
- return $this->oWpUser;
17
  }
18
 
19
  /**
20
- * @param \WP_User $user
21
  * @return $this
22
  */
23
- public function setWpUser( \WP_User $user ) {
24
- $this->oWpUser = $user;
25
  return $this;
26
  }
27
  }
7
  /**
8
  * @var \WP_User
9
  */
10
+ private $wpUser;
11
 
12
  /**
13
+ * @return \WP_User|null
14
  */
15
  public function getWpUser() {
16
+ return $this->wpUser;
17
  }
18
 
19
  /**
20
+ * @param \WP_User|null $user
21
  * @return $this
22
  */
23
+ public function setWpUser( $user ) {
24
+ $this->wpUser = $user;
25
  return $this;
26
  }
27
  }
src/lib/vendor/bacon/bacon-qr-code/Module.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode;
11
+
12
+ use Zend\ModuleManager\Feature\AutoloaderProviderInterface;
13
+
14
+ /**
15
+ * Module for generating QR codes.
16
+ */
17
+ class Module implements AutoloaderProviderInterface
18
+ {
19
+ /**
20
+ * Get autoloader config.
21
+ *
22
+ * @return array
23
+ */
24
+ public function getAutoloaderConfig()
25
+ {
26
+ return array(
27
+ 'Zend\Loader\ClassMapAutoloader' => array(
28
+ __DIR__ . '/autoload_classmap.php',
29
+ ),
30
+ 'Zend\Loader\StandardAutoloader' => array(
31
+ 'namespaces' => array(
32
+ __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
33
+ ),
34
+ ),
35
+ );
36
+ }
37
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/AbstractEnum.php ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Common;
11
+
12
+ use BaconQrCode\Exception;
13
+ use ReflectionClass;
14
+
15
+ /**
16
+ * A general enum implementation until we got SplEnum.
17
+ */
18
+ abstract class AbstractEnum
19
+ {
20
+ /**
21
+ * Default value.
22
+ */
23
+ const __default = null;
24
+
25
+ /**
26
+ * Current value.
27
+ *
28
+ * @var mixed
29
+ */
30
+ protected $value;
31
+
32
+ /**
33
+ * Cache of constants.
34
+ *
35
+ * @var array
36
+ */
37
+ protected $constants;
38
+
39
+ /**
40
+ * Whether to handle values strict or not.
41
+ *
42
+ * @var boolean
43
+ */
44
+ protected $strict;
45
+
46
+ /**
47
+ * Creates a new enum.
48
+ *
49
+ * @param mixed $initialValue
50
+ * @param boolean $strict
51
+ */
52
+ public function __construct($initialValue = null, $strict = false)
53
+ {
54
+ $this->strict = $strict;
55
+ $this->change($initialValue);
56
+ }
57
+
58
+ /**
59
+ * Changes the value of the enum.
60
+ *
61
+ * @param mixed $value
62
+ * @return void
63
+ */
64
+ public function change($value)
65
+ {
66
+ if (!in_array($value, $this->getConstList(), $this->strict)) {
67
+ throw new Exception\UnexpectedValueException('Value not a const in enum ' . get_class($this));
68
+ }
69
+
70
+ $this->value = $value;
71
+ }
72
+
73
+ /**
74
+ * Gets current value.
75
+ *
76
+ * @return mixed
77
+ */
78
+ public function get()
79
+ {
80
+ return $this->value;
81
+ }
82
+
83
+ /**
84
+ * Gets all constants (possible values) as an array.
85
+ *
86
+ * @param boolean $includeDefault
87
+ * @return array
88
+ */
89
+ public function getConstList($includeDefault = true)
90
+ {
91
+ if ($this->constants === null) {
92
+ $reflection = new ReflectionClass($this);
93
+ $this->constants = $reflection->getConstants();
94
+ }
95
+
96
+ if ($includeDefault) {
97
+ return $this->constants;
98
+ }
99
+
100
+ $constants = $this->constants;
101
+ unset($constants['__default']);
102
+
103
+ return $constants;
104
+ }
105
+
106
+ /**
107
+ * Gets the name of the enum.
108
+ *
109
+ * @return string
110
+ */
111
+ public function __toString()
112
+ {
113
+ return array_search($this->value, $this->getConstList());
114
+ }
115
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitArray.php ADDED
@@ -0,0 +1,435 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Common;
11
+
12
+ use SplFixedArray;
13
+
14
+ /**
15
+ * A simple, fast array of bits.
16
+ */
17
+ class BitArray
18
+ {
19
+ /**
20
+ * Bits represented as an array of integers.
21
+ *
22
+ * @var SplFixedArray
23
+ */
24
+ protected $bits;
25
+
26
+ /**
27
+ * Size of the bit array in bits.
28
+ *
29
+ * @var integer
30
+ */
31
+ protected $size;
32
+
33
+ /**
34
+ * Creates a new bit array with a given size.
35
+ *
36
+ * @param integer $size
37
+ */
38
+ public function __construct($size = 0)
39
+ {
40
+ $this->size = $size;
41
+ $this->bits = new SplFixedArray(($this->size + 31) >> 3);
42
+ }
43
+
44
+ /**
45
+ * Gets the size in bits.
46
+ *
47
+ * @return integer
48
+ */
49
+ public function getSize()
50
+ {
51
+ return $this->size;
52
+ }
53
+
54
+ /**
55
+ * Gets the size in bytes.
56
+ *
57
+ * @return integer
58
+ */
59
+ public function getSizeInBytes()
60
+ {
61
+ return ($this->size + 7) >> 3;
62
+ }
63
+
64
+ /**
65
+ * Ensures that the array has a minimum capacity.
66
+ *
67
+ * @param integer $size
68
+ * @return void
69
+ */
70
+ public function ensureCapacity($size)
71
+ {
72
+ if ($size > count($this->bits) << 5) {
73
+ $this->bits->setSize(($size + 31) >> 5);
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Gets a specific bit.
79
+ *
80
+ * @param integer $i
81
+ * @return boolean
82
+ */
83
+ public function get($i)
84
+ {
85
+ return ($this->bits[$i >> 5] & (1 << ($i & 0x1f))) !== 0;
86
+ }
87
+
88
+ /**
89
+ * Sets a specific bit.
90
+ *
91
+ * @param integer $i
92
+ * @return void
93
+ */
94
+ public function set($i)
95
+ {
96
+ $this->bits[$i >> 5] = $this->bits[$i >> 5] | 1 << ($i & 0x1f);
97
+ }
98
+
99
+ /**
100
+ * Flips a specific bit.
101
+ *
102
+ * @param integer $i
103
+ * @return void
104
+ */
105
+ public function flip($i)
106
+ {
107
+ $this->bits[$i >> 5] ^= 1 << ($i & 0x1f);
108
+ }
109
+
110
+ /**
111
+ * Gets the next set bit position from a given position.
112
+ *
113
+ * @param integer $from
114
+ * @return integer
115
+ */
116
+ public function getNextSet($from)
117
+ {
118
+ if ($from >= $this->size) {
119
+ return $this->size;
120
+ }
121
+
122
+ $bitsOffset = $from >> 5;
123
+ $currentBits = $this->bits[$bitsOffset];
124
+ $bitsLength = count($this->bits);
125
+
126
+ $currentBits &= ~((1 << ($from & 0x1f)) - 1);
127
+
128
+ while ($currentBits === 0) {
129
+ if (++$bitsOffset === $bitsLength) {
130
+ return $this->size;
131
+ }
132
+
133
+ $currentBits = $this->bits[$bitsOffset];
134
+ }
135
+
136
+ $result = ($bitsOffset << 5) + BitUtils::numberOfTrailingZeros($currentBits);
137
+
138
+ return $result > $this->size ? $this->size : $result;
139
+ }
140
+
141
+ /**
142
+ * Gets the next unset bit position from a given position.
143
+ *
144
+ * @param integer $from
145
+ * @return integer
146
+ */
147
+ public function getNextUnset($from)
148
+ {
149
+ if ($from >= $this->size) {
150
+ return $this->size;
151
+ }
152
+
153
+ $bitsOffset = $from >> 5;
154
+ $currentBits = ~$this->bits[$bitsOffset];
155
+ $bitsLength = count($this->bits);
156
+
157
+ $currentBits &= ~((1 << ($from & 0x1f)) - 1);
158
+
159
+ while ($currentBits === 0) {
160
+ if (++$bitsOffset === $bitsLength) {
161
+ return $this->size;
162
+ }
163
+
164
+ $currentBits = ~$this->bits[$bitsOffset];
165
+ }
166
+
167
+ $result = ($bitsOffset << 5) + BitUtils::numberOfTrailingZeros($currentBits);
168
+
169
+ return $result > $this->size ? $this->size : $result;
170
+ }
171
+
172
+ /**
173
+ * Sets a bulk of bits.
174
+ *
175
+ * @param integer $i
176
+ * @param integer $newBits
177
+ * @return void
178
+ */
179
+ public function setBulk($i, $newBits)
180
+ {
181
+ $this->bits[$i >> 5] = $newBits;
182
+ }
183
+
184
+ /**
185
+ * Sets a range of bits.
186
+ *
187
+ * @param integer $start
188
+ * @param integer $end
189
+ * @return void
190
+ * @throws Exception\InvalidArgumentException
191
+ */
192
+ public function setRange($start, $end)
193
+ {
194
+ if ($end < $start) {
195
+ throw new Exception\InvalidArgumentException('End must be greater or equal to start');
196
+ }
197
+
198
+ if ($end === $start) {
199
+ return;
200
+ }
201
+
202
+ $end--;
203
+
204
+ $firstInt = $start >> 5;
205
+ $lastInt = $end >> 5;
206
+
207
+ for ($i = $firstInt; $i <= $lastInt; $i++) {
208
+ $firstBit = $i > $firstInt ? 0 : $start & 0x1f;
209
+ $lastBit = $i < $lastInt ? 31 : $end & 0x1f;
210
+
211
+ if ($firstBit === 0 && $lastBit === 31) {
212
+ $mask = 0x7fffffff;
213
+ } else {
214
+ $mask = 0;
215
+
216
+ for ($j = $firstBit; $j < $lastBit; $j++) {
217
+ $mask |= 1 << $j;
218
+ }
219
+ }
220
+
221
+ $this->bits[$i] = $this->bits[$i] | $mask;
222
+ }
223
+ }
224
+
225
+ /**
226
+ * Clears the bit array, unsetting every bit.
227
+ *
228
+ * @return void
229
+ */
230
+ public function clear()
231
+ {
232
+ $bitsLength = count($this->bits);
233
+
234
+ for ($i = 0; $i < $bitsLength; $i++) {
235
+ $this->bits[$i] = 0;
236
+ }
237
+ }
238
+
239
+ /**
240
+ * Checks if a range of bits is set or not set.
241
+ *
242
+ * @param integer $start
243
+ * @param integer $end
244
+ * @param integer $value
245
+ * @return boolean
246
+ * @throws Exception\InvalidArgumentException
247
+ */
248
+ public function isRange($start, $end, $value)
249
+ {
250
+ if ($end < $start) {
251
+ throw new Exception\InvalidArgumentException('End must be greater or equal to start');
252
+ }
253
+
254
+ if ($end === $start) {
255
+ return;
256
+ }
257
+
258
+ $end--;
259
+
260
+ $firstInt = $start >> 5;
261
+ $lastInt = $end >> 5;
262
+
263
+ for ($i = $firstInt; $i <= $lastInt; $i++) {
264
+ $firstBit = $i > $firstInt ? 0 : $start & 0x1f;
265
+ $lastBit = $i < $lastInt ? 31 : $end & 0x1f;
266
+
267
+ if ($firstBit === 0 && $lastBit === 31) {
268
+ $mask = 0x7fffffff;
269
+ } else {
270
+ $mask = 0;
271
+
272
+ for ($j = $firstBit; $j <= $lastBit; $j++) {
273
+ $mask |= 1 << $j;
274
+ }
275
+ }
276
+
277
+ if (($this->bits[$i] & $mask) !== ($value ? $mask : 0)) {
278
+ return false;
279
+ }
280
+ }
281
+
282
+ return true;
283
+ }
284
+
285
+ /**
286
+ * Appends a bit to the array.
287
+ *
288
+ * @param boolean $bit
289
+ * @return void
290
+ */
291
+ public function appendBit($bit)
292
+ {
293
+ $this->ensureCapacity($this->size + 1);
294
+
295
+ if ($bit) {
296
+ $this->bits[$this->size >> 5] = $this->bits[$this->size >> 5] | (1 << ($this->size & 0x1f));
297
+ }
298
+
299
+ $this->size++;
300
+ }
301
+
302
+ /**
303
+ * Appends a number of bits (up to 32) to the array.
304
+ *
305
+ * @param integer $value
306
+ * @param integer $numBits
307
+ * @return void
308
+ * @throws Exception\InvalidArgumentException
309
+ */
310
+ public function appendBits($value, $numBits)
311
+ {
312
+ if ($numBits < 0 || $numBits > 32) {
313
+ throw new Exception\InvalidArgumentException('Num bits must be between 0 and 32');
314
+ }
315
+
316
+ $this->ensureCapacity($this->size + $numBits);
317
+
318
+ for ($numBitsLeft = $numBits; $numBitsLeft > 0; $numBitsLeft--) {
319
+ $this->appendBit((($value >> ($numBitsLeft - 1)) & 0x01) === 1);
320
+ }
321
+ }
322
+
323
+ /**
324
+ * Appends another bit array to this array.
325
+ *
326
+ * @param BitArray $other
327
+ * @return void
328
+ */
329
+ public function appendBitArray(self $other)
330
+ {
331
+ $otherSize = $other->getSize();
332
+ $this->ensureCapacity($this->size + $other->getSize());
333
+
334
+ for ($i = 0; $i < $otherSize; $i++) {
335
+ $this->appendBit($other->get($i));
336
+ }
337
+ }
338
+
339
+ /**
340
+ * Makes an exclusive-or comparision on the current bit array.
341
+ *
342
+ * @param BitArray $other
343
+ * @return void
344
+ * @throws Exception\InvalidArgumentException
345
+ */
346
+ public function xorBits(self $other)
347
+ {
348
+ $bitsLength = count($this->bits);
349
+ $otherBits = $other->getBitArray();
350
+
351
+ if ($bitsLength !== count($otherBits)) {
352
+ throw new Exception\InvalidArgumentException('Sizes don\'t match');
353
+ }
354
+
355
+ for ($i = 0; $i < $bitsLength; $i++) {
356
+ $this->bits[$i] = $this->bits[$i] ^ $otherBits[$i];
357
+ }
358
+ }
359
+
360
+ /**
361
+ * Converts the bit array to a byte array.
362
+ *
363
+ * @param integer $bitOffset
364
+ * @param integer $numBytes
365
+ * @return SplFixedArray
366
+ */
367
+ public function toBytes($bitOffset, $numBytes)
368
+ {
369
+ $bytes = new SplFixedArray($numBytes);
370
+
371
+ for ($i = 0; $i < $numBytes; $i++) {
372
+ $byte = 0;
373
+
374
+ for ($j = 0; $j < 8; $j++) {
375
+ if ($this->get($bitOffset)) {
376
+ $byte |= 1 << (7 - $j);
377
+ }
378
+
379
+ $bitOffset++;
380
+ }
381
+
382
+ $bytes[$i] = $byte;
383
+ }
384
+
385
+ return $bytes;
386
+ }
387
+
388
+ /**
389
+ * Gets the internal bit array.
390
+ *
391
+ * @return SplFixedArray
392
+ */
393
+ public function getBitArray()
394
+ {
395
+ return $this->bits;
396
+ }
397
+
398
+ /**
399
+ * Reverses the array.
400
+ *
401
+ * @return void
402
+ */
403
+ public function reverse()
404
+ {
405
+ $newBits = new SplFixedArray(count($this->bits));
406
+
407
+ for ($i = 0; $i < $this->size; $i++) {
408
+ if ($this->get($this->size - $i - 1)) {
409
+ $newBits[$i >> 5] = $newBits[$i >> 5] | (1 << ($i & 0x1f));
410
+ }
411
+ }
412
+
413
+ $this->bits = newBits;
414
+ }
415
+
416
+ /**
417
+ * Returns a string representation of the bit array.
418
+ *
419
+ * @return string
420
+ */
421
+ public function __toString()
422
+ {
423
+ $result = '';
424
+
425
+ for ($i = 0; $i < $this->size; $i++) {
426
+ if (($i & 0x07) === 0) {
427
+ $result .= ' ';
428
+ }
429
+
430
+ $result .= $this->get($i) ? 'X' : '.';
431
+ }
432
+
433
+ return $result;
434
+ }
435
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitMatrix.php ADDED
@@ -0,0 +1,350 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Common;
11
+
12
+ use SplFixedArray;
13
+
14
+ /**
15
+ * Bit matrix.
16
+ *
17
+ * Represents a 2D matrix of bits. In function arguments below, and throughout
18
+ * the common module, x is the column position, and y is the row position. The
19
+ * ordering is always x, y. The origin is at the top-left.
20
+ */
21
+ class BitMatrix
22
+ {
23
+ /**
24
+ * Width of the bit matrix.
25
+ *
26
+ * @var integer
27
+ */
28
+ protected $width;
29
+
30
+ /**
31
+ * Height of the bit matrix.
32
+ *
33
+ * @var integer
34
+ */
35
+ protected $height;
36
+
37
+ /**
38
+ * Size in bits of each individual row.
39
+ *
40
+ * @var integer
41
+ */
42
+ protected $rowSize;
43
+
44
+ /**
45
+ * Bits representation.
46
+ *
47
+ * @var SplFixedArray
48
+ */
49
+ protected $bits;
50
+
51
+ /**
52
+ * Creates a new bit matrix with given dimensions.
53
+ *
54
+ * @param integer $width
55
+ * @param integer|null $height
56
+ * @throws Exception\InvalidArgumentException
57
+ */
58
+ public function __construct($width, $height = null)
59
+ {
60
+ if ($height === null) {
61
+ $height = $width;
62
+ }
63
+
64
+ if ($width < 1 || $height < 1) {
65
+ throw new Exception\InvalidArgumentException('Both dimensions must be greater than zero');
66
+ }
67
+
68
+ $this->width = $width;
69
+ $this->height = $height;
70
+ $this->rowSize = ($width + 31) >> 5;
71
+ $this->bits = new SplFixedArray($this->rowSize * $height);
72
+ }
73
+
74
+ /**
75
+ * Gets the requested bit, where true means black.
76
+ *
77
+ * @param integer $x
78
+ * @param integer $y
79
+ * @return boolean
80
+ */
81
+ public function get($x, $y)
82
+ {
83
+ $offset = $y * $this->rowSize + ($x >> 5);
84
+ return (BitUtils::unsignedRightShift($this->bits[$offset], ($x & 0x1f)) & 1) !== 0;
85
+ }
86
+
87
+ /**
88
+ * Sets the given bit to true.
89
+ *
90
+ * @param integer $x
91
+ * @param integer $y
92
+ * @return void
93
+ */
94
+ public function set($x, $y)
95
+ {
96
+ $offset = $y * $this->rowSize + ($x >> 5);
97
+ $this->bits[$offset] = $this->bits[$offset] | (1 << ($x & 0x1f));
98
+ }
99
+
100
+ /**
101
+ * Flips the given bit.
102
+ *
103
+ * @param integer $x
104
+ * @param integer $y
105
+ * @return void
106
+ */
107
+ public function flip($x, $y)
108
+ {
109
+ $offset = $y * $this->rowSize + ($x >> 5);
110
+ $this->bits[$offset] = $this->bits[$offset] ^ (1 << ($x & 0x1f));
111
+ }
112
+
113
+ /**
114
+ * Clears all bits (set to false).
115
+ *
116
+ * @return void
117
+ */
118
+ public function clear()
119
+ {
120
+ $max = count($this->bits);
121
+
122
+ for ($i = 0; $i < $max; $i++) {
123
+ $this->bits[$i] = 0;
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Sets a square region of the bit matrix to true.
129
+ *
130
+ * @param integer $left
131
+ * @param integer $top
132
+ * @param integer $width
133
+ * @param integer $height
134
+ * @return void
135
+ */
136
+ public function setRegion($left, $top, $width, $height)
137
+ {
138
+ if ($top < 0 || $left < 0) {
139
+ throw new Exception\InvalidArgumentException('Left and top must be non-negative');
140
+ }
141
+
142
+ if ($height < 1 || $width < 1) {
143
+ throw new Exception\InvalidArgumentException('Width and height must be at least 1');
144
+ }
145
+
146
+ $right = $left + $width;
147
+ $bottom = $top + $height;
148
+
149
+ if ($bottom > $this->height || $right > $this->width) {
150
+ throw new Exception\InvalidArgumentException('The region must fit inside the matrix');
151
+ }
152
+
153
+ for ($y = $top; $y < $bottom; $y++) {
154
+ $offset = $y * $this->rowSize;
155
+
156
+ for ($x = $left; $x < $right; $x++) {
157
+ $index = $offset + ($x >> 5);
158
+ $this->bits[$index] = $this->bits[$index] | (1 << ($x & 0x1f));
159
+ }
160
+ }
161
+ }
162
+
163
+ /**
164
+ * A fast method to retrieve one row of data from the matrix as a BitArray.
165
+ *
166
+ * @param integer $y
167
+ * @param BitArray $row
168
+ * @return BitArray
169
+ */
170
+ public function getRow($y, BitArray $row = null)
171
+ {
172
+ if ($row === null || $row->getSize() < $this->width) {
173
+ $row = new BitArray($this->width);
174
+ }
175
+
176
+ $offset = $y * $this->rowSize;
177
+
178
+ for ($x = 0; $x < $this->rowSize; $x++) {
179
+ $row->setBulk($x << 5, $this->bits[$offset + $x]);
180
+ }
181
+
182
+ return $row;
183
+ }
184
+
185
+ /**
186
+ * Sets a row of data from a BitArray.
187
+ *
188
+ * @param integer $y
189
+ * @param BitArray $row
190
+ * @return void
191
+ */
192
+ public function setRow($y, BitArray $row)
193
+ {
194
+ $bits = $row->getBitArray();
195
+
196
+ for ($i = 0; $i < $this->rowSize; $i++) {
197
+ $this->bits[$y * $this->rowSize + $i] = $bits[$i];
198
+ }
199
+ }
200
+
201
+ /**
202
+ * This is useful in detecting the enclosing rectangle of a 'pure' barcode.
203
+ *
204
+ * @return SplFixedArray
205
+ */
206
+ public function getEnclosingRectangle()
207
+ {
208
+ $left = $this->width;
209
+ $top = $this->height;
210
+ $right = -1;
211
+ $bottom = -1;
212
+
213
+ for ($y = 0; $y < $this->height; $y++) {
214
+ for ($x32 = 0; $x32 < $this->rowSize; $x32++) {
215
+ $bits = $this->bits[$y * $this->rowSize + $x32];
216
+
217
+ if ($bits !== 0) {
218
+ if ($y < $top) {
219
+ $top = $y;
220
+ }
221
+
222
+ if ($y > $bottom) {
223
+ $bottom = $y;
224
+ }
225
+
226
+ if ($x32 * 32 < $left) {
227
+ $bit = 0;
228
+
229
+ while (($bits << (31 - $bit)) === 0) {
230
+ $bit++;
231
+ }
232
+
233
+ if (($x32 * 32 + $bit) < $left) {
234
+ $left = $x32 * 32 + $bit;
235
+ }
236
+ }
237
+ }
238
+
239
+ if ($x32 * 32 + 31 > $right) {
240
+ $bit = 31;
241
+
242
+ while (BitUtils::unsignedRightShift($bits, $bit) === 0) {
243
+ $bit--;
244
+ }
245
+
246
+ if (($x32 * 32 + $bit) > $right) {
247
+ $right = $x32 * 32 + $bit;
248
+ }
249
+ }
250
+ }
251
+ }
252
+
253
+ $width = $right - $left;
254
+ $height = $bottom - $top;
255
+
256
+ if ($width < 0 || $height < 0) {
257
+ return null;
258
+ }
259
+
260
+ return SplFixedArray::fromArray(array($left, $top, $width, $height), false);
261
+ }
262
+
263
+ /**
264
+ * Gets the most top left set bit.
265
+ *
266
+ * This is useful in detecting a corner of a 'pure' barcode.
267
+ *
268
+ * @return SplFixedArray
269
+ */
270
+ public function getTopLeftOnBit()
271
+ {
272
+ $bitsOffset = 0;
273
+
274
+ while ($bitsOffset < count($this->bits) && $this->bits[$bitsOffset] === 0) {
275
+ $bitsOffset++;
276
+ }
277
+
278
+ if ($bitsOffset === count($this->bits)) {
279
+ return null;
280
+ }
281
+
282
+ $x = intval($bitsOffset / $this->rowSize);
283
+ $y = ($bitsOffset % $this->rowSize) << 5;
284
+
285
+ $bits = $this->bits[$bitsOffset];
286
+ $bit = 0;
287
+
288
+ while (($bits << (31 - $bit)) === 0) {
289
+ $bit++;
290
+ }
291
+
292
+ $x += $bit;
293
+
294
+ return SplFixedArray::fromArray(array($x, $y), false);
295
+ }
296
+
297
+ /**
298
+ * Gets the most bottom right set bit.
299
+ *
300
+ * This is useful in detecting a corner of a 'pure' barcode.
301
+ *
302
+ * @return SplFixedArray
303
+ */
304
+ public function getBottomRightOnBit()
305
+ {
306
+ $bitsOffset = count($this->bits) - 1;
307
+
308
+ while ($bitsOffset >= 0 && $this->bits[$bitsOffset] === 0) {
309
+ $bitsOffset--;
310
+ }
311
+
312
+ if ($bitsOffset < 0) {
313
+ return null;
314
+ }
315
+
316
+ $x = intval($bitsOffset / $this->rowSize);
317
+ $y = ($bitsOffset % $this->rowSize) << 5;
318
+
319
+ $bits = $this->bits[$bitsOffset];
320
+ $bit = 0;
321
+
322
+ while (BitUtils::unsignedRightShift($bits, $bit) === 0) {
323
+ $bit--;
324
+ }
325
+
326
+ $x += $bit;
327
+
328
+ return SplFixedArray::fromArray(array($x, $y), false);
329
+ }
330
+
331
+ /**
332
+ * Gets the width of the matrix,
333
+ *
334
+ * @return integer
335
+ */
336
+ public function getWidth()
337
+ {
338
+ return $this->width;
339
+ }
340
+
341
+ /**
342
+ * Gets the height of the matrix.
343
+ *
344
+ * @return integer
345
+ */
346
+ public function getHeight()
347
+ {
348
+ return $this->height;
349
+ }
350
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/BitUtils.php ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Common;
11
+
12
+ /**
13
+ * General bit utilities.
14
+ *
15
+ * All utility methods are based on 32-bit integers and also work on 64-bit
16
+ * systems.
17
+ */
18
+ class BitUtils
19
+ {
20
+ /**
21
+ * Performs an unsigned right shift.
22
+ *
23
+ * This is the same as the unsigned right shift operator ">>>" in other
24
+ * languages.
25
+ *
26
+ * @param integer $a
27
+ * @param integer $b
28
+ * @return integer
29
+ */
30
+ public static function unsignedRightShift($a, $b)
31
+ {
32
+ return (
33
+ $a >= 0
34
+ ? $a >> $b
35
+ : (($a & 0x7fffffff) >> $b) | (0x40000000 >> ($b - 1))
36
+ );
37
+ }
38
+
39
+ /**
40
+ * Gets the number of trailing zeros.
41
+ *
42
+ * @param integer $i
43
+ * @return integer
44
+ */
45
+ public static function numberOfTrailingZeros($i)
46
+ {
47
+ $lastPos = strrpos(str_pad(decbin($i), 32, '0', STR_PAD_LEFT), '1');
48
+
49
+ return $lastPos === false ? 32 : 31 - $lastPos;
50
+ }
51
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/CharacterSetEci.php ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Common;
11
+
12
+ /**
13
+ * Encapsulates a Character Set ECI, according to "Extended Channel
14
+ * Interpretations" 5.3.1.1 of ISO 18004.
15
+ */
16
+ class CharacterSetEci extends AbstractEnum
17
+ {
18
+ /**#@+
19
+ * Character set constants.
20
+ */
21
+ const CP437 = 0;
22
+ const ISO8859_1 = 1;
23
+ const ISO8859_2 = 4;
24
+ const ISO8859_3 = 5;
25
+ const ISO8859_4 = 6;
26
+ const ISO8859_5 = 7;
27
+ const ISO8859_6 = 8;
28
+ const ISO8859_7 = 9;
29
+ const ISO8859_8 = 10;
30
+ const ISO8859_9 = 11;
31
+ const ISO8859_10 = 12;
32
+ const ISO8859_11 = 13;
33
+ const ISO8859_12 = 14;
34
+ const ISO8859_13 = 15;
35
+ const ISO8859_14 = 16;
36
+ const ISO8859_15 = 17;
37
+ const ISO8859_16 = 18;
38
+ const SJIS = 20;
39
+ const CP1250 = 21;
40
+ const CP1251 = 22;
41
+ const CP1252 = 23;
42
+ const CP1256 = 24;
43
+ const UNICODE_BIG_UNMARKED = 25;
44
+ const UTF8 = 26;
45
+ const ASCII = 27;
46
+ const BIG5 = 28;
47
+ const GB18030 = 29;
48
+ const EUC_KR = 30;
49
+ /**#@-*/
50
+
51
+ /**
52
+ * Map between character names and their ECI values.
53
+ *
54
+ * @var array
55
+ */
56
+ protected static $nameToEci = array(
57
+ 'ISO-8859-1' => self::ISO8859_1,
58
+ 'ISO-8859-2' => self::ISO8859_2,
59
+ 'ISO-8859-3' => self::ISO8859_3,
60
+ 'ISO-8859-4' => self::ISO8859_4,
61
+ 'ISO-8859-5' => self::ISO8859_5,
62
+ 'ISO-8859-6' => self::ISO8859_6,
63
+ 'ISO-8859-7' => self::ISO8859_7,
64
+ 'ISO-8859-8' => self::ISO8859_8,
65
+ 'ISO-8859-9' => self::ISO8859_9,
66
+ 'ISO-8859-10' => self::ISO8859_10,
67
+ 'ISO-8859-11' => self::ISO8859_11,
68
+ 'ISO-8859-12' => self::ISO8859_12,
69
+ 'ISO-8859-13' => self::ISO8859_13,
70
+ 'ISO-8859-14' => self::ISO8859_14,
71
+ 'ISO-8859-15' => self::ISO8859_15,
72
+ 'ISO-8859-16' => self::ISO8859_16,
73
+ 'SHIFT-JIS' => self::SJIS,
74
+ 'WINDOWS-1250' => self::CP1250,
75
+ 'WINDOWS-1251' => self::CP1251,
76
+ 'WINDOWS-1252' => self::CP1252,
77
+ 'WINDOWS-1256' => self::CP1256,
78
+ 'UTF-16BE' => self::UNICODE_BIG_UNMARKED,
79
+ 'UTF-8' => self::UTF8,
80
+ 'ASCII' => self::ASCII,
81
+ 'GBK' => self::GB18030,
82
+ 'EUC-KR' => self::EUC_KR,
83
+ );
84
+
85
+ /**
86
+ * Additional possible values for character sets.
87
+ *
88
+ * @var array
89
+ */
90
+ protected $additionalValues = array(
91
+ self::CP437 => 2,
92
+ self::ASCII => 170,
93
+ );
94
+
95
+ /**
96
+ * Gets character set ECI by value.
97
+ *
98
+ * @param string $name
99
+ * @return CharacterSetEci|null
100
+ */
101
+ public static function getCharacterSetECIByValue($value)
102
+ {
103
+ if ($value < 0 || $value >= 900) {
104
+ throw new Exception\InvalidArgumentException('Value must be between 0 and 900');
105
+ }
106
+
107
+ if (false !== ($key = array_search($value, self::$additionalValues))) {
108
+ $value = $key;
109
+ }
110
+
111
+ try {
112
+ return new self($value);
113
+ } catch (Exception\UnexpectedValueException $e) {
114
+ return null;
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Gets character set ECI by name.
120
+ *
121
+ * @param string $name
122
+ * @return CharacterSetEci|null
123
+ */
124
+ public static function getCharacterSetECIByName($name)
125
+ {
126
+ $name = strtoupper($name);
127
+
128
+ if (isset(self::$nameToEci[$name])) {
129
+ return new self(self::$nameToEci[$name]);
130
+ }
131
+
132
+ return null;
133
+ }
134
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/EcBlock.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Common;
11
+
12
+ /**
13
+ * Encapsualtes the parameters for one error-correction block in one symbol
14
+ * version. This includes the number of data codewords, and the number of times
15
+ * a block with these parameters is used consecutively in the QR code version's
16
+ * format.
17
+ */
18
+ class EcBlock
19
+ {
20
+ /**
21
+ * How many times the block is used.
22
+ *
23
+ * @var integer
24
+ */
25
+ protected $count;
26
+
27
+ /**
28
+ * Number of data codewords.
29
+ *
30
+ * @var integer
31
+ */
32
+ protected $dataCodewords;
33
+
34
+ /**
35
+ * Creates a new EC block.
36
+ *
37
+ * @param integer $count
38
+ * @param integer $dataCodewords
39
+ */
40
+ public function __construct($count, $dataCodewords)
41
+ {
42
+ $this->count = $count;
43
+ $this->dataCodewords = $dataCodewords;
44
+ }
45
+
46
+ /**
47
+ * Returns how many times the block is used.
48
+ *
49
+ * @return integer
50
+ */
51
+ public function getCount()
52
+ {
53
+ return $this->count;
54
+ }
55
+
56
+ /**
57
+ * Returns the number of data codewords.
58
+ *
59
+ * @return integer
60
+ */
61
+ public function getDataCodewords()
62
+ {
63
+ return $this->dataCodewords;
64
+ }
65
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/EcBlocks.php ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Common;
11
+
12
+ use SplFixedArray;
13
+
14
+ /**
15
+ * Encapsulates a set of error-correction blocks in one symbol version. Most
16
+ * versions will use blocks of differing sizes within one version, so, this
17
+ * encapsulates the parameters for each set of blocks. It also holds the number
18
+ * of error-correction codewords per block since it will be the same across all
19
+ * blocks within one version.
20
+ */
21
+ class EcBlocks
22
+ {
23
+ /**
24
+ * Number of EC codewords per block.
25
+ *
26
+ * @var integer
27
+ */
28
+ protected $ecCodewordsPerBlock;
29
+
30
+ /**
31
+ * List of EC blocks.
32
+ *
33
+ * @var SplFixedArray
34
+ */
35
+ protected $ecBlocks;
36
+
37
+ /**
38
+ * Creates a new EC blocks instance.
39
+ *
40
+ * @param integer $ecCodewordsPerBlock
41
+ * @param EcBlock $ecb1
42
+ * @param EcBlock|null $ecb2
43
+ */
44
+ public function __construct($ecCodewordsPerBlock, EcBlock $ecb1, EcBlock $ecb2 = null)
45
+ {
46
+ $this->ecCodewordsPerBlock = $ecCodewordsPerBlock;
47
+
48
+ $this->ecBlocks = new SplFixedArray($ecb2 === null ? 1 : 2);
49
+ $this->ecBlocks[0] = $ecb1;
50
+
51
+ if ($ecb2 !== null) {
52
+ $this->ecBlocks[1] = $ecb2;
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Gets the number of EC codewords per block.
58
+ *
59
+ * @return integer
60
+ */
61
+ public function getEcCodewordsPerBlock()
62
+ {
63
+ return $this->ecCodewordsPerBlock;
64
+ }
65
+
66
+ /**
67
+ * Gets the total number of EC block appearances.
68
+ *
69
+ * @return integer
70
+ */
71
+ public function getNumBlocks()
72
+ {
73
+ $total = 0;
74
+
75
+ foreach ($this->ecBlocks as $ecBlock) {
76
+ $total += $ecBlock->getCount();
77
+ }
78
+
79
+ return $total;
80
+ }
81
+
82
+ /**
83
+ * Gets the total count of EC codewords.
84
+ *
85
+ * @return integer
86
+ */
87
+ public function getTotalEcCodewords()
88
+ {
89
+ return $this->ecCodewordsPerBlock * $this->getNumBlocks();
90
+ }
91
+
92
+ /**
93
+ * Gets the EC blocks included in this collection.
94
+ *
95
+ * @return SplFixedArray
96
+ */
97
+ public function getEcBlocks()
98
+ {
99
+ return $this->ecBlocks;
100
+ }
101
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/ErrorCorrectionLevel.php ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Common;
11
+
12
+ /**
13
+ * Enum representing the four error correction levels.
14
+ */
15
+ class ErrorCorrectionLevel extends AbstractEnum
16
+ {
17
+ /**
18
+ * Level L, ~7% correction.
19
+ */
20
+ const L = 0x1;
21
+
22
+ /**
23
+ * Level M, ~15% correction.
24
+ */
25
+ const M = 0x0;
26
+
27
+ /**
28
+ * Level Q, ~25% correction.
29
+ */
30
+ const Q = 0x3;
31
+
32
+ /**
33
+ * Level H, ~30% correction.
34
+ */
35
+ const H = 0x2;
36
+
37
+ /**
38
+ * Gets the ordinal of this enumeration constant.
39
+ *
40
+ * @return integer
41
+ */
42
+ public function getOrdinal()
43
+ {
44
+ switch ($this->value) {
45
+ case self::L:
46
+ return 0;
47
+ break;
48
+
49
+ case self::M:
50
+ return 1;
51
+ break;
52
+
53
+ case self::Q:
54
+ return 2;
55
+ break;
56
+
57
+ case self::H:
58
+ return 3;
59
+ break;
60
+ }
61
+ }
62
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/FormatInformation.php ADDED
@@ -0,0 +1,236 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Common;
11
+
12
+ /**
13
+ * Encapsulates a QR Code's format information, including the data mask used and
14
+ * error correction level.
15
+ */
16
+ class FormatInformation
17
+ {
18
+ /**
19
+ * Mask for format information.
20
+ */
21
+ const FORMAT_INFO_MASK_QR = 0x5412;
22
+
23
+ /**
24
+ * Lookup table for decoding format information.
25
+ *
26
+ * See ISO 18004:2006, Annex C, Table C.1
27
+ *
28
+ * @var array
29
+ */
30
+ protected static $formatInfoDecodeLookup = array(
31
+ array(0x5412, 0x00),
32
+ array(0x5125, 0x01),
33
+ array(0x5e7c, 0x02),
34
+ array(0x5b4b, 0x03),
35
+ array(0x45f9, 0x04),
36
+ array(0x40ce, 0x05),
37
+ array(0x4f97, 0x06),
38
+ array(0x4aa0, 0x07),
39
+ array(0x77c4, 0x08),
40
+ array(0x72f3, 0x09),
41
+ array(0x7daa, 0x0a),
42
+ array(0x789d, 0x0b),
43
+ array(0x662f, 0x0c),
44
+ array(0x6318, 0x0d),
45
+ array(0x6c41, 0x0e),
46
+ array(0x6976, 0x0f),
47
+ array(0x1689, 0x10),
48
+ array(0x13be, 0x11),
49
+ array(0x1ce7, 0x12),
50
+ array(0x19d0, 0x13),
51
+ array(0x0762, 0x14),
52
+ array(0x0255, 0x15),
53
+ array(0x0d0c, 0x16),
54
+ array(0x083b, 0x17),
55
+ array(0x355f, 0x18),
56
+ array(0x3068, 0x19),
57
+ array(0x3f31, 0x1a),
58
+ array(0x3a06, 0x1b),
59
+ array(0x24b4, 0x1c),
60
+ array(0x2183, 0x1d),
61
+ array(0x2eda, 0x1e),
62
+ array(0x2bed, 0x1f),
63
+ );
64
+
65
+ /**
66
+ * Offset i holds the number of 1 bits in the binary representation of i.
67
+ *
68
+ * @var array
69
+ */
70
+ protected static $bitsSetInHalfByte = array(0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4);
71
+
72
+ /**
73
+ * Error correction level.
74
+ *
75
+ * @var ErrorCorrectionLevel
76
+ */
77
+ protected $ecLevel;
78
+
79
+ /**
80
+ * Data mask.
81
+ *
82
+ * @var integer
83
+ */
84
+ protected $dataMask;
85
+
86
+ /**
87
+ * Creates a new format information instance.
88
+ *
89
+ * @param integer $formatInfo
90
+ */
91
+ protected function __construct($formatInfo)
92
+ {
93
+ $this->ecLevel = new ErrorCorrectionLevel(($formatInfo >> 3) & 0x3);
94
+ $this->dataMask = $formatInfo & 0x7;
95
+ }
96
+
97
+ /**
98
+ * Checks how many bits are different between two integers.
99
+ *
100
+ * @param integer $a
101
+ * @param integer $b
102
+ * @return integer
103
+ */
104
+ public static function numBitsDiffering($a, $b)
105
+ {
106
+ $a ^= $b;
107
+
108
+ return (
109
+ self::$bitsSetInHalfByte[$a & 0xf]
110
+ + self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 4) & 0xf)]
111
+ + self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 8) & 0xf)]
112
+ + self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 12) & 0xf)]
113
+ + self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 16) & 0xf)]
114
+ + self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 20) & 0xf)]
115
+ + self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 24) & 0xf)]
116
+ + self::$bitsSetInHalfByte[(BitUtils::unsignedRightShift($a, 28) & 0xf)]
117
+ );
118
+ }
119
+
120
+ /**
121
+ * Decodes format information.
122
+ *
123
+ * @param integer $maskedFormatInfo1
124
+ * @param integer $maskedFormatInfo2
125
+ * @return FormatInformation|null
126
+ */
127
+ public static function decodeFormatInformation($maskedFormatInfo1, $maskedFormatInfo2)
128
+ {
129
+ $formatInfo = self::doDecodeFormatInformation($maskedFormatInfo1, $maskedFormatInfo2);
130
+
131
+ if ($formatInfo !== null) {
132
+ return $formatInfo;
133
+ }
134
+
135
+ // Should return null, but, some QR codes apparently do not mask this
136
+ // info. Try again by actually masking the pattern first.
137
+ return self::doDecodeFormatInformation(
138
+ $maskedFormatInfo1 ^ self::FORMAT_INFO_MASK_QR,
139
+ $maskedFormatInfo2 ^ self::FORMAT_INFO_MASK_QR
140
+ );
141
+ }
142
+
143
+ /**
144
+ * Internal method for decoding format information.
145
+ *
146
+ * @param integer $maskedFormatInfo1
147
+ * @param integer $maskedFormatInfo2
148
+ * @return FormatInformation|null
149
+ */
150
+ protected static function doDecodeFormatInformation($maskedFormatInfo1, $maskedFormatInfo2)
151
+ {
152
+ $bestDifference = PHP_INT_MAX;
153
+ $bestFormatInfo = 0;
154
+
155
+ foreach (self::$formatInfoDecodeLookup as $decodeInfo) {
156
+ $targetInfo = $decodeInfo[0];
157
+
158
+ if ($targetInfo === $maskedFormatInfo1 || $targetInfo === $maskedFormatInfo2) {
159
+ // Found an exact match
160
+ return new self($decodeInfo[1]);
161
+ }
162
+
163
+ $bitsDifference = self::numBitsDiffering($maskedFormatInfo1, $targetInfo);
164
+
165
+ if ($bitsDifference < $bestDifference) {
166
+ $bestFormatInfo = $decodeInfo[1];
167
+ $bestDifference = $bitsDifference;
168
+ }
169
+
170
+ if ($maskedFormatInfo1 !== $maskedFormatInfo2) {
171
+ // Also try the other option
172
+ $bitsDifference = self::numBitsDiffering($maskedFormatInfo2, $targetInfo);
173
+
174
+ if ($bitsDifference < $bestDifference) {
175
+ $bestFormatInfo = $decodeInfo[1];
176
+ $bestDifference = $bitsDifference;
177
+ }
178
+ }
179
+ }
180
+
181
+ // Hamming distance of the 32 masked codes is 7, by construction, so
182
+ // <= 3 bits differing means we found a match.
183
+ if ($bestDifference <= 3) {
184
+ return new self($bestFormatInfo);
185
+ }
186
+
187
+ return null;
188
+ }
189
+
190
+ /**
191
+ * Gets the error correction level.
192
+ *
193
+ * @return ErrorCorrectionLevel
194
+ */
195
+ public function getErrorCorrectionLevel()
196
+ {
197
+ return $this->ecLevel;
198
+ }
199
+
200
+ /**
201
+ * Gets the data mask.
202
+ *
203
+ * @return integer
204
+ */
205
+ public function getDataMask()
206
+ {
207
+ return $this->dataMask;
208
+ }
209
+
210
+ /**
211
+ * Hashes the code of the EC level.
212
+ *
213
+ * @return integer
214
+ */
215
+ public function hashCode()
216
+ {
217
+ return ($this->ecLevel->get() << 3) | $this->dataMask;
218
+ }
219
+
220
+ /**
221
+ * Verifies if this instance equals another one.
222
+ *
223
+ * @param mixed $other
224
+ * @return boolean
225
+ */
226
+ public function equals($other) {
227
+ if (!$other instanceof self) {
228
+ return false;
229
+ }
230
+
231
+ return (
232
+ $this->ecLevel->get() === $other->getErrorCorrectionLevel()->get()
233
+ && $this->dataMask === $other->getDataMask()
234
+ );
235
+ }
236
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/Mode.php ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Common;
11
+
12
+ /**
13
+ * Enum representing various modes in which data can be encoded to bits.
14
+ */
15
+ class Mode extends AbstractEnum
16
+ {
17
+ /**#@+
18
+ * Mode constants.
19
+ */
20
+ const TERMINATOR = 0x0;
21
+ const NUMERIC = 0x1;
22
+ const ALPHANUMERIC = 0x2;
23
+ const STRUCTURED_APPEND = 0x3;
24
+ const BYTE = 0x4;
25
+ const ECI = 0x7;
26
+ const KANJI = 0x8;
27
+ const FNC1_FIRST_POSITION = 0x5;
28
+ const FNC1_SECOND_POSITION = 0x9;
29
+ const HANZI = 0xd;
30
+ /**#@-*/
31
+
32
+ /**
33
+ * Character count bits for each version.
34
+ *
35
+ * @var array
36
+ */
37
+ protected static $characterCountBitsForVersions = array(
38
+ self::TERMINATOR => array(0, 0, 0),
39
+ self::NUMERIC => array(10, 12, 14),
40
+ self::ALPHANUMERIC => array(9, 11, 13),
41
+ self::STRUCTURED_APPEND => array(0, 0, 0),
42
+ self::BYTE => array(8, 16, 16),
43
+ self::ECI => array(0, 0, 0),
44
+ self::KANJI => array(8, 10, 12),
45
+ self::FNC1_FIRST_POSITION => array(0, 0, 0),
46
+ self::FNC1_SECOND_POSITION => array(0, 0, 0),
47
+ self::HANZI => array(8, 10, 12),
48
+ );
49
+
50
+ /**
51
+ * Gets the number of bits used in a specific QR code version.
52
+ *
53
+ * @param Version $version
54
+ * @return integer
55
+ */
56
+ public function getCharacterCountBits(Version $version)
57
+ {
58
+ $number = $version->getVersionNumber();
59
+
60
+ if ($number <= 9) {
61
+ $offset = 0;
62
+ } elseif ($number <= 26) {
63
+ $offset = 1;
64
+ } else {
65
+ $offset = 2;
66
+ }
67
+
68
+ return self::$characterCountBitsForVersions[$this->value][$offset];
69
+ }
70
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/ReedSolomonCodec.php ADDED
@@ -0,0 +1,476 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Common;
11
+
12
+ use BaconQrCode\Exception;
13
+ use SplFixedArray;
14
+
15
+ /**
16
+ * Reed-Solomon codec for 8-bit characters.
17
+ *
18
+ * Based on libfec by Phil Karn, KA9Q.
19
+ */
20
+ class ReedSolomonCodec
21
+ {
22
+ /**
23
+ * Symbol size in bits.
24
+ *
25
+ * @var integer
26
+ */
27
+ protected $symbolSize;
28
+
29
+ /**
30
+ * Block size in symbols.
31
+ *
32
+ * @var integer
33
+ */
34
+ protected $blockSize;
35
+
36
+ /**
37
+ * First root of RS code generator polynomial, index form.
38
+ *
39
+ * @var integer
40
+ */
41
+ protected $firstRoot;
42
+
43
+ /**
44
+ * Primitive element to generate polynomial roots, index form.
45
+ *
46
+ * @var integer
47
+ */
48
+ protected $primitive;
49
+
50
+ /**
51
+ * Prim-th root of 1, index form.
52
+ *
53
+ * @var integer
54
+ */
55
+ protected $iPrimitive;
56
+
57
+ /**
58
+ * RS code generator polynomial degree (number of roots).
59
+ *
60
+ * @var integer
61
+ */
62
+ protected $numRoots;
63
+
64
+ /**
65
+ * Padding bytes at front of shortened block.
66
+ *
67
+ * @var integer
68
+ */
69
+ protected $padding;
70
+
71
+ /**
72
+ * Log lookup table.
73
+ *
74
+ * @var SplFixedArray
75
+ */
76
+ protected $alphaTo;
77
+
78
+ /**
79
+ * Anti-Log lookup table.
80
+ *
81
+ * @var SplFixedArray
82
+ */
83
+ protected $indexOf;
84
+
85
+ /**
86
+ * Generator polynomial.
87
+ *
88
+ * @var SplFixedArray
89
+ */
90
+ protected $generatorPoly;
91
+
92
+ /**
93
+ * Creates a new reed solomon instance.
94
+ *
95
+ * @param integer $symbolSize
96
+ * @param integer $gfPoly
97
+ * @param integer $firstRoot
98
+ * @param integer $primitive
99
+ * @param integer $numRoots
100
+ * @param integer $padding
101
+ * @throws Exception\InvalidArgumentException
102
+ * @throws Exception\RuntimeException
103
+ */
104
+ public function __construct($symbolSize, $gfPoly, $firstRoot, $primitive, $numRoots, $padding)
105
+ {
106
+ if ($symbolSize < 0 || $symbolSize > 8) {
107
+ throw new Exception\InvalidArgumentException('Symbol size must be between 0 and 8');
108
+ }
109
+
110
+ if ($firstRoot < 0 || $firstRoot >= (1 << $symbolSize)) {
111
+ throw new Exception\InvalidArgumentException('First root must be between 0 and ' . (1 << $symbolSize));
112
+ }
113
+
114
+ if ($numRoots < 0 || $numRoots >= (1 << $symbolSize)) {
115
+ throw new Exception\InvalidArgumentException('Num roots must be between 0 and ' . (1 << $symbolSize));
116
+ }
117
+
118
+ if ($padding < 0 || $padding >= ((1 << $symbolSize) - 1 - $numRoots)) {
119
+ throw new Exception\InvalidArgumentException('Padding must be between 0 and ' . ((1 << $symbolSize) - 1 - $numRoots));
120
+ }
121
+
122
+ $this->symbolSize = $symbolSize;
123
+ $this->blockSize = (1 << $symbolSize) - 1;
124
+ $this->padding = $padding;
125
+ $this->alphaTo = SplFixedArray::fromArray(array_fill(0, $this->blockSize + 1, 0), false);
126
+ $this->indexOf = SplFixedArray::fromArray(array_fill(0, $this->blockSize + 1, 0), false);
127
+
128
+ // Generate galous field lookup table
129
+ $this->indexOf[0] = $this->blockSize;
130
+ $this->alphaTo[$this->blockSize] = 0;
131
+
132
+ $sr = 1;
133
+
134
+ for ($i = 0; $i < $this->blockSize; $i++) {
135
+ $this->indexOf[$sr] = $i;
136
+ $this->alphaTo[$i] = $sr;
137
+
138
+ $sr <<= 1;
139
+
140
+ if ($sr & (1 << $symbolSize)) {
141
+ $sr ^= $gfPoly;
142
+ }
143
+
144
+ $sr &= $this->blockSize;
145
+ }
146
+
147
+ if ($sr !== 1) {
148
+ throw new Exception\RuntimeException('Field generator polynomial is not primitive');
149
+ }
150
+
151
+ // Form RS code generator polynomial from its roots
152
+ $this->generatorPoly = SplFixedArray::fromArray(array_fill(0, $numRoots + 1, 0), false);
153
+ $this->firstRoot = $firstRoot;
154
+ $this->primitive = $primitive;
155
+ $this->numRoots = $numRoots;
156
+
157
+ // Find prim-th root of 1, used in decoding
158
+ for ($iPrimitive = 1; ($iPrimitive % $primitive) !== 0; $iPrimitive += $this->blockSize);
159
+ $this->iPrimitive = intval($iPrimitive / $primitive);
160
+
161
+ $this->generatorPoly[0] = 1;
162
+
163
+ for ($i = 0, $root = $firstRoot * $primitive; $i < $numRoots; $i++, $root += $primitive) {
164
+ $this->generatorPoly[$i + 1] = 1;
165
+
166
+ for ($j = $i; $j > 0; $j--) {
167
+ if ($this->generatorPoly[$j] !== 0) {
168
+ $this->generatorPoly[$j] = $this->generatorPoly[$j - 1] ^ $this->alphaTo[$this->modNn($this->indexOf[$this->generatorPoly[$j]] + $root)];
169
+ } else {
170
+ $this->generatorPoly[$j] = $this->generatorPoly[$j - 1];
171
+ }
172
+ }
173
+
174
+ $this->generatorPoly[$j] = $this->alphaTo[$this->modNn($this->indexOf[$this->generatorPoly[0]] + $root)];
175
+ }
176
+
177
+ // Convert generator poly to index form for quicker encoding
178
+ for ($i = 0; $i <= $numRoots; $i++) {
179
+ $this->generatorPoly[$i] = $this->indexOf[$this->generatorPoly[$i]];
180
+ }
181
+ }
182
+
183
+ /**
184
+ * Encodes data and writes result back into parity array.
185
+ *
186
+ * @param SplFixedArray $data
187
+ * @param SplFixedArray $parity
188
+ * @return void
189
+ */
190
+ public function encode(SplFixedArray $data, SplFixedArray $parity)
191
+ {
192
+ for ($i = 0; $i < $this->numRoots; $i++) {
193
+ $parity[$i] = 0;
194
+ }
195
+
196
+ $iterations = $this->blockSize - $this->numRoots - $this->padding;
197
+
198
+ for ($i = 0; $i < $iterations; $i++) {
199
+ $feedback = $this->indexOf[$data[$i] ^ $parity[0]];
200
+
201
+ if ($feedback !== $this->blockSize) {
202
+ // Feedback term is non-zero
203
+ $feedback = $this->modNn($this->blockSize - $this->generatorPoly[$this->numRoots] + $feedback);
204
+
205
+ for ($j = 1; $j < $this->numRoots; $j++) {
206
+ $parity[$j] = $parity[$j] ^ $this->alphaTo[$this->modNn($feedback + $this->generatorPoly[$this->numRoots - $j])];
207
+ }
208
+ }
209
+
210
+ for ($j = 0; $j < $this->numRoots - 1; $j++) {
211
+ $parity[$j] = $parity[$j + 1];
212
+ }
213
+
214
+ if ($feedback !== $this->blockSize) {
215
+ $parity[$this->numRoots - 1] = $this->alphaTo[$this->modNn($feedback + $this->generatorPoly[0])];
216
+ } else {
217
+ $parity[$this->numRoots - 1] = 0;
218
+ }
219
+ }
220
+ }
221
+
222
+ /**
223
+ * Decodes received data.
224
+ *
225
+ * @param SplFixedArray $data
226
+ * @param SplFixedArray|null $erasures
227
+ * @return null|integer
228
+ */
229
+ public function decode(SplFixedArray $data, SplFixedArray $erasures = null)
230
+ {
231
+ // This speeds up the initialization a bit.
232
+ $numRootsPlusOne = SplFixedArray::fromArray(array_fill(0, $this->numRoots + 1, 0), false);
233
+ $numRoots = SplFixedArray::fromArray(array_fill(0, $this->numRoots, 0), false);
234
+
235
+ $lambda = clone $numRootsPlusOne;
236
+ $b = clone $numRootsPlusOne;
237
+ $t = clone $numRootsPlusOne;
238
+ $omega = clone $numRootsPlusOne;
239
+ $root = clone $numRoots;
240
+ $loc = clone $numRoots;
241
+
242
+ $numErasures = ($erasures !== null ? count($erasures) : 0);
243
+
244
+ // Form the Syndromes; i.e., evaluate data(x) at roots of g(x)
245
+ $syndromes = SplFixedArray::fromArray(array_fill(0, $this->numRoots, $data[0]), false);
246
+
247
+ for ($i = 1; $i < $this->blockSize - $this->padding; $i++) {
248
+ for ($j = 0; $j < $this->numRoots; $j++) {
249
+ if ($syndromes[$j] === 0) {
250
+ $syndromes[$j] = $data[$i];
251
+ } else {
252
+ $syndromes[$j] = $data[$i] ^ $this->alphaTo[
253
+ $this->modNn($this->indexOf[$syndromes[$j]] + ($this->firstRoot + $j) * $this->primitive)
254
+ ];
255
+ }
256
+ }
257
+ }
258
+
259
+ // Convert syndromes to index form, checking for nonzero conditions
260
+ $syndromeError = 0;
261
+
262
+ for ($i = 0; $i < $this->numRoots; $i++) {
263
+ $syndromeError |= $syndromes[$i];
264
+ $syndromes[$i] = $this->indexOf[$syndromes[$i]];
265
+ }
266
+
267
+ if (!$syndromeError) {
268
+ // If syndrome is zero, data[] is a codeword and there are no errors
269
+ // to correct, so return data[] unmodified.
270
+ return 0;
271
+ }
272
+
273
+ $lambda[0] = 1;
274
+
275
+ if ($numErasures > 0) {
276
+ // Init lambda to be the erasure locator polynomial
277
+ $lambda[1] = $this->alphaTo[$this->modNn($this->primitive * ($this->blockSize - 1 - $erasures[0]))];
278
+
279
+ for ($i = 1; $i < $numErasures; $i++) {
280
+ $u = $this->modNn($this->primitive * ($this->blockSize - 1 - $erasures[$i]));
281
+
282
+ for ($j = $i + 1; $j > 0; $j--) {
283
+ $tmp = $this->indexOf[$lambda[$j - 1]];
284
+
285
+ if ($tmp !== $this->blockSize) {
286
+ $lambda[$j] = $lambda[$j] ^ $this->alphaTo[$this->modNn($u + $tmp)];
287
+ }
288
+ }
289
+ }
290
+ }
291
+
292
+ for ($i = 0; $i <= $this->numRoots; $i++) {
293
+ $b[$i] = $this->indexOf[$lambda[$i]];
294
+ }
295
+
296
+ // Begin Berlekamp-Massey algorithm to determine error+erasure locator
297
+ // polynomial
298
+ $r = $numErasures;
299
+ $el = $numErasures;
300
+
301
+ while (++$r <= $this->numRoots) {
302
+ // Compute discrepancy at the r-th step in poly form
303
+ $discrepancyR = 0;
304
+
305
+ for ($i = 0; $i < $r; $i++) {
306
+ if ($lambda[$i] !== 0 && $syndromes[$r - $i - 1] !== $this->blockSize) {
307
+ $discrepancyR ^= $this->alphaTo[$this->modNn($this->indexOf[$lambda[$i]] + $syndromes[$r - $i - 1])];
308
+ }
309
+ }
310
+
311
+ $discrepancyR = $this->indexOf[$discrepancyR];
312
+
313
+ if ($discrepancyR === $this->blockSize) {
314
+ $tmp = $b->toArray();
315
+ array_unshift($tmp, $this->blockSize);
316
+ array_pop($tmp);
317
+ $b = SplFixedArray::fromArray($tmp, false);
318
+ } else {
319
+ $t[0] = $lambda[0];
320
+
321
+ for ($i = 0; $i < $this->numRoots; $i++) {
322
+ if ($b[$i] !== $this->blockSize) {
323
+ $t[$i + 1] = $lambda[$i + 1] ^ $this->alphaTo[$this->modNn($discrepancyR + $b[$i])];
324
+ } else {
325
+ $t[$i + 1] = $lambda[$i + 1];
326
+ }
327
+ }
328
+
329
+ if (2 * $el <= $r + $numErasures - 1) {
330
+ $el = $r + $numErasures - $el;
331
+
332
+ for ($i = 0; $i <= $this->numRoots; $i++) {
333
+ $b[$i] = (
334
+ $lambda[$i] === 0
335
+ ? $this->blockSize
336
+ : $this->modNn($this->indexOf[$lambda[$i]] - $discrepancyR + $this->blockSize)
337
+ );
338
+ }
339
+ } else {
340
+ $tmp = $b->toArray();
341
+ array_unshift($tmp, $this->blockSize);
342
+ array_pop($tmp);
343
+ $b = SplFixedArray::fromArray($tmp, false);
344
+ }
345
+
346
+ $lambda = clone $t;
347
+ }
348
+ }
349
+
350
+ // Convert lambda to index form and compute deg(lambda(x))
351
+ $degLambda = 0;
352
+
353
+ for ($i = 0; $i <= $this->numRoots; $i++) {
354
+ $lambda[$i] = $this->indexOf[$lambda[$i]];
355
+
356
+ if ($lambda[$i] !== $this->blockSize) {
357
+ $degLambda = $i;
358
+ }
359
+ }
360
+
361
+ // Find roots of the error+erasure locator polynomial by Chien search.
362
+ $reg = clone $lambda;
363
+ $reg[0] = 0;
364
+ $count = 0;
365
+
366
+ for ($i = 1, $k = $this->iPrimitive - 1; $i <= $this->blockSize; $i++, $k = $this->modNn($k + $this->iPrimitive)) {
367
+ $q = 1;
368
+
369
+ for ($j = $degLambda; $j > 0; $j--) {
370
+ if ($reg[$j] !== $this->blockSize) {
371
+ $reg[$j] = $this->modNn($reg[$j] + $j);
372
+ $q ^= $this->alphaTo[$reg[$j]];
373
+ }
374
+ }
375
+
376
+ if ($q !== 0) {
377
+ // Not a root
378
+ continue;
379
+ }
380
+
381
+ // Store root (index-form) and error location number
382
+ $root[$count] = $i;
383
+ $loc[$count] = $k;
384
+
385
+ if (++$count === $degLambda) {
386
+ break;
387
+ }
388
+ }
389
+
390
+ if ($degLambda !== $count) {
391
+ // deg(lambda) unequal to number of roots: uncorreactable error
392
+ // detected
393
+ return null;
394
+ }
395
+
396
+ // Compute err+eras evaluate poly omega(x) = s(x)*lambda(x) (modulo
397
+ // x**numRoots). In index form. Also find deg(omega).
398
+ $degOmega = $degLambda - 1;
399
+
400
+ for ($i = 0; $i <= $degOmega; $i++) {
401
+ $tmp = 0;
402
+
403
+ for ($j = $i; $j >= 0; $j--) {
404
+ if ($syndromes[$i - $j] !== $this->blockSize && $lambda[$j] !== $this->blockSize) {
405
+ $tmp ^= $this->alphaTo[$this->modNn($syndromes[$i - $j] + $lambda[$j])];
406
+ }
407
+ }
408
+
409
+ $omega[$i] = $this->indexOf[$tmp];
410
+ }
411
+
412
+ // Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
413
+ // inv(X(l))**(firstRoot-1) and den = lambda_pr(inv(X(l))) all in poly
414
+ // form.
415
+ for ($j = $count - 1; $j >= 0; $j--) {
416
+ $num1 = 0;
417
+
418
+ for ($i = $degOmega; $i >= 0; $i--) {
419
+ if ($omega[$i] !== $this->blockSize) {
420
+ $num1 ^= $this->alphaTo[$this->modNn($omega[$i] + $i * $root[$j])];
421
+ }
422
+ }
423
+
424
+ $num2 = $this->alphaTo[$this->modNn($root[$j] * ($this->firstRoot - 1) + $this->blockSize)];
425
+ $den = 0;
426
+
427
+ // lambda[i+1] for i even is the formal derivativelambda_pr of
428
+ // lambda[i]
429
+ for ($i = min($degLambda, $this->numRoots - 1) & ~1; $i >= 0; $i -= 2) {
430
+ if ($lambda[$i + 1] !== $this->blockSize) {
431
+ $den ^= $this->alphaTo[$this->modNn($lambda[$i + 1] + $i * $root[$j])];
432
+ }
433
+ }
434
+
435
+ // Apply error to data
436
+ if ($num1 !== 0 && $loc[$j] >= $this->padding) {
437
+ $data[$loc[$j] - $this->padding] = $data[$loc[$j] - $this->padding] ^ (
438
+ $this->alphaTo[
439
+ $this->modNn(
440
+ $this->indexOf[$num1] + $this->indexOf[$num2] + $this->blockSize - $this->indexOf[$den]
441
+ )
442
+ ]
443
+ );
444
+ }
445
+ }
446
+
447
+ if ($erasures !== null) {
448
+ if (count($erasures) < $count) {
449
+ $erasures->setSize($count);
450
+ }
451
+
452
+ for ($i = 0; $i < $count; $i++) {
453
+ $erasures[$i] = $loc[$i];
454
+ }
455
+ }
456
+
457
+ return $count;
458
+ }
459
+
460
+ /**
461
+ * Computes $x % GF_SIZE, where GF_SIZE is 2**GF_BITS - 1, without a slow
462
+ * divide.
463
+ *
464
+ * @param itneger $x
465
+ * @return integer
466
+ */
467
+ protected function modNn($x)
468
+ {
469
+ while ($x >= $this->blockSize) {
470
+ $x -= $this->blockSize;
471
+ $x = ($x >> $this->symbolSize) + ($x & $this->blockSize);
472
+ }
473
+
474
+ return $x;
475
+ }
476
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Common/Version.php ADDED
@@ -0,0 +1,687 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Common;
11
+
12
+ use SplFixedArray;
13
+
14
+ /**
15
+ * Version representation.
16
+ */
17
+ class Version
18
+ {
19
+ /**
20
+ * Version decode information.
21
+ *
22
+ * @var array
23
+ */
24
+ protected static $versionDecodeInfo = array(
25
+ 0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d,
26
+ 0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9,
27
+ 0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75,
28
+ 0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64,
29
+ 0x27541, 0x28c69
30
+ );
31
+
32
+ /**
33
+ * Cached version instances.
34
+ *
35
+ * @var array
36
+ */
37
+ protected static $versions = array();
38
+
39
+ /**
40
+ * Version number of this version.
41
+ *
42
+ * @var integer
43
+ */
44
+ protected $versionNumber;
45
+
46
+ /**
47
+ * Alignment pattern centers.
48
+ *
49
+ * @var SplFixedArray
50
+ */
51
+ protected $alignmentPatternCenters;
52
+
53
+ /**
54
+ * Error correction blocks.
55
+ *
56
+ * @var SplFixedArray
57
+ */
58
+ protected $errorCorrectionBlocks;
59
+
60
+ /**
61
+ * Total number of codewords.
62
+ *
63
+ * @var integer
64
+ */
65
+ protected $totalCodewords;
66
+
67
+ /**
68
+ * Creates a new version.
69
+ *
70
+ * @param integer $versionNumber
71
+ * @param SplFixedArray $alignmentPatternCenters
72
+ * @param SplFixedArray $ecBlocks
73
+ */
74
+ protected function __construct(
75
+ $versionNumber,
76
+ SplFixedArray $alignmentPatternCenters,
77
+ SplFixedArray $ecBlocks
78
+ ) {
79
+ $this->versionNumber = $versionNumber;
80
+ $this->alignmentPatternCenters = $alignmentPatternCenters;
81
+ $this->errorCorrectionBlocks = $ecBlocks;
82
+
83
+ $totalCodewords = 0;
84
+ $ecCodewords = $ecBlocks[0]->getEcCodewordsPerBlock();
85
+
86
+ foreach ($ecBlocks[0]->getEcBlocks() as $ecBlock) {
87
+ $totalCodewords += $ecBlock->getCount() * ($ecBlock->getDataCodewords() + $ecCodewords);
88
+ }
89
+
90
+ $this->totalCodewords = $totalCodewords;
91
+ }
92
+
93
+ /**
94
+ * Gets the version number.
95
+ *
96
+ * @return integer
97
+ */
98
+ public function getVersionNumber()
99
+ {
100
+ return $this->versionNumber;
101
+ }
102
+
103
+ /**
104
+ * Gets the alignment pattern centers.
105
+ *
106
+ * @return SplFixedArray
107
+ */
108
+ public function getAlignmentPatternCenters()
109
+ {
110
+ return $this->alignmentPatternCenters;
111
+ }
112
+
113
+ /**
114
+ * Gets the total number of codewords.
115
+ *
116
+ * @return integer
117
+ */
118
+ public function getTotalCodewords()
119
+ {
120
+ return $this->totalCodewords;
121
+ }
122
+
123
+ /**
124
+ * Gets the dimension for the current version.
125
+ *
126
+ * @return integer
127
+ */
128
+ public function getDimensionForVersion()
129
+ {
130
+ return 17 + 4 * $this->versionNumber;
131
+ }
132
+
133
+ /**
134
+ * Gets the number of EC blocks for a specific EC level.
135
+ *
136
+ * @param ErrorCorrectionLevel $ecLevel
137
+ * @return integer
138
+ */
139
+ public function getEcBlocksForLevel(ErrorCorrectionLevel $ecLevel)
140
+ {
141
+ return $this->errorCorrectionBlocks[$ecLevel->getOrdinal()];
142
+ }
143
+
144
+ /**
145
+ * Gets a provisional version number for a specific dimension.
146
+ *
147
+ * @param integer $dimension
148
+ * @return Version
149
+ * @throws Exception\InvalidArgumentException
150
+ */
151
+ public static function getProvisionalVersionForDimension($dimension)
152
+ {
153
+ if ($dimension % 4 !== 1) {
154
+ throw new Exception\InvalidArgumentException('Dimension is not 1 mod 4');
155
+ }
156
+
157
+ return self::getVersionForNumber(($dimension - 17) >> 2);
158
+ }
159
+
160
+ /**
161
+ * Gets a version instance for a specific version number.
162
+ *
163
+ * @param integer $versionNumber
164
+ * @return Version
165
+ * @throws Exception\InvalidArgumentException
166
+ */
167
+ public static function getVersionForNumber($versionNumber)
168
+ {
169
+ if ($versionNumber < 1 || $versionNumber > 40) {
170
+ throw new Exception\InvalidArgumentException('Version number must be between 1 and 40');
171
+ }
172
+
173
+ if (!isset(self::$versions[$versionNumber])) {
174
+ self::buildVersion($versionNumber);
175
+ }
176
+
177
+ return self::$versions[$versionNumber - 1];
178
+ }
179
+
180
+ /**
181
+ * Decodes version information from an integer and returns the version.
182
+ *
183
+ * @param integer $versionBits
184
+ * @return Version|null
185
+ */
186
+ public static function decodeVersionInformation($versionBits)
187
+ {
188
+ $bestDifference = PHP_INT_MAX;
189
+ $bestVersion = 0;
190
+
191
+ foreach (self::$versionDecodeInfo as $i => $targetVersion) {
192
+ if ($targetVersion === $versionBits) {
193
+ return self::getVersionForNumber($i + 7);
194
+ }
195
+
196
+ $bitsDifference = FormatInformation::numBitsDiffering($versionBits, $targetVersion);
197
+
198
+ if ($bitsDifference < $bestDifference) {
199
+ $bestVersion = $i + 7;
200
+ $bestDifference = $bitsDifference;
201
+ }
202
+ }
203
+
204
+ if ($bestDifference <= 3) {
205
+ return self::getVersionForNumber($bestVersion);
206
+ }
207
+
208
+ return null;
209
+ }
210
+
211
+ /**
212
+ * Builds the function pattern for the current version.
213
+ *
214
+ * @return BitMatrix
215
+ */
216
+ public function buildFunctionPattern()
217
+ {
218
+ $dimension = $this->getDimensionForVersion();
219
+ $bitMatrix = new BitMatrix($dimension);
220
+
221
+ // Top left finder pattern + separator + format
222
+ $bitMatrix->setRegion(0, 0, 9, 9);
223
+ // Top right finder pattern + separator + format
224
+ $bitMatrix->setRegion($dimension - 8, 0, 8, 9);
225
+ // Bottom left finder pattern + separator + format
226
+ $bitMatrix->setRegion(0, $dimension - 8, 9, 8);
227
+
228
+ // Alignment patterns
229
+ $max = count($this->alignmentPatternCenters);
230
+
231
+ for ($x = 0; $x < $max; $x++) {
232
+ $i = $this->alignmentPatternCenters[$x] - 2;
233
+
234
+ for ($y = 0; $y < $max; $y++) {
235
+ if (($x === 0 && ($y === 0 || $y === $max - 1)) || ($x === $max - 1 && $y === 0)) {
236
+ // No alignment patterns near the three finder paterns
237
+ continue;
238
+ }
239
+
240
+ $bitMatrix->setRegion($this->alignmentPatternCenters[$y] - 2, $i, 5, 5);
241
+ }
242
+ }
243
+
244
+ // Vertical timing pattern
245
+ $bitMatrix->setRegion(6, 9, 1, $dimension - 17);
246
+ // Horizontal timing pattern
247
+ $bitMatrix->setRegion(9, 6, $dimension - 17, 1);
248
+
249
+ if ($this->versionNumber > 6) {
250
+ // Version info, top right
251
+ $bitMatrix->setRegion($dimension - 11, 0, 3, 6);
252
+ // Version info, bottom left
253
+ $bitMatrix->setRegion(0, $dimension - 11, 6, 3);
254
+ }
255
+
256
+ return $bitMatrix;
257
+ }
258
+
259
+ /**
260
+ * Returns a string representation for the version.
261
+ *
262
+ * @return string
263
+ */
264
+ public function __toString()
265
+ {
266
+ return (string) $this->versionNumber;
267
+ }
268
+
269
+ /**
270
+ * Build and cache a specific version.
271
+ *
272
+ * See ISO 18004:2006 6.5.1 Table 9.
273
+ *
274
+ * @param integer $versionNumber
275
+ * @return void
276
+ */
277
+ protected static function buildVersion($versionNumber)
278
+ {
279
+ switch ($versionNumber) {
280
+ case 1:
281
+ $patterns = array();
282
+ $ecBlocks = array(
283
+ new EcBlocks(7, new EcBlock(1, 19)),
284
+ new EcBlocks(10, new EcBlock(1, 16)),
285
+ new EcBlocks(13, new EcBlock(1, 13)),
286
+ new EcBlocks(17, new EcBlock(1, 9)),
287
+ );
288
+ break;
289
+
290
+ case 2:
291
+ $patterns = array(6, 18);
292
+ $ecBlocks = array(
293
+ new EcBlocks(10, new EcBlock(1, 34)),
294
+ new EcBlocks(16, new EcBlock(1, 28)),
295
+ new EcBlocks(22, new EcBlock(1, 22)),
296
+ new EcBlocks(28, new EcBlock(1, 16)),
297
+ );
298
+ break;
299
+
300
+ case 3:
301
+ $patterns = array(6, 22);
302
+ $ecBlocks = array(
303
+ new EcBlocks(15, new EcBlock(1, 55)),
304
+ new EcBlocks(26, new EcBlock(1, 44)),
305
+ new EcBlocks(18, new EcBlock(2, 17)),
306
+ new EcBlocks(22, new EcBlock(2, 13)),
307
+ );
308
+ break;
309
+
310
+ case 4:
311
+ $patterns = array(6, 26);
312
+ $ecBlocks = array(
313
+ new EcBlocks(20, new EcBlock(1, 80)),
314
+ new EcBlocks(18, new EcBlock(2, 32)),
315
+ new EcBlocks(26, new EcBlock(3, 24)),
316
+ new EcBlocks(16, new EcBlock(4, 9)),
317
+ );
318
+ break;
319
+
320
+ case 5:
321
+ $patterns = array(6, 30);
322
+ $ecBlocks = array(
323
+ new EcBlocks(26, new EcBlock(1, 108)),
324
+ new EcBlocks(24, new EcBlock(2, 43)),
325
+ new EcBlocks(18, new EcBlock(2, 15), new EcBlock(2, 16)),
326
+ new EcBlocks(22, new EcBlock(2, 11), new EcBlock(2, 12)),
327
+ );
328
+ break;
329
+
330
+ case 6:
331
+ $patterns = array(6, 34);
332
+ $ecBlocks = array(
333
+ new EcBlocks(18, new EcBlock(2, 68)),
334
+ new EcBlocks(16, new EcBlock(4, 27)),
335
+ new EcBlocks(24, new EcBlock(4, 19)),
336
+ new EcBlocks(28, new EcBlock(4, 15)),
337
+ );
338
+ break;
339
+
340
+ case 7:
341
+ $patterns = array(6, 22, 38);
342
+ $ecBlocks = array(
343
+ new EcBlocks(20, new EcBlock(2, 78)),
344
+ new EcBlocks(18, new EcBlock(4, 31)),
345
+ new EcBlocks(18, new EcBlock(2, 14), new EcBlock(4, 15)),
346
+ new EcBlocks(26, new EcBlock(4, 13), new EcBlock(1, 14)),
347
+ );
348
+ break;
349
+
350
+ case 8:
351
+ $patterns = array(6, 24, 42);
352
+ $ecBlocks = array(
353
+ new EcBlocks(24, new EcBlock(2, 97)),
354
+ new EcBlocks(22, new EcBlock(2, 38), new EcBlock(2, 39)),
355
+ new EcBlocks(22, new EcBlock(4, 18), new EcBlock(2, 19)),
356
+ new EcBlocks(26, new EcBlock(4, 14), new EcBlock(2, 15)),
357
+ );
358
+ break;
359
+
360
+ case 9:
361
+ $patterns = array(6, 26, 46);
362
+ $ecBlocks = array(
363
+ new EcBlocks(30, new EcBlock(2, 116)),
364
+ new EcBlocks(22, new EcBlock(3, 36), new EcBlock(2, 37)),
365
+ new EcBlocks(20, new EcBlock(4, 16), new EcBlock(4, 17)),
366
+ new EcBlocks(24, new EcBlock(4, 12), new EcBlock(4, 13)),
367
+ );
368
+ break;
369
+
370
+ case 10:
371
+ $patterns = array(6, 28, 50);
372
+ $ecBlocks = array(
373
+ new EcBlocks(18, new EcBlock(2, 68), new EcBlock(2, 69)),
374
+ new EcBlocks(26, new EcBlock(4, 43), new EcBlock(1, 44)),
375
+ new EcBlocks(24, new EcBlock(6, 19), new EcBlock(2, 20)),
376
+ new EcBlocks(28, new EcBlock(6, 15), new EcBlock(2, 16)),
377
+ );
378
+ break;
379
+
380
+ case 11:
381
+ $patterns = array(6, 30, 54);
382
+ $ecBlocks = array(
383
+ new EcBlocks(20, new EcBlock(4, 81)),
384
+ new EcBlocks(30, new EcBlock(1, 50), new EcBlock(4, 51)),
385
+ new EcBlocks(28, new EcBlock(4, 22), new EcBlock(4, 23)),
386
+ new EcBlocks(24, new EcBlock(3, 12), new EcBlock(8, 13)),
387
+ );
388
+ break;
389
+
390
+ case 12:
391
+ $patterns = array(6, 32, 58);
392
+ $ecBlocks = array(
393
+ new EcBlocks(24, new EcBlock(2, 92), new EcBlock(2, 93)),
394
+ new EcBlocks(22, new EcBlock(6, 36), new EcBlock(2, 37)),
395
+ new EcBlocks(26, new EcBlock(4, 20), new EcBlock(6, 21)),
396
+ new EcBlocks(28, new EcBlock(7, 14), new EcBlock(4, 15)),
397
+ );
398
+ break;
399
+
400
+ case 13:
401
+ $patterns = array(6, 34, 62);
402
+ $ecBlocks = array(
403
+ new EcBlocks(26, new EcBlock(4, 107)),
404
+ new EcBlocks(22, new EcBlock(8, 37), new EcBlock(1, 38)),
405
+ new EcBlocks(24, new EcBlock(8, 20), new EcBlock(4, 21)),
406
+ new EcBlocks(22, new EcBlock(12, 11), new EcBlock(4, 12)),
407
+ );
408
+ break;
409
+
410
+ case 14:
411
+ $patterns = array(6, 26, 46, 66);
412
+ $ecBlocks = array(
413
+ new EcBlocks(30, new EcBlock(3, 115), new EcBlock(1, 116)),
414
+ new EcBlocks(24, new EcBlock(4, 40), new EcBlock(5, 41)),
415
+ new EcBlocks(20, new EcBlock(11, 16), new EcBlock(5, 17)),
416
+ new EcBlocks(24, new EcBlock(11, 12), new EcBlock(5, 13)),
417
+ );
418
+ break;
419
+
420
+ case 15:
421
+ $patterns = array(6, 26, 48, 70);
422
+ $ecBlocks = array(
423
+ new EcBlocks(22, new EcBlock(5, 87), new EcBlock(1, 88)),
424
+ new EcBlocks(24, new EcBlock(5, 41), new EcBlock(5, 42)),
425
+ new EcBlocks(30, new EcBlock(5, 24), new EcBlock(7, 25)),
426
+ new EcBlocks(24, new EcBlock(11, 12), new EcBlock(7, 13)),
427
+ );
428
+ break;
429
+
430
+ case 16:
431
+ $patterns = array(6, 26, 50, 74);
432
+ $ecBlocks = array(
433
+ new EcBlocks(24, new EcBlock(5, 98), new EcBlock(1, 99)),
434
+ new EcBlocks(28, new EcBlock(7, 45), new EcBlock(3, 46)),
435
+ new EcBlocks(24, new EcBlock(15, 19), new EcBlock(2, 20)),
436
+ new EcBlocks(30, new EcBlock(3, 15), new EcBlock(13, 16)),
437
+ );
438
+ break;
439
+
440
+ case 17:
441
+ $patterns = array(6, 30, 54, 78);
442
+ $ecBlocks = array(
443
+ new EcBlocks(28, new EcBlock(1, 107), new EcBlock(5, 108)),
444
+ new EcBlocks(28, new EcBlock(10, 46), new EcBlock(1, 47)),
445
+ new EcBlocks(28, new EcBlock(1, 22), new EcBlock(15, 23)),
446
+ new EcBlocks(28, new EcBlock(2, 14), new EcBlock(17, 15)),
447
+ );
448
+ break;
449
+
450
+ case 18:
451
+ $patterns = array(6, 30, 56, 82);
452
+ $ecBlocks = array(
453
+ new EcBlocks(30, new EcBlock(5, 120), new EcBlock(1, 121)),
454
+ new EcBlocks(26, new EcBlock(9, 43), new EcBlock(4, 44)),
455
+ new EcBlocks(28, new EcBlock(17, 22), new EcBlock(1, 23)),
456
+ new EcBlocks(28, new EcBlock(2, 14), new EcBlock(19, 15)),
457
+ );
458
+ break;
459
+
460
+ case 19:
461
+ $patterns = array(6, 30, 58, 86);
462
+ $ecBlocks = array(
463
+ new EcBlocks(28, new EcBlock(3, 113), new EcBlock(4, 114)),
464
+ new EcBlocks(26, new EcBlock(3, 44), new EcBlock(11, 45)),
465
+ new EcBlocks(26, new EcBlock(17, 21), new EcBlock(4, 22)),
466
+ new EcBlocks(26, new EcBlock(9, 13), new EcBlock(16, 14)),
467
+ );
468
+ break;
469
+
470
+ case 20:
471
+ $patterns = array(6, 34, 62, 90);
472
+ $ecBlocks = array(
473
+ new EcBlocks(28, new EcBlock(3, 107), new EcBlock(5, 108)),
474
+ new EcBlocks(26, new EcBlock(3, 41), new EcBlock(13, 42)),
475
+ new EcBlocks(30, new EcBlock(15, 24), new EcBlock(5, 25)),
476
+ new EcBlocks(28, new EcBlock(15, 15), new EcBlock(10, 16)),
477
+ );
478
+ break;
479
+
480
+ case 21:
481
+ $patterns = array(6, 28, 50, 72, 94);
482
+ $ecBlocks = array(
483
+ new EcBlocks(28, new EcBlock(4, 116), new EcBlock(4, 117)),
484
+ new EcBlocks(26, new EcBlock(17, 42)),
485
+ new EcBlocks(28, new EcBlock(17, 22), new EcBlock(6, 23)),
486
+ new EcBlocks(30, new EcBlock(19, 16), new EcBlock(6, 17)),
487
+ );
488
+ break;
489
+
490
+ case 22:
491
+ $patterns = array(6, 26, 50, 74, 98);
492
+ $ecBlocks = array(
493
+ new EcBlocks(28, new EcBlock(2, 111), new EcBlock(7, 112)),
494
+ new EcBlocks(28, new EcBlock(17, 46)),
495
+ new EcBlocks(30, new EcBlock(7, 24), new EcBlock(16, 25)),
496
+ new EcBlocks(24, new EcBlock(34, 13)),
497
+ );
498
+ break;
499
+
500
+ case 23:
501
+ $patterns = array(6, 30, 54, 78, 102);
502
+ $ecBlocks = array(
503
+ new EcBlocks(30, new EcBlock(4, 121), new EcBlock(5, 122)),
504
+ new EcBlocks(28, new EcBlock(4, 47), new EcBlock(14, 48)),
505
+ new EcBlocks(30, new EcBlock(11, 24), new EcBlock(14, 25)),
506
+ new EcBlocks(30, new EcBlock(16, 15), new EcBlock(14, 16)),
507
+ );
508
+ break;
509
+
510
+ case 24:
511
+ $patterns = array(6, 28, 54, 80, 106);
512
+ $ecBlocks = array(
513
+ new EcBlocks(30, new EcBlock(6, 117), new EcBlock(4, 118)),
514
+ new EcBlocks(28, new EcBlock(6, 45), new EcBlock(14, 46)),
515
+ new EcBlocks(30, new EcBlock(11, 24), new EcBlock(16, 25)),
516
+ new EcBlocks(30, new EcBlock(30, 16), new EcBlock(2, 17)),
517
+ );
518
+ break;
519
+
520
+ case 25:
521
+ $patterns = array(6, 32, 58, 84, 110);
522
+ $ecBlocks = array(
523
+ new EcBlocks(26, new EcBlock(8, 106), new EcBlock(4, 107)),
524
+ new EcBlocks(28, new EcBlock(8, 47), new EcBlock(13, 48)),
525
+ new EcBlocks(30, new EcBlock(7, 24), new EcBlock(22, 25)),
526
+ new EcBlocks(30, new EcBlock(22, 15), new EcBlock(13, 16)),
527
+ );
528
+ break;
529
+
530
+ case 26:
531
+ $patterns = array(6, 30, 58, 86, 114);
532
+ $ecBlocks = array(
533
+ new EcBlocks(28, new EcBlock(10, 114), new EcBlock(2, 115)),
534
+ new EcBlocks(28, new EcBlock(19, 46), new EcBlock(4, 47)),
535
+ new EcBlocks(28, new EcBlock(28, 22), new EcBlock(6, 23)),
536
+ new EcBlocks(30, new EcBlock(33, 16), new EcBlock(4, 17)),
537
+ );
538
+ break;
539
+
540
+ case 27:
541
+ $patterns = array(6, 34, 62, 90, 118);
542
+ $ecBlocks = array(
543
+ new EcBlocks(30, new EcBlock(8, 122), new EcBlock(4, 123)),
544
+ new EcBlocks(28, new EcBlock(22, 45), new EcBlock(3, 46)),
545
+ new EcBlocks(30, new EcBlock(8, 23), new EcBlock(26, 24)),
546
+ new EcBlocks(30, new EcBlock(12, 15), new EcBlock(28, 16)),
547
+ );
548
+ break;
549
+
550
+ case 28:
551
+ $patterns = array(6, 26, 50, 74, 98, 122);
552
+ $ecBlocks = array(
553
+ new EcBlocks(30, new EcBlock(3, 117), new EcBlock(10, 118)),
554
+ new EcBlocks(28, new EcBlock(3, 45), new EcBlock(23, 46)),
555
+ new EcBlocks(30, new EcBlock(4, 24), new EcBlock(31, 25)),
556
+ new EcBlocks(30, new EcBlock(11, 15), new EcBlock(31, 16)),
557
+ );
558
+ break;
559
+
560
+ case 29:
561
+ $patterns = array(6, 30, 54, 78, 102, 126);
562
+ $ecBlocks = array(
563
+ new EcBlocks(30, new EcBlock(7, 116), new EcBlock(7, 117)),
564
+ new EcBlocks(28, new EcBlock(21, 45), new EcBlock(7, 46)),
565
+ new EcBlocks(30, new EcBlock(1, 23), new EcBlock(37, 24)),
566
+ new EcBlocks(30, new EcBlock(19, 15), new EcBlock(26, 16)),
567
+ );
568
+ break;
569
+
570
+ case 30:
571
+ $patterns = array(6, 26, 52, 78, 104, 130);
572
+ $ecBlocks = array(
573
+ new EcBlocks(30, new EcBlock(5, 115), new EcBlock(10, 116)),
574
+ new EcBlocks(28, new EcBlock(19, 47), new EcBlock(10, 48)),
575
+ new EcBlocks(30, new EcBlock(15, 24), new EcBlock(25, 25)),
576
+ new EcBlocks(30, new EcBlock(23, 15), new EcBlock(25, 16)),
577
+ );
578
+ break;
579
+
580
+ case 31:
581
+ $patterns = array(6, 30, 56, 82, 108, 134);
582
+ $ecBlocks = array(
583
+ new EcBlocks(30, new EcBlock(13, 115), new EcBlock(3, 116)),
584
+ new EcBlocks(28, new EcBlock(2, 46), new EcBlock(29, 47)),
585
+ new EcBlocks(30, new EcBlock(42, 24), new EcBlock(1, 25)),
586
+ new EcBlocks(30, new EcBlock(23, 15), new EcBlock(28, 16)),
587
+ );
588
+ break;
589
+
590
+ case 32:
591
+ $patterns = array(6, 34, 60, 86, 112, 138);
592
+ $ecBlocks = array(
593
+ new EcBlocks(30, new EcBlock(17, 115)),
594
+ new EcBlocks(28, new EcBlock(10, 46), new EcBlock(23, 47)),
595
+ new EcBlocks(30, new EcBlock(10, 24), new EcBlock(35, 25)),
596
+ new EcBlocks(30, new EcBlock(19, 15), new EcBlock(35, 16)),
597
+ );
598
+ break;
599
+
600
+ case 33:
601
+ $patterns = array(6, 30, 58, 86, 114, 142);
602
+ $ecBlocks = array(
603
+ new EcBlocks(30, new EcBlock(17, 115), new EcBlock(1, 116)),
604
+ new EcBlocks(28, new EcBlock(14, 46), new EcBlock(21, 47)),
605
+ new EcBlocks(30, new EcBlock(29, 24), new EcBlock(19, 25)),
606
+ new EcBlocks(30, new EcBlock(11, 15), new EcBlock(46, 16)),
607
+ );
608
+ break;
609
+
610
+ case 34:
611
+ $patterns = array(6, 34, 62, 90, 118, 146);
612
+ $ecBlocks = array(
613
+ new EcBlocks(30, new EcBlock(13, 115), new EcBlock(6, 116)),
614
+ new EcBlocks(28, new EcBlock(14, 46), new EcBlock(23, 47)),
615
+ new EcBlocks(30, new EcBlock(44, 24), new EcBlock(7, 25)),
616
+ new EcBlocks(30, new EcBlock(59, 16), new EcBlock(1, 17)),
617
+ );
618
+ break;
619
+
620
+ case 35:
621
+ $patterns = array(6, 30, 54, 78, 102, 126, 150);
622
+ $ecBlocks = array(
623
+ new EcBlocks(30, new EcBlock(12, 121), new EcBlock(7, 122)),
624
+ new EcBlocks(28, new EcBlock(12, 47), new EcBlock(26, 48)),
625
+ new EcBlocks(30, new EcBlock(39, 24), new EcBlock(14, 25)),
626
+ new EcBlocks(30, new EcBlock(22, 15), new EcBlock(41, 16)),
627
+ );
628
+ break;
629
+
630
+ case 36:
631
+ $patterns = array(6, 24, 50, 76, 102, 128, 154);
632
+ $ecBlocks = array(
633
+ new EcBlocks(30, new EcBlock(6, 121), new EcBlock(14, 122)),
634
+ new EcBlocks(28, new EcBlock(6, 47), new EcBlock(34, 48)),
635
+ new EcBlocks(30, new EcBlock(46, 24), new EcBlock(10, 25)),
636
+ new EcBlocks(30, new EcBlock(2, 15), new EcBlock(64, 16)),
637
+ );
638
+ break;
639
+
640
+ case 37:
641
+ $patterns = array(6, 28, 54, 80, 106, 132, 158);
642
+ $ecBlocks = array(
643
+ new EcBlocks(30, new EcBlock(17, 122), new EcBlock(4, 123)),
644
+ new EcBlocks(28, new EcBlock(29, 46), new EcBlock(14, 47)),
645
+ new EcBlocks(30, new EcBlock(49, 24), new EcBlock(10, 25)),
646
+ new EcBlocks(30, new EcBlock(24, 15), new EcBlock(46, 16)),
647
+ );
648
+ break;
649
+
650
+ case 38:
651
+ $patterns = array(6, 32, 58, 84, 110, 136, 162);
652
+ $ecBlocks = array(
653
+ new EcBlocks(30, new EcBlock(4, 122), new EcBlock(18, 123)),
654
+ new EcBlocks(28, new EcBlock(13, 46), new EcBlock(32, 47)),
655
+ new EcBlocks(30, new EcBlock(48, 24), new EcBlock(14, 25)),
656
+ new EcBlocks(30, new EcBlock(42, 15), new EcBlock(32, 16)),
657
+ );
658
+ break;
659
+
660
+ case 39:
661
+ $patterns = array(6, 26, 54, 82, 110, 138, 166);
662
+ $ecBlocks = array(
663
+ new EcBlocks(30, new EcBlock(20, 117), new EcBlock(4, 118)),
664
+ new EcBlocks(28, new EcBlock(40, 47), new EcBlock(7, 48)),
665
+ new EcBlocks(30, new EcBlock(43, 24), new EcBlock(22, 25)),
666
+ new EcBlocks(30, new EcBlock(10, 15), new EcBlock(67, 16)),
667
+ );
668
+ break;
669
+
670
+ case 40:
671
+ $patterns = array(6, 30, 58, 86, 114, 142, 170);
672
+ $ecBlocks = array(
673
+ new EcBlocks(30, new EcBlock(19, 118), new EcBlock(6, 119)),
674
+ new EcBlocks(28, new EcBlock(18, 47), new EcBlock(31, 48)),
675
+ new EcBlocks(30, new EcBlock(34, 24), new EcBlock(34, 25)),
676
+ new EcBlocks(30, new EcBlock(20, 15), new EcBlock(61, 16)),
677
+ );
678
+ break;
679
+ }
680
+
681
+ self::$versions[$versionNumber - 1] = new self(
682
+ $versionNumber,
683
+ SplFixedArray::fromArray($patterns, false),
684
+ SplFixedArray::fromArray($ecBlocks, false)
685
+ );
686
+ }
687
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/BlockPair.php ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Encoder;
11
+
12
+ use SplFixedArray;
13
+
14
+ /**
15
+ * Block pair.
16
+ */
17
+ class BlockPair
18
+ {
19
+ /**
20
+ * Data bytes in the block.
21
+ *
22
+ * @var SplFixedArray
23
+ */
24
+ protected $dataBytes;
25
+
26
+ /**
27
+ * Error correction bytes in the block.
28
+ *
29
+ * @var SplFixedArray
30
+ */
31
+ protected $errorCorrectionBytes;
32
+
33
+ /**
34
+ * Creates a new block pair.
35
+ *
36
+ * @param SplFixedArray $data
37
+ * @param SplFixedArray $errorCorrection
38
+ */
39
+ public function __construct(SplFixedArray $data, SplFixedArray $errorCorrection)
40
+ {
41
+ $this->dataBytes = $data;
42
+ $this->errorCorrectionBytes = $errorCorrection;
43
+ }
44
+
45
+ /**
46
+ * Gets the data bytes.
47
+ *
48
+ * @return SplFixedArray
49
+ */
50
+ public function getDataBytes()
51
+ {
52
+ return $this->dataBytes;
53
+ }
54
+
55
+ /**
56
+ * Gets the error correction bytes.
57
+ *
58
+ * @return SplFixedArray
59
+ */
60
+ public function getErrorCorrectionBytes()
61
+ {
62
+ return $this->errorCorrectionBytes;
63
+ }
64
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/ByteMatrix.php ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Encoder;
11
+
12
+ use SplFixedArray;
13
+
14
+ /**
15
+ * Byte matrix.
16
+ */
17
+ class ByteMatrix
18
+ {
19
+ /**
20
+ * Bytes in the matrix, represented as array.
21
+ *
22
+ * @var SplFixedArray
23
+ */
24
+ protected $bytes;
25
+
26
+ /**
27
+ * Width of the matrix.
28
+ *
29
+ * @var integer
30
+ */
31
+ protected $width;
32
+
33
+ /**
34
+ * Height of the matrix.
35
+ *
36
+ * @var integer
37
+ */
38
+ protected $height;
39
+
40
+ /**
41
+ * Creates a new byte matrix.
42
+ *
43
+ * @param integer $width
44
+ * @param integer $height
45
+ */
46
+ public function __construct($width, $height)
47
+ {
48
+ $this->height = $height;
49
+ $this->width = $width;
50
+ $this->bytes = new SplFixedArray($height);
51
+
52
+ for ($y = 0; $y < $height; $y++) {
53
+ $this->bytes[$y] = new SplFixedArray($width);
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Gets the width of the matrix.
59
+ *
60
+ * @return integer
61
+ */
62
+ public function getWidth()
63
+ {
64
+ return $this->width;
65
+ }
66
+
67
+ /**
68
+ * Gets the height of the matrix.
69
+ *
70
+ * @return integer
71
+ */
72
+ public function getHeight()
73
+ {
74
+ return $this->height;
75
+ }
76
+
77
+ /**
78
+ * Gets the internal representation of the matrix.
79
+ *
80
+ * @return SplFixedArray
81
+ */
82
+ public function getArray()
83
+ {
84
+ return $this->bytes;
85
+ }
86
+
87
+ /**
88
+ * Gets the byte for a specific position.
89
+ *
90
+ * @param integer $x
91
+ * @param integer $y
92
+ * @return integer
93
+ */
94
+ public function get($x, $y)
95
+ {
96
+ return $this->bytes[$y][$x];
97
+ }
98
+
99
+ /**
100
+ * Sets the byte for a specific position.
101
+ *
102
+ * @param integer $x
103
+ * @param integer $y
104
+ * @param integer $value
105
+ * @return void
106
+ */
107
+ public function set($x, $y, $value)
108
+ {
109
+ $this->bytes[$y][$x] = (int) $value;
110
+ }
111
+
112
+ /**
113
+ * Clears the matrix with a specific value.
114
+ *
115
+ * @param integer $value
116
+ * @return void
117
+ */
118
+ public function clear($value)
119
+ {
120
+ for ($y = 0; $y < $this->height; $y++) {
121
+ for ($x = 0; $x < $this->width; $x++) {
122
+ $this->bytes[$y][$x] = $value;
123
+ }
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Returns a string representation of the matrix.
129
+ *
130
+ * @return string
131
+ */
132
+ public function __toString()
133
+ {
134
+ $result = '';
135
+
136
+ for ($y = 0; $y < $this->height; $y++) {
137
+ for ($x = 0; $x < $this->width; $x++) {
138
+ switch ($this->bytes[$y][$x]) {
139
+ case 0:
140
+ $result .= ' 0';
141
+ break;
142
+
143
+ case 1:
144
+ $result .= ' 1';
145
+ break;
146
+
147
+ default:
148
+ $result .= ' ';
149
+ break;
150
+ }
151
+ }
152
+
153
+ $result .= "\n";
154
+ }
155
+
156
+ return $result;
157
+ }
158
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/Encoder.php ADDED
@@ -0,0 +1,687 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Encoder;
11
+
12
+ use BaconQrCode\Common\BitArray;
13
+ use BaconQrCode\Common\CharacterSetEci;
14
+ use BaconQrCode\Common\ErrorCorrectionLevel;
15
+ use BaconQrCode\Common\Mode;
16
+ use BaconQrCode\Common\ReedSolomonCodec;
17
+ use BaconQrCode\Common\Version;
18
+ use BaconQrCode\Exception;
19
+ use SplFixedArray;
20
+
21
+ /**
22
+ * Encoder.
23
+ */
24
+ class Encoder
25
+ {
26
+ /**
27
+ * Default byte encoding.
28
+ */
29
+ const DEFAULT_BYTE_MODE_ECODING = 'ISO-8859-1';
30
+
31
+ /**
32
+ * The original table is defined in the table 5 of JISX0510:2004 (p.19).
33
+ *
34
+ * @var array
35
+ */
36
+ protected static $alphanumericTable = array(
37
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x00-0x0f
38
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x10-0x1f
39
+ 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, // 0x20-0x2f
40
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, // 0x30-0x3f
41
+ -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x40-0x4f
42
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, // 0x50-0x5f
43
+ );
44
+
45
+ /**
46
+ * Codec cache.
47
+ *
48
+ * @var array
49
+ */
50
+ protected static $codecs = array();
51
+
52
+ /**
53
+ * Encodes "content" with the error correction level "ecLevel".
54
+ *
55
+ * @param string $content
56
+ * @param ErrorCorrectionLevel $ecLevel
57
+ * @param ? $hints
58
+ * @return QrCode
59
+ */
60
+ public static function encode($content, ErrorCorrectionLevel $ecLevel, $encoding = self::DEFAULT_BYTE_MODE_ECODING)
61
+ {
62
+ // Pick an encoding mode appropriate for the content. Note that this
63
+ // will not attempt to use multiple modes / segments even if that were
64
+ // more efficient. Would be nice.
65
+ $mode = self::chooseMode($content, $encoding);
66
+
67
+ // This will store the header information, like mode and length, as well
68
+ // as "header" segments like an ECI segment.
69
+ $headerBits = new BitArray();
70
+
71
+ // Append ECI segment if applicable
72
+ if ($mode->get() === Mode::BYTE && $encoding !== self::DEFAULT_BYTE_MODE_ECODING) {
73
+ $eci = CharacterSetEci::getCharacterSetEciByName($encoding);
74
+
75
+ if ($eci !== null) {
76
+ self::appendEci($eci, $headerBits);
77
+ }
78
+ }
79
+
80
+ // (With ECI in place,) Write the mode marker
81
+ self::appendModeInfo($mode, $headerBits);
82
+
83
+ // Collect data within the main segment, separately, to count its size
84
+ // if needed. Don't add it to main payload yet.
85
+ $dataBits = new BitArray();
86
+ self::appendBytes($content, $mode, $dataBits, $encoding);
87
+
88
+ // Hard part: need to know version to know how many bits length takes.
89
+ // But need to know how many bits it takes to know version. First we
90
+ // take a guess at version by assuming version will be the minimum, 1:
91
+ $provisionalBitsNeeded = $headerBits->getSize()
92
+ + $mode->getCharacterCountBits(Version::getVersionForNumber(1))
93
+ + $dataBits->getSize();
94
+ $provisionalVersion = self::chooseVersion($provisionalBitsNeeded, $ecLevel);
95
+
96
+ // Use that guess to calculate the right version. I am still not sure
97
+ // this works in 100% of cases.
98
+ $bitsNeeded = $headerBits->getSize()
99
+ + $mode->getCharacterCountBits($provisionalVersion)
100
+ + $dataBits->getSize();
101
+ $version = self::chooseVersion($bitsNeeded, $ecLevel);
102
+
103
+ $headerAndDataBits = new BitArray();
104
+ $headerAndDataBits->appendBitArray($headerBits);
105
+
106
+ // Find "length" of main segment and write it.
107
+ $numLetters = ($mode->get() === Mode::BYTE ? $dataBits->getSizeInBytes() : strlen($content));
108
+ self::appendLengthInfo($numLetters, $version, $mode, $headerAndDataBits);
109
+
110
+ // Put data together into the overall payload.
111
+ $headerAndDataBits->appendBitArray($dataBits);
112
+ $ecBlocks = $version->getEcBlocksForLevel($ecLevel);
113
+ $numDataBytes = $version->getTotalCodewords() - $ecBlocks->getTotalEcCodewords();
114
+
115
+ // Terminate the bits properly.
116
+ self::terminateBits($numDataBytes, $headerAndDataBits);
117
+
118
+ // Interleave data bits with error correction code.
119
+ $finalBits = self::interleaveWithEcBytes(
120
+ $headerAndDataBits,
121
+ $version->getTotalCodewords(),
122
+ $numDataBytes,
123
+ $ecBlocks->getNumBlocks()
124
+ );
125
+
126
+ $qrCode = new QrCode();
127
+ $qrCode->setErrorCorrectionLevel($ecLevel);
128
+ $qrCode->setMode($mode);
129
+ $qrCode->setVersion($version);
130
+
131
+ // Choose the mask pattern and set to "qrCode".
132
+ $dimension = $version->getDimensionForVersion();
133
+ $matrix = new ByteMatrix($dimension, $dimension);
134
+ $maskPattern = self::chooseMaskPattern($finalBits, $ecLevel, $version, $matrix);
135
+ $qrCode->setMaskPattern($maskPattern);
136
+
137
+ // Build the matrix and set it to "qrCode".
138
+ MatrixUtil::buildMatrix($finalBits, $ecLevel, $version, $maskPattern, $matrix);
139
+ $qrCode->setMatrix($matrix);
140
+
141
+ return $qrCode;
142
+ }
143
+
144
+ /**
145
+ * Gets the alphanumeric code for a byte.
146
+ *
147
+ * @param string|integer $code
148
+ * @return integer
149
+ */
150
+ protected static function getAlphanumericCode($code)
151
+ {
152
+ $code = (is_string($code) ? ord($code) : $code);
153
+
154
+ if (isset(self::$alphanumericTable[$code])) {
155
+ return self::$alphanumericTable[$code];
156
+ }
157
+
158
+ return -1;
159
+ }
160
+
161
+ /**
162
+ * Chooses the best mode for a given content.
163
+ *
164
+ * @param string $content
165
+ * @param string $encoding
166
+ * @return Mode
167
+ */
168
+ protected static function chooseMode($content, $encoding = null)
169
+ {
170
+ if (strcasecmp($encoding, 'SHIFT-JIS') === 0) {
171
+ return self::isOnlyDoubleByteKanji($content) ? new Mode(Mode::KANJI) : new Mode(Mode::BYTE);
172
+ }
173
+
174
+ $hasNumeric = false;
175
+ $hasAlphanumeric = false;
176
+ $contentLength = strlen($content);
177
+
178
+ for ($i = 0; $i < $contentLength; $i++) {
179
+ $char = $content[$i];
180
+
181
+ if (ctype_digit($char)) {
182
+ $hasNumeric = true;
183
+ } elseif (self::getAlphanumericCode($char) !== -1) {
184
+ $hasAlphanumeric = true;
185
+ } else {
186
+ return new Mode(Mode::BYTE);
187
+ }
188
+ }
189
+
190
+ if ($hasAlphanumeric) {
191
+ return new Mode(Mode::ALPHANUMERIC);
192
+ } elseif ($hasNumeric) {
193
+ return new Mode(Mode::NUMERIC);
194
+ }
195
+
196
+ return new Mode(Mode::BYTE);
197
+ }
198
+
199
+ /**
200
+ * Calculates the mask penalty for a matrix.
201
+ *
202
+ * @param ByteMatrix $matrix
203
+ * @return integer
204
+ */
205
+ protected static function calculateMaskPenalty(ByteMatrix $matrix)
206
+ {
207
+ return (
208
+ MaskUtil::applyMaskPenaltyRule1($matrix)
209
+ + MaskUtil::applyMaskPenaltyRule2($matrix)
210
+ + MaskUtil::applyMaskPenaltyRule3($matrix)
211
+ + MaskUtil::applyMaskPenaltyRule4($matrix)
212
+ );
213
+ }
214
+
215
+ /**
216
+ * Chooses the best mask pattern for a matrix.
217
+ *
218
+ * @param BitArray $bits
219
+ * @param ErrorCorrectionLevel $ecLevel
220
+ * @param Version $version
221
+ * @param ByteMatrix $matrix
222
+ * @return integer
223
+ */
224
+ protected static function chooseMaskPattern(
225
+ BitArray $bits,
226
+ ErrorCorrectionLevel $ecLevel,
227
+ Version $version,
228
+ ByteMatrix $matrix
229
+ ) {
230
+ $minPenality = PHP_INT_MAX;
231
+ $bestMaskPattern = -1;
232
+
233
+ for ($maskPattern = 0; $maskPattern < QrCode::NUM_MASK_PATTERNS; $maskPattern++) {
234
+ MatrixUtil::buildMatrix($bits, $ecLevel, $version, $maskPattern, $matrix);
235
+ $penalty = self::calculateMaskPenalty($matrix);
236
+
237
+ if ($penalty < $minPenality) {
238
+ $minPenality = $penalty;
239
+ $bestMaskPattern = $maskPattern;
240
+ }
241
+ }
242
+
243
+ return $bestMaskPattern;
244
+ }
245
+
246
+ /**
247
+ * Chooses the best version for the input.
248
+ *
249
+ * @param integer $numInputBits
250
+ * @param ErrorCorrectionLevel $ecLevel
251
+ * @return Version
252
+ * @throws Exception\WriterException
253
+ */
254
+ protected static function chooseVersion($numInputBits, ErrorCorrectionLevel $ecLevel)
255
+ {
256
+ for ($versionNum = 1; $versionNum <= 40; $versionNum++) {
257
+ $version = Version::getVersionForNumber($versionNum);
258
+ $numBytes = $version->getTotalCodewords();
259
+
260
+ $ecBlocks = $version->getEcBlocksForLevel($ecLevel);
261
+ $numEcBytes = $ecBlocks->getTotalEcCodewords();
262
+
263
+ $numDataBytes = $numBytes - $numEcBytes;
264
+ $totalInputBytes = intval(($numInputBits + 8) / 8);
265
+
266
+ if ($numDataBytes >= $totalInputBytes) {
267
+ return $version;
268
+ }
269
+ }
270
+
271
+ throw new Exception\WriterException('Data too big');
272
+ }
273
+
274
+ /**
275
+ * Terminates the bits in a bit array.
276
+ *
277
+ * @param integer $numDataBytes
278
+ * @param BitArray $bits
279
+ * @throws Exception\WriterException
280
+ */
281
+ protected static function terminateBits($numDataBytes, BitArray $bits)
282
+ {
283
+ $capacity = $numDataBytes << 3;
284
+
285
+ if ($bits->getSize() > $capacity) {
286
+ throw new Exception\WriterException('Data bits cannot fit in the QR code');
287
+ }
288
+
289
+ for ($i = 0; $i < 4 && $bits->getSize() < $capacity; $i++) {
290
+ $bits->appendBit(false);
291
+ }
292
+
293
+ $numBitsInLastByte = $bits->getSize() & 0x7;
294
+
295
+ if ($numBitsInLastByte > 0) {
296
+ for ($i = $numBitsInLastByte; $i < 8; $i++) {
297
+ $bits->appendBit(false);
298
+ }
299
+ }
300
+
301
+ $numPaddingBytes = $numDataBytes - $bits->getSizeInBytes();
302
+
303
+ for ($i = 0; $i < $numPaddingBytes; $i++) {
304
+ $bits->appendBits(($i & 0x1) === 0 ? 0xec : 0x11, 8);
305
+ }
306
+
307
+ if ($bits->getSize() !== $capacity) {
308
+ throw new Exception\WriterException('Bits size does not equal capacity');
309
+ }
310
+ }
311
+
312
+ /**
313
+ * Gets number of data- and EC bytes for a block ID.
314
+ *
315
+ * @param integer $numTotalBytes
316
+ * @param integer $numDataBytes
317
+ * @param integer $numRsBlocks
318
+ * @param integer $blockId
319
+ * @return array
320
+ * @throws Exception\WriterException
321
+ */
322
+ protected static function getNumDataBytesAndNumEcBytesForBlockId(
323
+ $numTotalBytes,
324
+ $numDataBytes,
325
+ $numRsBlocks,
326
+ $blockId
327
+ ) {
328
+ if ($blockId >= $numRsBlocks) {
329
+ throw new Exception\WriterException('Block ID too large');
330
+ }
331
+
332
+ $numRsBlocksInGroup2 = $numTotalBytes % $numRsBlocks;
333
+ $numRsBlocksInGroup1 = $numRsBlocks - $numRsBlocksInGroup2;
334
+ $numTotalBytesInGroup1 = intval($numTotalBytes / $numRsBlocks);
335
+ $numTotalBytesInGroup2 = $numTotalBytesInGroup1 + 1;
336
+ $numDataBytesInGroup1 = intval($numDataBytes / $numRsBlocks);
337
+ $numDataBytesInGroup2 = $numDataBytesInGroup1 + 1;
338
+ $numEcBytesInGroup1 = $numTotalBytesInGroup1 - $numDataBytesInGroup1;
339
+ $numEcBytesInGroup2 = $numTotalBytesInGroup2 - $numDataBytesInGroup2;
340
+
341
+ if ($numEcBytesInGroup1 !== $numEcBytesInGroup2) {
342
+ throw new Exception\WriterException('EC bytes mismatch');
343
+ }
344
+
345
+ if ($numRsBlocks !== $numRsBlocksInGroup1 + $numRsBlocksInGroup2) {
346
+ throw new Exception\WriterException('RS blocks mismatch');
347
+ }
348
+
349
+ if ($numTotalBytes !==
350
+ (($numDataBytesInGroup1 + $numEcBytesInGroup1) * $numRsBlocksInGroup1)
351
+ + (($numDataBytesInGroup2 + $numEcBytesInGroup2) * $numRsBlocksInGroup2)
352
+ ) {
353
+ throw new Exception\WriterException('Total bytes mismatch');
354
+ }
355
+
356
+ if ($blockId < $numRsBlocksInGroup1) {
357
+ return array($numDataBytesInGroup1, $numEcBytesInGroup1);
358
+ } else {
359
+ return array($numDataBytesInGroup2, $numEcBytesInGroup2);
360
+ }
361
+ }
362
+
363
+ /**
364
+ * Interleaves data with EC bytes.
365
+ *
366
+ * @param BitArray $bits
367
+ * @param integer $numTotalBytes
368
+ * @param integer $numDataBytes
369
+ * @param integer $numRsBlocks
370
+ * @return BitArray
371
+ * @throws Exception\WriterException
372
+ */
373
+ protected static function interleaveWithEcBytes(BitArray $bits, $numTotalBytes, $numDataBytes, $numRsBlocks)
374
+ {
375
+ if ($bits->getSizeInBytes() !== $numDataBytes) {
376
+ throw new Exception\WriterException('Number of bits and data bytes does not match');
377
+ }
378
+
379
+ $dataBytesOffset = 0;
380
+ $maxNumDataBytes = 0;
381
+ $maxNumEcBytes = 0;
382
+
383
+ $blocks = new SplFixedArray($numRsBlocks);
384
+
385
+ for ($i = 0; $i < $numRsBlocks; $i++) {
386
+ list($numDataBytesInBlock, $numEcBytesInBlock) = self::getNumDataBytesAndNumEcBytesForBlockId(
387
+ $numTotalBytes,
388
+ $numDataBytes,
389
+ $numRsBlocks,
390
+ $i
391
+ );
392
+
393
+ $size = $numDataBytesInBlock;
394
+ $dataBytes = $bits->toBytes(8 * $dataBytesOffset, $size);
395
+ $ecBytes = self::generateEcBytes($dataBytes, $numEcBytesInBlock);
396
+ $blocks[$i] = new BlockPair($dataBytes, $ecBytes);
397
+
398
+ $maxNumDataBytes = max($maxNumDataBytes, $size);
399
+ $maxNumEcBytes = max($maxNumEcBytes, count($ecBytes));
400
+ $dataBytesOffset += $numDataBytesInBlock;
401
+ }
402
+
403
+ if ($numDataBytes !== $dataBytesOffset) {
404
+ throw new Exception\WriterException('Data bytes does not match offset');
405
+ }
406
+
407
+ $result = new BitArray();
408
+
409
+ for ($i = 0; $i < $maxNumDataBytes; $i++) {
410
+ foreach ($blocks as $block) {
411
+ $dataBytes = $block->getDataBytes();
412
+
413
+ if ($i < count($dataBytes)) {
414
+ $result->appendBits($dataBytes[$i], 8);
415
+ }
416
+ }
417
+ }
418
+
419
+ for ($i = 0; $i < $maxNumEcBytes; $i++) {
420
+ foreach ($blocks as $block) {
421
+ $ecBytes = $block->getErrorCorrectionBytes();
422
+
423
+ if ($i < count($ecBytes)) {
424
+ $result->appendBits($ecBytes[$i], 8);
425
+ }
426
+ }
427
+ }
428
+
429
+ if ($numTotalBytes !== $result->getSizeInBytes()) {
430
+ throw new Exception\WriterException('Interleaving error: ' . $numTotalBytes . ' and ' . $result->getSizeInBytes() . ' differ');
431
+ }
432
+
433
+ return $result;
434
+ }
435
+
436
+ /**
437
+ * Generates EC bytes for given data.
438
+ *
439
+ * @param SplFixedArray $dataBytes
440
+ * @param integer $numEcBytesInBlock
441
+ * @return SplFixedArray
442
+ */
443
+ protected static function generateEcBytes(SplFixedArray $dataBytes, $numEcBytesInBlock)
444
+ {
445
+ $numDataBytes = count($dataBytes);
446
+ $toEncode = new SplFixedArray($numDataBytes + $numEcBytesInBlock);
447
+
448
+ for ($i = 0; $i < $numDataBytes; $i++) {
449
+ $toEncode[$i] = $dataBytes[$i] & 0xff;
450
+ }
451
+
452
+ $ecBytes = new SplFixedArray($numEcBytesInBlock);
453
+ $codec = self::getCodec($numDataBytes, $numEcBytesInBlock);
454
+ $codec->encode($toEncode, $ecBytes);
455
+
456
+ return $ecBytes;
457
+ }
458
+
459
+ /**
460
+ * Gets an RS codec and caches it.
461
+ *
462
+ * @param integer $numDataBytes
463
+ * @param integer $numEcBytesInBlock
464
+ * @return ReedSolomonCodec
465
+ */
466
+ protected static function getCodec($numDataBytes, $numEcBytesInBlock)
467
+ {
468
+ $cacheId = $numDataBytes . '-' . $numEcBytesInBlock;
469
+
470
+ if (!isset(self::$codecs[$cacheId])) {
471
+ self::$codecs[$cacheId] = new ReedSolomonCodec(
472
+ 8,
473
+ 0x11d,
474
+ 0,
475
+ 1,
476
+ $numEcBytesInBlock,
477
+ 255 - $numDataBytes - $numEcBytesInBlock
478
+ );
479
+ }
480
+
481
+ return self::$codecs[$cacheId];
482
+ }
483
+
484
+ /**
485
+ * Appends mode information to a bit array.
486
+ *
487
+ * @param Mode $mode
488
+ * @param BitArray $bits
489
+ * @return void
490
+ */
491
+ protected static function appendModeInfo(Mode $mode, BitArray $bits)
492
+ {
493
+ $bits->appendBits($mode->get(), 4);
494
+ }
495
+
496
+ /**
497
+ * Appends length information to a bit array.
498
+ *
499
+ * @param integer $numLetters
500
+ * @param Version $version
501
+ * @param Mode $mode
502
+ * @param BitArray $bits
503
+ * @return void
504
+ * @throws Exception\WriterException
505
+ */
506
+ protected static function appendLengthInfo($numLetters, Version $version, Mode $mode, BitArray $bits)
507
+ {
508
+ $numBits = $mode->getCharacterCountBits($version);
509
+
510
+ if ($numLetters >= (1 << $numBits)) {
511
+ throw new Exception\WriterException($numLetters . ' is bigger than ' . ((1 << $numBits) - 1));
512
+ }
513
+
514
+ $bits->appendBits($numLetters, $numBits);
515
+ }
516
+
517
+ /**
518
+ * Appends bytes to a bit array in a specific mode.
519
+ *
520
+ * @param stirng $content
521
+ * @param Mode $mode
522
+ * @param BitArray $bits
523
+ * @param string $encoding
524
+ * @return void
525
+ * @throws Exception\WriterException
526
+ */
527
+ protected static function appendBytes($content, Mode $mode, BitArray $bits, $encoding)
528
+ {
529
+ switch ($mode->get()) {
530
+ case Mode::NUMERIC:
531
+ self::appendNumericBytes($content, $bits);
532
+ break;
533
+
534
+ case Mode::ALPHANUMERIC:
535
+ self::appendAlphanumericBytes($content, $bits);
536
+ break;
537
+
538
+ case Mode::BYTE:
539
+ self::append8BitBytes($content, $bits, $encoding);
540
+ break;
541
+
542
+ case Mode::KANJI:
543
+ self::appendKanjiBytes($content, $bits);
544
+ break;
545
+
546
+ default:
547
+ throw new Exception\WriterException('Invalid mode: ' . $mode->get());
548
+ }
549
+ }
550
+
551
+ /**
552
+ * Appends numeric bytes to a bit array.
553
+ *
554
+ * @param string $content
555
+ * @param BitArray $bits
556
+ * @return void
557
+ */
558
+ protected static function appendNumericBytes($content, BitArray $bits)
559
+ {
560
+ $length = strlen($content);
561
+ $i = 0;
562
+
563
+ while ($i < $length) {
564
+ $num1 = (int) $content[$i];
565
+
566
+ if ($i + 2 < $length) {
567
+ // Encode three numeric letters in ten bits.
568
+ $num2 = (int) $content[$i + 1];
569
+ $num3 = (int) $content[$i + 2];
570
+ $bits->appendBits($num1 * 100 + $num2 * 10 + $num3, 10);
571
+ $i += 3;
572
+ } elseif ($i + 1 < $length) {
573
+ // Encode two numeric letters in seven bits.
574
+ $num2 = (int) $content[$i + 1];
575
+ $bits->appendBits($num1 * 10 + $num2, 7);
576
+ $i += 2;
577
+ } else {
578
+ // Encode one numeric letter in four bits.
579
+ $bits->appendBits($num1, 4);
580
+ $i++;
581
+ }
582
+ }
583
+ }
584
+
585
+ /**
586
+ * Appends alpha-numeric bytes to a bit array.
587
+ *
588
+ * @param string $content
589
+ * @param BitArray $bits
590
+ * @return void
591
+ */
592
+ protected static function appendAlphanumericBytes($content, BitArray $bits)
593
+ {
594
+ $length = strlen($content);
595
+ $i = 0;
596
+
597
+ while ($i < $length) {
598
+ if (-1 === ($code1 = self::getAlphanumericCode($content[$i]))) {
599
+ throw new Exception\WriterException('Invalid alphanumeric code');
600
+ }
601
+
602
+ if ($i + 1 < $length) {
603
+ if (-1 === ($code2 = self::getAlphanumericCode($content[$i + 1]))) {
604
+ throw new Exception\WriterException('Invalid alphanumeric code');
605
+ }
606
+
607
+ // Encode two alphanumeric letters in 11 bits.
608
+ $bits->appendBits($code1 * 45 + $code2, 11);
609
+ $i += 2;
610
+ } else {
611
+ // Encode one alphanumeric letter in six bits.
612
+ $bits->appendBits($code1, 6);
613
+ $i++;
614
+ }
615
+ }
616
+ }
617
+
618
+ /**
619
+ * Appends regular 8-bit bytes to a bit array.
620
+ *
621
+ * @param string $content
622
+ * @param BitArray $bits
623
+ * @return void
624
+ */
625
+ protected static function append8BitBytes($content, BitArray $bits, $encoding)
626
+ {
627
+ if (false === ($bytes = @iconv('utf-8', $encoding, $content))) {
628
+ throw new Exception\WriterException('Could not encode content to ' . $encoding);
629
+ }
630
+
631
+ $length = strlen($bytes);
632
+
633
+ for ($i = 0; $i < $length; $i++) {
634
+ $bits->appendBits(ord($bytes[$i]), 8);
635
+ }
636
+ }
637
+
638
+ /**
639
+ * Appends KANJI bytes to a bit array.
640
+ *
641
+ * @param string $content
642
+ * @param BitArray $bits
643
+ * @return void
644
+ */
645
+ protected static function appendKanjiBytes($content, BitArray $bits)
646
+ {
647
+ if (strlen($content) % 2 > 0) {
648
+ // We just do a simple length check here. The for loop will check
649
+ // individual characters.
650
+ throw new Exception\WriterException('Content does not seem to be encoded in SHIFT-JIS');
651
+ }
652
+
653
+ $length = strlen($content);
654
+
655
+ for ($i = 0; $i < $length; $i += 2) {
656
+ $byte1 = ord($content[$i]) & 0xff;
657
+ $byte2 = ord($content[$i + 1]) & 0xff;
658
+ $code = ($byte1 << 8) | $byte2;
659
+
660
+ if ($code >= 0x8140 && $code <= 0x9ffc) {
661
+ $subtracted = $code - 0x8140;
662
+ } elseif ($code >= 0xe040 && $code <= 0xebbf) {
663
+ $subtracted = $code - 0xc140;
664
+ } else {
665
+ throw new Exception\WriterException('Invalid byte sequence');
666
+ }
667
+
668
+ $encoded = (($subtracted >> 8) * 0xc0) + ($subtracted & 0xff);
669
+
670
+ $bits->appendBits($encoded, 13);
671
+ }
672
+ }
673
+
674
+ /**
675
+ * Appends ECI information to a bit array.
676
+ *
677
+ * @param CharacterSetEci $eci
678
+ * @param BitArray $bits
679
+ * @return void
680
+ */
681
+ protected static function appendEci(CharacterSetEci $eci, BitArray $bits)
682
+ {
683
+ $mode = new Mode(Mode::ECI);
684
+ $bits->appendBits($mode->get(), 4);
685
+ $bits->appendBits($eci->get(), 8);
686
+ }
687
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/MaskUtil.php ADDED
@@ -0,0 +1,291 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Encoder;
11
+
12
+ use BaconQrCode\Common\BitUtils;
13
+
14
+ /**
15
+ * Mask utility.
16
+ */
17
+ class MaskUtil
18
+ {
19
+ /**#@+
20
+ * Penalty weights from section 6.8.2.1
21
+ */
22
+ const N1 = 3;
23
+ const N2 = 3;
24
+ const N3 = 40;
25
+ const N4 = 10;
26
+ /**#@-*/
27
+
28
+ /**
29
+ * Applies mask penalty rule 1 and returns the penalty.
30
+ *
31
+ * Finds repetitive cells with the same color and gives penalty to them.
32
+ * Example: 00000 or 11111.
33
+ *
34
+ * @param ByteMatrix $matrix
35
+ * @return integer
36
+ */
37
+ public static function applyMaskPenaltyRule1(ByteMatrix $matrix)
38
+ {
39
+ return (
40
+ self::applyMaskPenaltyRule1Internal($matrix, true)
41
+ + self::applyMaskPenaltyRule1Internal($matrix, false)
42
+ );
43
+ }
44
+
45
+ /**
46
+ * Applies mask penalty rule 2 and returns the penalty.
47
+ *
48
+ * Finds 2x2 blocks with the same color and gives penalty to them. This is
49
+ * actually equivalent to the spec's rule, which is to find MxN blocks and
50
+ * give a penalty proportional to (M-1)x(N-1), because this is the number of
51
+ * 2x2 blocks inside such a block.
52
+ *
53
+ * @param ByteMatrix $matrix
54
+ * @return integer
55
+ */
56
+ public static function applyMaskPenaltyRule2(ByteMatrix $matrix)
57
+ {
58
+ $penalty = 0;
59
+ $array = $matrix->getArray();
60
+ $width = $matrix->getWidth();
61
+ $height = $matrix->getHeight();
62
+
63
+ for ($y = 0; $y < $height - 1; $y++) {
64
+ for ($x = 0; $x < $width - 1; $x++) {
65
+ $value = $array[$y][$x];
66
+
67
+ if ($value === $array[$y][$x + 1] && $value === $array[$y + 1][$x] && $value === $array[$y + 1][$x + 1]) {
68
+ $penalty++;
69
+ }
70
+ }
71
+ }
72
+
73
+ return self::N2 * $penalty;
74
+ }
75
+
76
+ /**
77
+ * Applies mask penalty rule 3 and returns the penalty.
78
+ *
79
+ * Finds consecutive cells of 00001011101 or 10111010000, and gives penalty
80
+ * to them. If we find patterns like 000010111010000, we give penalties
81
+ * twice (i.e. 40 * 2).
82
+ *
83
+ * @param ByteMatrix $matrix
84
+ * @return integer
85
+ */
86
+ public static function applyMaskPenaltyRule3(ByteMatrix $matrix)
87
+ {
88
+ $penalty = 0;
89
+ $array = $matrix->getArray();
90
+ $width = $matrix->getWidth();
91
+ $height = $matrix->getHeight();
92
+
93
+ for ($y = 0; $y < $height; $y++) {
94
+ for ($x = 0; $x < $width; $x++) {
95
+ if (
96
+ $x + 6 < $width
97
+ && $array[$y][$x] === 1
98
+ && $array[$y][$x + 1] === 0
99
+ && $array[$y][$x + 2] === 1
100
+ && $array[$y][$x + 3] === 1
101
+ && $array[$y][$x + 4] === 1
102
+ && $array[$y][$x + 5] === 0
103
+ && $array[$y][$x + 6] === 1
104
+ && (
105
+ (
106
+ $x + 10 < $width
107
+ && $array[$y][$x + 7] === 0
108
+ && $array[$y][$x + 8] === 0
109
+ && $array[$y][$x + 9] === 0
110
+ && $array[$y][$x + 10] === 0
111
+ )
112
+ || (
113
+ $x - 4 >= 0
114
+ && $array[$y][$x - 1] === 0
115
+ && $array[$y][$x - 2] === 0
116
+ && $array[$y][$x - 3] === 0
117
+ && $array[$y][$x - 4] === 0
118
+ )
119
+ )
120
+ ) {
121
+ $penalty += self::N3;
122
+ }
123
+
124
+ if (
125
+ $y + 6 < $height
126
+ && $array[$y][$x] === 1
127
+ && $array[$y + 1][$x] === 0
128
+ && $array[$y + 2][$x] === 1
129
+ && $array[$y + 3][$x] === 1
130
+ && $array[$y + 4][$x] === 1
131
+ && $array[$y + 5][$x] === 0
132
+ && $array[$y + 6][$x] === 1
133
+ && (
134
+ (
135
+ $y + 10 < $height
136
+ && $array[$y + 7][$x] === 0
137
+ && $array[$y + 8][$x] === 0
138
+ && $array[$y + 9][$x] === 0
139
+ && $array[$y + 10][$x] === 0
140
+ )
141
+ || (
142
+ $y - 4 >= 0
143
+ && $array[$y - 1][$x] === 0
144
+ && $array[$y - 2][$x] === 0
145
+ && $array[$y - 3][$x] === 0
146
+ && $array[$y - 4][$x] === 0
147
+ )
148
+ )
149
+ ) {
150
+ $penalty += self::N3;
151
+ }
152
+ }
153
+ }
154
+
155
+ return $penalty;
156
+ }
157
+
158
+ /**
159
+ * Applies mask penalty rule 4 and returns the penalty.
160
+ *
161
+ * Calculates the ratio of dark cells and gives penalty if the ratio is far
162
+ * from 50%. It gives 10 penalty for 5% distance.
163
+ *
164
+ * @param ByteMatrix $matrix
165
+ * @return integer
166
+ */
167
+ public static function applyMaskPenaltyRule4(ByteMatrix $matrix)
168
+ {
169
+ $numDarkCells = 0;
170
+
171
+ $array = $matrix->getArray();
172
+ $width = $matrix->getWidth();
173
+ $height = $matrix->getHeight();
174
+
175
+ for ($y = 0; $y < $height; $y++) {
176
+ $arrayY = $array[$y];
177
+
178
+ for ($x = 0; $x < $width; $x++) {
179
+ if ($arrayY[$x] === 1) {
180
+ $numDarkCells++;
181
+ }
182
+ }
183
+ }
184
+
185
+ $numTotalCells = $height * $width;
186
+ $darkRatio = $numDarkCells / $numTotalCells;
187
+ $fixedPercentVariances = (int) (abs($darkRatio - 0.5) * 20);
188
+
189
+ return $fixedPercentVariances * self::N4;
190
+ }
191
+
192
+ /**
193
+ * Returns the mask bit for "getMaskPattern" at "x" and "y".
194
+ *
195
+ * See 8.8 of JISX0510:2004 for mask pattern conditions.
196
+ *
197
+ * @param integer $maskPattern
198
+ * @param integer $x
199
+ * @param integer $y
200
+ * @return integer
201
+ * @throws Exception\InvalidArgumentException
202
+ */
203
+ public static function getDataMaskBit($maskPattern, $x, $y)
204
+ {
205
+ switch ($maskPattern) {
206
+ case 0:
207
+ $intermediate = ($y + $x) & 0x1;
208
+ break;
209
+
210
+ case 1:
211
+ $intermediate = $y & 0x1;
212
+ break;
213
+
214
+ case 2:
215
+ $intermediate = $x % 3;
216
+ break;
217
+
218
+ case 3:
219
+ $intermediate = ($y + $x) % 3;
220
+ break;
221
+
222
+ case 4:
223
+ $intermediate = (BitUtils::unsignedRightShift($y, 1) + ($x / 3)) & 0x1;
224
+ break;
225
+
226
+ case 5:
227
+ $temp = $y * $x;
228
+ $intermediate = ($temp & 0x1) + ($temp % 3);
229
+ break;
230
+
231
+ case 6:
232
+ $temp = $y * $x;
233
+ $intermediate = (($temp & 0x1) + ($temp % 3)) & 0x1;
234
+ break;
235
+
236
+ case 7:
237
+ $temp = $y * $x;
238
+ $intermediate = (($temp % 3) + (($y + $x) & 0x1)) & 0x1;
239
+ break;
240
+
241
+ default:
242
+ throw new Exception\InvalidArgumentException('Invalid mask pattern: ' . $maskPattern);
243
+ }
244
+
245
+ return $intermediate === 0;
246
+ }
247
+
248
+ /**
249
+ * Helper function for applyMaskPenaltyRule1.
250
+ *
251
+ * We need this for doing this calculation in both vertical and horizontal
252
+ * orders respectively.
253
+ *
254
+ * @param ByteMatrix $matrix
255
+ * @param boolean $isHorizontal
256
+ * @return integer
257
+ */
258
+ protected static function applyMaskPenaltyRule1Internal(ByteMatrix $matrix, $isHorizontal)
259
+ {
260
+ $penalty = 0;
261
+ $iLimit = $isHorizontal ? $matrix->getHeight() : $matrix->getWidth();
262
+ $jLimit = $isHorizontal ? $matrix->getWidth() : $matrix->getHeight();
263
+ $array = $matrix->getArray();
264
+
265
+ for ($i = 0; $i < $iLimit; $i++) {
266
+ $numSameBitCells = 0;
267
+ $prevBit = -1;
268
+
269
+ for ($j = 0; $j < $jLimit; $j++) {
270
+ $bit = $isHorizontal ? $array[$i][$j] : $array[$j][$i];
271
+
272
+ if ($bit === $prevBit) {
273
+ $numSameBitCells++;
274
+ } else {
275
+ if ($numSameBitCells >= 5) {
276
+ $penalty += self::N1 + ($numSameBitCells - 5);
277
+ }
278
+
279
+ $numSameBitCells = 1;
280
+ $prevBit = $bit;
281
+ }
282
+ }
283
+
284
+ if ($numSameBitCells >= 5) {
285
+ $penalty += self::N1 + ($numSameBitCells - 5);
286
+ }
287
+ }
288
+
289
+ return $penalty;
290
+ }
291
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/MatrixUtil.php ADDED
@@ -0,0 +1,580 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Encoder;
11
+
12
+ use BaconQrCode\Common\BitArray;
13
+ use BaconQrCode\Common\ErrorCorrectionLevel;
14
+ use BaconQrCode\Common\Version;
15
+ use BaconQrCode\Exception;
16
+
17
+ /**
18
+ * Matrix utility.
19
+ */
20
+ class MatrixUtil
21
+ {
22
+ /**
23
+ * Position detection pattern.
24
+ *
25
+ * @var array
26
+ */
27
+ protected static $positionDetectionPattern = array(
28
+ array(1, 1, 1, 1, 1, 1, 1),
29
+ array(1, 0, 0, 0, 0, 0, 1),
30
+ array(1, 0, 1, 1, 1, 0, 1),
31
+ array(1, 0, 1, 1, 1, 0, 1),
32
+ array(1, 0, 1, 1, 1, 0, 1),
33
+ array(1, 0, 0, 0, 0, 0, 1),
34
+ array(1, 1, 1, 1, 1, 1, 1),
35
+ );
36
+
37
+ /**
38
+ * Position adjustment pattern.
39
+ *
40
+ * @var array
41
+ */
42
+ protected static $positionAdjustmentPattern = array(
43
+ array(1, 1, 1, 1, 1),
44
+ array(1, 0, 0, 0, 1),
45
+ array(1, 0, 1, 0, 1),
46
+ array(1, 0, 0, 0, 1),
47
+ array(1, 1, 1, 1, 1),
48
+ );
49
+
50
+ /**
51
+ * Coordinates for position adjustment patterns for each version.
52
+ *
53
+ * @var array
54
+ */
55
+ protected static $positionAdjustmentPatternCoordinateTable = array(
56
+ array(null, null, null, null, null, null, null), // Version 1
57
+ array( 6, 18, null, null, null, null, null), // Version 2
58
+ array( 6, 22, null, null, null, null, null), // Version 3
59
+ array( 6, 26, null, null, null, null, null), // Version 4
60
+ array( 6, 30, null, null, null, null, null), // Version 5
61
+ array( 6, 34, null, null, null, null, null), // Version 6
62
+ array( 6, 22, 38, null, null, null, null), // Version 7
63
+ array( 6, 24, 42, null, null, null, null), // Version 8
64
+ array( 6, 26, 46, null, null, null, null), // Version 9
65
+ array( 6, 28, 50, null, null, null, null), // Version 10
66
+ array( 6, 30, 54, null, null, null, null), // Version 11
67
+ array( 6, 32, 58, null, null, null, null), // Version 12
68
+ array( 6, 34, 62, null, null, null, null), // Version 13
69
+ array( 6, 26, 46, 66, null, null, null), // Version 14
70
+ array( 6, 26, 48, 70, null, null, null), // Version 15
71
+ array( 6, 26, 50, 74, null, null, null), // Version 16
72
+ array( 6, 30, 54, 78, null, null, null), // Version 17
73
+ array( 6, 30, 56, 82, null, null, null), // Version 18
74
+ array( 6, 30, 58, 86, null, null, null), // Version 19
75
+ array( 6, 34, 62, 90, null, null, null), // Version 20
76
+ array( 6, 28, 50, 72, 94, null, null), // Version 21
77
+ array( 6, 26, 50, 74, 98, null, null), // Version 22
78
+ array( 6, 30, 54, 78, 102, null, null), // Version 23
79
+ array( 6, 28, 54, 80, 106, null, null), // Version 24
80
+ array( 6, 32, 58, 84, 110, null, null), // Version 25
81
+ array( 6, 30, 58, 86, 114, null, null), // Version 26
82
+ array( 6, 34, 62, 90, 118, null, null), // Version 27
83
+ array( 6, 26, 50, 74, 98, 122, null), // Version 28
84
+ array( 6, 30, 54, 78, 102, 126, null), // Version 29
85
+ array( 6, 26, 52, 78, 104, 130, null), // Version 30
86
+ array( 6, 30, 56, 82, 108, 134, null), // Version 31
87
+ array( 6, 34, 60, 86, 112, 138, null), // Version 32
88
+ array( 6, 30, 58, 86, 114, 142, null), // Version 33
89
+ array( 6, 34, 62, 90, 118, 146, null), // Version 34
90
+ array( 6, 30, 54, 78, 102, 126, 150), // Version 35
91
+ array( 6, 24, 50, 76, 102, 128, 154), // Version 36
92
+ array( 6, 28, 54, 80, 106, 132, 158), // Version 37
93
+ array( 6, 32, 58, 84, 110, 136, 162), // Version 38
94
+ array( 6, 26, 54, 82, 110, 138, 166), // Version 39
95
+ array( 6, 30, 58, 86, 114, 142, 170), // Version 40
96
+ );
97
+
98
+ /**
99
+ * Type information coordinates.
100
+ *
101
+ * @var array
102
+ */
103
+ protected static $typeInfoCoordinates = array(
104
+ array(8, 0),
105
+ array(8, 1),
106
+ array(8, 2),
107
+ array(8, 3),
108
+ array(8, 4),
109
+ array(8, 5),
110
+ array(8, 7),
111
+ array(8, 8),
112
+ array(7, 8),
113
+ array(5, 8),
114
+ array(4, 8),
115
+ array(3, 8),
116
+ array(2, 8),
117
+ array(1, 8),
118
+ array(0, 8),
119
+ );
120
+
121
+ /**
122
+ * Version information polynomial.
123
+ *
124
+ * @var integer
125
+ */
126
+ protected static $versionInfoPoly = 0x1f25;
127
+
128
+ /**
129
+ * Type information polynomial.
130
+ *
131
+ * @var integer
132
+ */
133
+ protected static $typeInfoPoly = 0x537;
134
+
135
+ /**
136
+ * Type information mask pattern.
137
+ *
138
+ * @var integer
139
+ */
140
+ protected static $typeInfoMaskPattern = 0x5412;
141
+
142
+ /**
143
+ * Clears a given matrix.
144
+ *
145
+ * @param ByteMatrix $matrix
146
+ * @return void
147
+ */
148
+ public static function clearMatrix(ByteMatrix $matrix)
149
+ {
150
+ $matrix->clear(-1);
151
+ }
152
+
153
+ /**
154
+ * Builds a complete matrix.
155
+ *
156
+ * @param BitArray $dataBits
157
+ * @param ErrorCorrectionLevel $level
158
+ * @param Version $version
159
+ * @param integer $maskPattern
160
+ * @param ByteMatrix $matrix
161
+ * @return void
162
+ */
163
+ public static function buildMatrix(
164
+ BitArray $dataBits,
165
+ ErrorCorrectionLevel $level,
166
+ Version $version,
167
+ $maskPattern,
168
+ ByteMatrix $matrix
169
+ ) {
170
+ self::clearMatrix($matrix);
171
+ self::embedBasicPatterns($version, $matrix);
172
+ self::embedTypeInfo($level, $maskPattern, $matrix);
173
+ self::maybeEmbedVersionInfo($version, $matrix);
174
+ self::embedDataBits($dataBits, $maskPattern, $matrix);
175
+ }
176
+
177
+ /**
178
+ * Embeds type information into a matrix.
179
+ *
180
+ * @param ErrorCorrectionLevel $level
181
+ * @param integer $maskPattern
182
+ * @param ByteMatrix $matrix
183
+ * @return void
184
+ */
185
+ protected static function embedTypeInfo(ErrorCorrectionLevel $level, $maskPattern, ByteMatrix $matrix)
186
+ {
187
+ $typeInfoBits = new BitArray();
188
+ self::makeTypeInfoBits($level, $maskPattern, $typeInfoBits);
189
+
190
+ $typeInfoBitsSize = $typeInfoBits->getSize();
191
+
192
+ for ($i = 0; $i < $typeInfoBitsSize; $i++) {
193
+ $bit = $typeInfoBits->get($typeInfoBitsSize - 1 - $i);
194
+
195
+ $x1 = self::$typeInfoCoordinates[$i][0];
196
+ $y1 = self::$typeInfoCoordinates[$i][1];
197
+
198
+ $matrix->set($x1, $y1, $bit);
199
+
200
+ if ($i < 8) {
201
+ $x2 = $matrix->getWidth() - $i - 1;
202
+ $y2 = 8;
203
+ } else {
204
+ $x2 = 8;
205
+ $y2 = $matrix->getHeight() - 7 + ($i - 8);
206
+ }
207
+
208
+ $matrix->set($x2, $y2, $bit);
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Generates type information bits and appends them to a bit array.
214
+ *
215
+ * @param ErrorCorrectionLevel $level
216
+ * @param integer $maskPattern
217
+ * @param BitArray $bits
218
+ * @return void
219
+ * @throws Exception\RuntimeException
220
+ */
221
+ protected static function makeTypeInfoBits(ErrorCorrectionLevel $level, $maskPattern, BitArray $bits)
222
+ {
223
+ $typeInfo = ($level->get() << 3) | $maskPattern;
224
+ $bits->appendBits($typeInfo, 5);
225
+
226
+ $bchCode = self::calculateBchCode($typeInfo, self::$typeInfoPoly);
227
+ $bits->appendBits($bchCode, 10);
228
+
229
+ $maskBits = new BitArray();
230
+ $maskBits->appendBits(self::$typeInfoMaskPattern, 15);
231
+ $bits->xorBits($maskBits);
232
+
233
+ if ($bits->getSize() !== 15) {
234
+ throw new Exception\RuntimeException('Bit array resulted in invalid size: ' . $bits->getSize());
235
+ }
236
+ }
237
+
238
+ /**
239
+ * Embeds version information if required.
240
+ *
241
+ * @param Version $version
242
+ * @param ByteMatrix $matrix
243
+ * @return void
244
+ */
245
+ protected static function maybeEmbedVersionInfo(Version $version, ByteMatrix $matrix)
246
+ {
247
+ if ($version->getVersionNumber() < 7) {
248
+ return;
249
+ }
250
+
251
+ $versionInfoBits = new BitArray();
252
+ self::makeVersionInfoBits($version, $versionInfoBits);
253
+
254
+ $bitIndex = 6 * 3 - 1;
255
+
256
+ for ($i = 0; $i < 6; $i++) {
257
+ for ($j = 0; $j < 3; $j++) {
258
+ $bit = $versionInfoBits->get($bitIndex);
259
+ $bitIndex--;
260
+
261
+ $matrix->set($i, $matrix->getHeight() - 11 + $j, $bit);
262
+ $matrix->set($matrix->getHeight() - 11 + $j, $i, $bit);
263
+ }
264
+ }
265
+ }
266
+
267
+ /**
268
+ * Generates version information bits and appends them to a bit array.
269
+ *
270
+ * @param Version $version
271
+ * @param BitArray $bits
272
+ * @return void
273
+ * @throws Exception\RuntimeException
274
+ */
275
+ protected static function makeVersionInfoBits(Version $version, BitArray $bits)
276
+ {
277
+ $bits->appendBits($version->getVersionNumber(), 6);
278
+
279
+ $bchCode = self::calculateBchCode($version->getVersionNumber(), self::$versionInfoPoly);
280
+ $bits->appendBits($bchCode, 12);
281
+
282
+ if ($bits->getSize() !== 18) {
283
+ throw new Exception\RuntimeException('Bit array resulted in invalid size: ' . $bits->getSize());
284
+ }
285
+ }
286
+
287
+ /**
288
+ * Calculates the BHC code for a value and a polynomial.
289
+ *
290
+ * @param integer $value
291
+ * @param integer $poly
292
+ * @return integer
293
+ */
294
+ protected static function calculateBchCode($value, $poly)
295
+ {
296
+ $msbSetInPoly = self::findMsbSet($poly);
297
+ $value <<= $msbSetInPoly - 1;
298
+
299
+ while (self::findMsbSet($value) >= $msbSetInPoly) {
300
+ $value ^= $poly << (self::findMsbSet($value) - $msbSetInPoly);
301
+ }
302
+
303
+ return $value;
304
+ }
305
+
306
+ /**
307
+ * Finds and MSB set.
308
+ *
309
+ * @param integer $value
310
+ * @return integer
311
+ */
312
+ protected static function findMsbSet($value)
313
+ {
314
+ $numDigits = 0;
315
+
316
+ while ($value !== 0) {
317
+ $value >>= 1;
318
+ $numDigits++;
319
+ }
320
+
321
+ return $numDigits;
322
+ }
323
+
324
+ /**
325
+ * Embeds basic patterns into a matrix.
326
+ *
327
+ * @param Version $version
328
+ * @param ByteMatrix $matrix
329
+ * @return void
330
+ */
331
+ protected static function embedBasicPatterns(Version $version, ByteMatrix $matrix)
332
+ {
333
+ self::embedPositionDetectionPatternsAndSeparators($matrix);
334
+ self::embedDarkDotAtLeftBottomCorner($matrix);
335
+ self::maybeEmbedPositionAdjustmentPatterns($version, $matrix);
336
+ self::embedTimingPatterns($matrix);
337
+ }
338
+
339
+ /**
340
+ * Embeds position detection patterns and separators into a byte matrix.
341
+ *
342
+ * @param ByteMatrix $matrix
343
+ * @return void
344
+ */
345
+ protected static function embedPositionDetectionPatternsAndSeparators(ByteMatrix $matrix)
346
+ {
347
+ $pdpWidth = count(self::$positionDetectionPattern[0]);
348
+
349
+ self::embedPositionDetectionPattern(0, 0, $matrix);
350
+ self::embedPositionDetectionPattern($matrix->getWidth() - $pdpWidth, 0, $matrix);
351
+ self::embedPositionDetectionPattern(0, $matrix->getWidth() - $pdpWidth, $matrix);
352
+
353
+ $hspWidth = 8;
354
+
355
+ self::embedHorizontalSeparationPattern(0, $hspWidth - 1, $matrix);
356
+ self::embedHorizontalSeparationPattern($matrix->getWidth() - $hspWidth, $hspWidth - 1, $matrix);
357
+ self::embedHorizontalSeparationPattern(0, $matrix->getWidth() - $hspWidth, $matrix);
358
+
359
+ $vspSize = 7;
360
+
361
+ self::embedVerticalSeparationPattern($vspSize, 0, $matrix);
362
+ self::embedVerticalSeparationPattern($matrix->getHeight() - $vspSize - 1, 0, $matrix);
363
+ self::embedVerticalSeparationPattern($vspSize, $matrix->getHeight() - $vspSize, $matrix);
364
+ }
365
+
366
+ /**
367
+ * Embeds a single position detection pattern into a byte matrix.
368
+ *
369
+ * @param integer $xStart
370
+ * @param integer $yStart
371
+ * @param ByteMatrix $matrix
372
+ * @return void
373
+ */
374
+ protected static function embedPositionDetectionPattern($xStart, $yStart, ByteMatrix $matrix)
375
+ {
376
+ for ($y = 0; $y < 7; $y++) {
377
+ for ($x = 0; $x < 7; $x++) {
378
+ $matrix->set($xStart + $x, $yStart + $y, self::$positionDetectionPattern[$y][$x]);
379
+ }
380
+ }
381
+ }
382
+
383
+ /**
384
+ * Embeds a single horizontal separation pattern.
385
+ *
386
+ * @param integer $xStart
387
+ * @param integer $yStart
388
+ * @param ByteMatrix $matrix
389
+ * @return void
390
+ * @throws Exception\RuntimeException
391
+ */
392
+ protected static function embedHorizontalSeparationPattern($xStart, $yStart, ByteMatrix $matrix)
393
+ {
394
+ for ($x = 0; $x < 8; $x++) {
395
+ if ($matrix->get($xStart + $x, $yStart) !== -1) {
396
+ throw new Exception\RuntimeException('Byte already set');
397
+ }
398
+
399
+ $matrix->set($xStart + $x, $yStart, 0);
400
+ }
401
+ }
402
+
403
+ /**
404
+ * Embeds a single vertical separation pattern.
405
+ *
406
+ * @param integer $xStart
407
+ * @param integer $yStart
408
+ * @param ByteMatrix $matrix
409
+ * @return void
410
+ * @throws Exception\RuntimeException
411
+ */
412
+ protected static function embedVerticalSeparationPattern($xStart, $yStart, ByteMatrix $matrix)
413
+ {
414
+ for ($y = 0; $y < 7; $y++) {
415
+ if ($matrix->get($xStart, $yStart + $y) !== -1) {
416
+ throw new Exception\RuntimeException('Byte already set');
417
+ }
418
+
419
+ $matrix->set($xStart, $yStart + $y, 0);
420
+ }
421
+ }
422
+
423
+ /**
424
+ * Embeds a dot at the left bottom corner.
425
+ *
426
+ * @param ByteMatrix $matrix
427
+ * @return void
428
+ * @throws Exception\RuntimeException
429
+ */
430
+ protected static function embedDarkDotAtLeftBottomCorner(ByteMatrix $matrix)
431
+ {
432
+ if ($matrix->get(8, $matrix->getHeight() - 8) === 0) {
433
+ throw new Exception\RuntimeException('Byte already set to 0');
434
+ }
435
+
436
+ $matrix->set(8, $matrix->getHeight() - 8, 1);
437
+ }
438
+
439
+ /**
440
+ * Embeds position adjustment patterns if required.
441
+ *
442
+ * @param Version $version
443
+ * @param ByteMatrix $matrix
444
+ * @return void
445
+ */
446
+ protected static function maybeEmbedPositionAdjustmentPatterns(Version $version, ByteMatrix $matrix)
447
+ {
448
+ if ($version->getVersionNumber() < 2) {
449
+ return;
450
+ }
451
+
452
+ $index = $version->getVersionNumber() - 1;
453
+
454
+ $coordinates = self::$positionAdjustmentPatternCoordinateTable[$index];
455
+ $numCoordinates = count($coordinates);
456
+
457
+ for ($i = 0; $i < $numCoordinates; $i++) {
458
+ for ($j = 0; $j < $numCoordinates; $j++) {
459
+ $y = $coordinates[$i];
460
+ $x = $coordinates[$j];
461
+
462
+ if ($x === null || $y === null) {
463
+ continue;
464
+ }
465
+
466
+ if ($matrix->get($x, $y) === -1) {
467
+ self::embedPositionAdjustmentPattern($x - 2, $y - 2, $matrix);
468
+ }
469
+ }
470
+ }
471
+ }
472
+
473
+ /**
474
+ * Embeds a single position adjustment pattern.
475
+ *
476
+ * @param integer $xStart
477
+ * @param intger $yStart
478
+ * @param ByteMatrix $matrix
479
+ * @return void
480
+ */
481
+ protected static function embedPositionAdjustmentPattern($xStart, $yStart, ByteMatrix $matrix)
482
+ {
483
+ for ($y = 0; $y < 5; $y++) {
484
+ for ($x = 0; $x < 5; $x++) {
485
+ $matrix->set($xStart + $x, $yStart + $y, self::$positionAdjustmentPattern[$y][$x]);
486
+ }
487
+ }
488
+ }
489
+
490
+ /**
491
+ * Embeds timing patterns into a matrix.
492
+ *
493
+ * @param ByteMatrix $matrix
494
+ * @return void
495
+ */
496
+ protected static function embedTimingPatterns(ByteMatrix $matrix)
497
+ {
498
+ $matrixWidth = $matrix->getWidth();
499
+
500
+ for ($i = 8; $i < $matrixWidth - 8; $i++) {
501
+ $bit = ($i + 1) % 2;
502
+
503
+ if ($matrix->get($i, 6) === -1) {
504
+ $matrix->set($i, 6, $bit);
505
+ }
506
+
507
+ if ($matrix->get(6, $i) === -1) {
508
+ $matrix->set(6, $i, $bit);
509
+ }
510
+ }
511
+ }
512
+
513
+ /**
514
+ * Embeds "dataBits" using "getMaskPattern".
515
+ *
516
+ * For debugging purposes, it skips masking process if "getMaskPattern" is
517
+ * -1. See 8.7 of JISX0510:2004 (p.38) for how to embed data bits.
518
+ *
519
+ * @param BitArray $dataBits
520
+ * @param integer $maskPattern
521
+ * @param ByteMatrix $matrix
522
+ * @return void
523
+ * @throws Exception\WriterException
524
+ */
525
+ protected static function embedDataBits(BitArray $dataBits, $maskPattern, ByteMatrix $matrix)
526
+ {
527
+ $bitIndex = 0;
528
+ $direction = -1;
529
+
530
+ // Start from the right bottom cell.
531
+ $x = $matrix->getWidth() - 1;
532
+ $y = $matrix->getHeight() - 1;
533
+
534
+ while ($x > 0) {
535
+ // Skip vertical timing pattern.
536
+ if ($x === 6) {
537
+ $x--;
538
+ }
539
+
540
+ while ($y >= 0 && $y < $matrix->getHeight()) {
541
+ for ($i = 0; $i < 2; $i++) {
542
+ $xx = $x - $i;
543
+
544
+ // Skip the cell if it's not empty.
545
+ if ($matrix->get($xx, $y) !== -1) {
546
+ continue;
547
+ }
548
+
549
+ if ($bitIndex < $dataBits->getSize()) {
550
+ $bit = $dataBits->get($bitIndex);
551
+ $bitIndex++;
552
+ } else {
553
+ // Padding bit. If there is no bit left, we'll fill the
554
+ // left cells with 0, as described in 8.4.9 of
555
+ // JISX0510:2004 (p. 24).
556
+ $bit = false;
557
+ }
558
+
559
+ // Skip masking if maskPattern is -1.
560
+ if ($maskPattern !== -1 && MaskUtil::getDataMaskBit($maskPattern, $xx, $y)) {
561
+ $bit = !$bit;
562
+ }
563
+
564
+ $matrix->set($xx, $y, $bit);
565
+ }
566
+
567
+ $y += $direction;
568
+ }
569
+
570
+ $direction = -$direction;
571
+ $y += $direction;
572
+ $x -= 2;
573
+ }
574
+
575
+ // All bits should be consumed
576
+ if ($bitIndex !== $dataBits->getSize()) {
577
+ throw new Exception\WriterException('Not all bits consumed (' . $bitIndex . ' out of ' . $dataBits->getSize() .')');
578
+ }
579
+ }
580
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Encoder/QrCode.php ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Encoder;
11
+
12
+ use BaconQrCode\Common\ErrorCorrectionLevel;
13
+ use BaconQrCode\Common\Mode;
14
+ use BaconQrCode\Common\Version;
15
+
16
+ /**
17
+ * QR code.
18
+ */
19
+ class QrCode
20
+ {
21
+ /**
22
+ * Number of possible mask patterns.
23
+ */
24
+ const NUM_MASK_PATTERNS = 8;
25
+
26
+ /**
27
+ * Mode of the QR code.
28
+ *
29
+ * @var Mode
30
+ */
31
+ protected $mode;
32
+
33
+ /**
34
+ * EC level of the QR code.
35
+ *
36
+ * @var ErrorCorrectionLevel
37
+ */
38
+ protected $errorCorrectionLevel;
39
+
40
+ /**
41
+ * Version of the QR code.
42
+ *
43
+ * @var Version
44
+ */
45
+ protected $version;
46
+
47
+ /**
48
+ * Mask pattern of the QR code.
49
+ *
50
+ * @var integer
51
+ */
52
+ protected $maskPattern = -1;
53
+
54
+ /**
55
+ * Matrix of the QR code.
56
+ *
57
+ * @var ByteMatrix
58
+ */
59
+ protected $matrix;
60
+
61
+ /**
62
+ * Gets the mode.
63
+ *
64
+ * @return Mode
65
+ */
66
+ public function getMode()
67
+ {
68
+ return $this->mode;
69
+ }
70
+
71
+ /**
72
+ * Sets the mode.
73
+ *
74
+ * @param Mode $mode
75
+ * @return void
76
+ */
77
+ public function setMode(Mode $mode)
78
+ {
79
+ $this->mode = $mode;
80
+ }
81
+
82
+ /**
83
+ * Gets the EC level.
84
+ *
85
+ * @return ErrorCorrectionLevel
86
+ */
87
+ public function getErrorCorrectionLevel()
88
+ {
89
+ return $this->errorCorrectionLevel;
90
+ }
91
+
92
+ /**
93
+ * Sets the EC level.
94
+ *
95
+ * @param ErrorCorrectionLevel $errorCorrectionLevel
96
+ * @return void
97
+ */
98
+ public function setErrorCorrectionLevel(ErrorCorrectionLevel $errorCorrectionLevel)
99
+ {
100
+ $this->errorCorrectionLevel = $errorCorrectionLevel;
101
+ }
102
+
103
+ /**
104
+ * Gets the version.
105
+ *
106
+ * @return Version
107
+ */
108
+ public function getVersion()
109
+ {
110
+ return $this->version;
111
+ }
112
+
113
+ /**
114
+ * Sets the version.
115
+ *
116
+ * @param Version $version
117
+ * @return void
118
+ */
119
+ public function setVersion(Version $version)
120
+ {
121
+ $this->version = $version;
122
+ }
123
+
124
+ /**
125
+ * Gets the mask pattern.
126
+ *
127
+ * @return integer
128
+ */
129
+ public function getMaskPattern()
130
+ {
131
+ return $this->maskPattern;
132
+ }
133
+
134
+ /**
135
+ * Sets the mask pattern.
136
+ *
137
+ * @param integer $maskPattern
138
+ * @return void
139
+ */
140
+ public function setMaskPattern($maskPattern)
141
+ {
142
+ $this->maskPattern = $maskPattern;
143
+ }
144
+
145
+ /**
146
+ * Gets the matrix.
147
+ *
148
+ * @return ByteMatrix
149
+ */
150
+ public function getMatrix()
151
+ {
152
+ return $this->matrix;
153
+ }
154
+
155
+ /**
156
+ * Sets the matrix.
157
+ *
158
+ * @param ByteMatrix $matrix
159
+ * @return void
160
+ */
161
+ public function setMatrix(ByteMatrix $matrix)
162
+ {
163
+ $this->matrix = $matrix;
164
+ }
165
+
166
+ /**
167
+ * Validates whether a mask pattern is valid.
168
+ *
169
+ * @param integer $maskPattern
170
+ * @return boolean
171
+ */
172
+ public static function isValidMaskPattern($maskPattern)
173
+ {
174
+ return $maskPattern > 0 && $maskPattern < self::NUM_MASK_PATTERNS;
175
+ }
176
+
177
+ /**
178
+ * Returns a string representation of the QR code.
179
+ *
180
+ * @return string
181
+ */
182
+ public function __toString()
183
+ {
184
+ $result = "<<\n"
185
+ . " mode: " . $this->mode . "\n"
186
+ . " ecLevel: " . $this->errorCorrectionLevel . "\n"
187
+ . " version: " . $this->version . "\n"
188
+ . " maskPattern: " . $this->maskPattern . "\n";
189
+
190
+ if ($this->matrix === null) {
191
+ $result .= " matrix: null\n";
192
+ } else {
193
+ $result .= " matrix:\n";
194
+ $result .= $this->matrix;
195
+ }
196
+
197
+ $result .= ">>\n";
198
+
199
+ return $result;
200
+ }
201
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/ExceptionInterface.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Exception;
11
+
12
+ interface ExceptionInterface
13
+ {
14
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/InvalidArgumentException.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Exception;
11
+
12
+ class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
13
+ {
14
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/OutOfBoundsException.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Exception;
11
+
12
+ class OutOfBoundsException extends \OutOfBoundsException implements ExceptionInterface
13
+ {
14
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/RuntimeException.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Exception;
11
+
12
+ class RuntimeException extends \RuntimeException implements ExceptionInterface
13
+ {
14
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/UnexpectedValueException.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Exception;
11
+
12
+ class UnexpectedValueException extends \UnexpectedValueException implements ExceptionInterface
13
+ {
14
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Exception/WriterException.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Exception;
11
+
12
+ class WriterException extends \RuntimeException implements ExceptionInterface
13
+ {
14
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/Cmyk.php ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Renderer\Color;
11
+
12
+ use BaconQrCode\Exception;
13
+
14
+ /**
15
+ * CMYK color.
16
+ */
17
+ class Cmyk implements ColorInterface
18
+ {
19
+ /**
20
+ * Cyan value.
21
+ *
22
+ * @var integer
23
+ */
24
+ protected $cyan;
25
+
26
+ /**
27
+ * Magenta value.
28
+ *
29
+ * @var integer
30
+ */
31
+ protected $magenta;
32
+
33
+ /**
34
+ * Yellow value.
35
+ *
36
+ * @var integer
37
+ */
38
+ protected $yellow;
39
+
40
+ /**
41
+ * Black value.
42
+ *
43
+ * @var integer
44
+ */
45
+ protected $black;
46
+
47
+ /**
48
+ * Creates a new CMYK color.
49
+ *
50
+ * @param integer $cyan
51
+ * @param integer $magenta
52
+ * @param integer $yellow
53
+ * @param integer $black
54
+ */
55
+ public function __construct($cyan, $magenta, $yellow, $black)
56
+ {
57
+ if ($cyan < 0 || $cyan > 100) {
58
+ throw new Exception\InvalidArgumentException('Cyan must be between 0 and 100');
59
+ }
60
+
61
+ if ($magenta < 0 || $magenta > 100) {
62
+ throw new Exception\InvalidArgumentException('Magenta must be between 0 and 100');
63
+ }
64
+
65
+ if ($yellow < 0 || $yellow > 100) {
66
+ throw new Exception\InvalidArgumentException('Yellow must be between 0 and 100');
67
+ }
68
+
69
+ if ($black < 0 || $black > 100) {
70
+ throw new Exception\InvalidArgumentException('Black must be between 0 and 100');
71
+ }
72
+
73
+ $this->cyan = (int) $cyan;
74
+ $this->magenta = (int) $magenta;
75
+ $this->yellow = (int) $yellow;
76
+ $this->black = (int) $black;
77
+ }
78
+
79
+ /**
80
+ * Returns the cyan value.
81
+ *
82
+ * @return integer
83
+ */
84
+ public function getCyan()
85
+ {
86
+ return $this->cyan;
87
+ }
88
+
89
+ /**
90
+ * Returns the magenta value.
91
+ *
92
+ * @return integer
93
+ */
94
+ public function getMagenta()
95
+ {
96
+ return $this->magenta;
97
+ }
98
+
99
+ /**
100
+ * Returns the yellow value.
101
+ *
102
+ * @return integer
103
+ */
104
+ public function getYellow()
105
+ {
106
+ return $this->yellow;
107
+ }
108
+
109
+ /**
110
+ * Returns the black value.
111
+ *
112
+ * @return integer
113
+ */
114
+ public function getBlack()
115
+ {
116
+ return $this->black;
117
+ }
118
+
119
+ /**
120
+ * toRgb(): defined by ColorInterface.
121
+ *
122
+ * @see ColorInterface::toRgb()
123
+ * @return Rgb
124
+ */
125
+ public function toRgb()
126
+ {
127
+ $k = $this->black / 100;
128
+ $c = (-$k * $this->cyan + $k * 100 + $this->cyan) / 100;
129
+ $m = (-$k * $this->magenta + $k * 100 + $this->magenta) / 100;
130
+ $y = (-$k * $this->yellow + $k * 100 + $this->yellow) / 100;
131
+
132
+ return new Rgb(
133
+ -$c * 255 + 255,
134
+ -$m * 255 + 255,
135
+ -$y * 255 + 255
136
+ );
137
+ }
138
+
139
+ /**
140
+ * toCmyk(): defined by ColorInterface.
141
+ *
142
+ * @see ColorInterface::toCmyk()
143
+ * @return Cmyk
144
+ */
145
+ public function toCmyk()
146
+ {
147
+ return $this;
148
+ }
149
+
150
+ /**
151
+ * toGray(): defined by ColorInterface.
152
+ *
153
+ * @see ColorInterface::toGray()
154
+ * @return Gray
155
+ */
156
+ public function toGray()
157
+ {
158
+ return $this->toRgb()->toGray();
159
+ }
160
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/ColorInterface.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Renderer\Color;
11
+
12
+ /**
13
+ * Color interface.
14
+ */
15
+ interface ColorInterface
16
+ {
17
+ /**
18
+ * Converts the color to RGB.
19
+ *
20
+ * @return Rgb
21
+ */
22
+ public function toRgb();
23
+
24
+ /**
25
+ * Converts the color to CMYK.
26
+ *
27
+ * @return Cmyk
28
+ */
29
+ public function toCmyk();
30
+
31
+ /**
32
+ * Converts the color to gray.
33
+ *
34
+ * @return Gray
35
+ */
36
+ public function toGray();
37
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/Gray.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Renderer\Color;
11
+
12
+ use BaconQrCode\Exception;
13
+
14
+ /**
15
+ * Gray color.
16
+ */
17
+ class Gray implements ColorInterface
18
+ {
19
+ /**
20
+ * Gray value.
21
+ *
22
+ * @var integer
23
+ */
24
+ protected $gray;
25
+
26
+ /**
27
+ * Creates a new gray color.
28
+ *
29
+ * A low gray value means black, while a high value means white.
30
+ *
31
+ * @param integer $gray
32
+ */
33
+ public function __construct($gray)
34
+ {
35
+ if ($gray < 0 || $gray > 100) {
36
+ throw new Exception\InvalidArgumentException('Gray must be between 0 and 100');
37
+ }
38
+
39
+ $this->gray = (int) $gray;
40
+ }
41
+
42
+ /**
43
+ * Returns the gray value.
44
+ *
45
+ * @return integer
46
+ */
47
+ public function getGray()
48
+ {
49
+ return $this->gray;
50
+ }
51
+
52
+ /**
53
+ * toRgb(): defined by ColorInterface.
54
+ *
55
+ * @see ColorInterface::toRgb()
56
+ * @return Rgb
57
+ */
58
+ public function toRgb()
59
+ {
60
+ return new Rgb($this->gray * 2.55, $this->gray * 2.55, $this->gray * 2.55);
61
+ }
62
+
63
+ /**
64
+ * toCmyk(): defined by ColorInterface.
65
+ *
66
+ * @see ColorInterface::toCmyk()
67
+ * @return Cmyk
68
+ */
69
+ public function toCmyk()
70
+ {
71
+ return new Cmyk(0, 0, 0, 100 - $this->gray);
72
+ }
73
+
74
+ /**
75
+ * toGray(): defined by ColorInterface.
76
+ *
77
+ * @see ColorInterface::toGray()
78
+ * @return Gray
79
+ */
80
+ public function toGray()
81
+ {
82
+ return $this;
83
+ }
84
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/Rgb.php ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Renderer\Color;
11
+
12
+ use BaconQrCode\Exception;
13
+
14
+ /**
15
+ * RGB color.
16
+ */
17
+ class Rgb implements ColorInterface
18
+ {
19
+ /**
20
+ * Red value.
21
+ *
22
+ * @var integer
23
+ */
24
+ protected $red;
25
+
26
+ /**
27
+ * Green value.
28
+ *
29
+ * @var integer
30
+ */
31
+ protected $green;
32
+
33
+ /**
34
+ * Blue value.
35
+ *
36
+ * @var integer
37
+ */
38
+ protected $blue;
39
+
40
+ /**
41
+ * Creates a new RGB color.
42
+ *
43
+ * @param integer $red
44
+ * @param integer $green
45
+ * @param integer $blue
46
+ */
47
+ public function __construct($red, $green, $blue)
48
+ {
49
+ if ($red < 0 || $red > 255) {
50
+ throw new Exception\InvalidArgumentException('Red must be between 0 and 255');
51
+ }
52
+
53
+ if ($green < 0 || $green > 255) {
54
+ throw new Exception\InvalidArgumentException('Green must be between 0 and 255');
55
+ }
56
+
57
+ if ($blue < 0 || $blue > 255) {
58
+ throw new Exception\InvalidArgumentException('Blue must be between 0 and 255');
59
+ }
60
+
61
+ $this->red = (int) $red;
62
+ $this->green = (int) $green;
63
+ $this->blue = (int) $blue;
64
+ }
65
+
66
+ /**
67
+ * Returns the red value.
68
+ *
69
+ * @return integer
70
+ */
71
+ public function getRed()
72
+ {
73
+ return $this->red;
74
+ }
75
+
76
+ /**
77
+ * Returns the green value.
78
+ *
79
+ * @return integer
80
+ */
81
+ public function getGreen()
82
+ {
83
+ return $this->green;
84
+ }
85
+
86
+ /**
87
+ * Returns the blue value.
88
+ *
89
+ * @return integer
90
+ */
91
+ public function getBlue()
92
+ {
93
+ return $this->blue;
94
+ }
95
+
96
+ /**
97
+ * Returns a hexadecimal string representation of the RGB value.
98
+ *
99
+ * @return string
100
+ */
101
+ public function __toString()
102
+ {
103
+ return sprintf('%02x%02x%02x', $this->red, $this->green, $this->blue);
104
+ }
105
+
106
+ /**
107
+ * toRgb(): defined by ColorInterface.
108
+ *
109
+ * @see ColorInterface::toRgb()
110
+ * @return Rgb
111
+ */
112
+ public function toRgb()
113
+ {
114
+ return $this;
115
+ }
116
+
117
+ /**
118
+ * toCmyk(): defined by ColorInterface.
119
+ *
120
+ * @see ColorInterface::toCmyk()
121
+ * @return Cmyk
122
+ */
123
+ public function toCmyk()
124
+ {
125
+ $c = 1 - ($this->red / 255);
126
+ $m = 1 - ($this->green / 255);
127
+ $y = 1 - ($this->blue / 255);
128
+ $k = min($c, $m, $y);
129
+
130
+ return new Cmyk(
131
+ 100 * ($c - $k) / (1 - $k),
132
+ 100 * ($m - $k) / (1 - $k),
133
+ 100 * ($y - $k) / (1 - $k),
134
+ 100 * $k
135
+ );
136
+ }
137
+
138
+ /**
139
+ * toGray(): defined by ColorInterface.
140
+ *
141
+ * @see ColorInterface::toGray()
142
+ * @return Gray
143
+ */
144
+ public function toGray()
145
+ {
146
+ return new Gray(($this->red * 0.21 + $this->green * 0.71 + $this->blue * 0.07) / 2.55);
147
+ }
148
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/AbstractRenderer.php ADDED
@@ -0,0 +1,338 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Renderer\Image;
11
+
12
+ use BaconQrCode\Encoder\QrCode;
13
+ use BaconQrCode\Renderer\Color;
14
+ use BaconQrCode\Renderer\Image\Decorator\DecoratorInterface;
15
+ use BaconQrCode\Exception;
16
+
17
+ /**
18
+ * Image renderer, supporting multiple backends.
19
+ */
20
+ abstract class AbstractRenderer implements RendererInterface
21
+ {
22
+ /**
23
+ * Margin around the QR code, also known as quiet zone.
24
+ *
25
+ * @var integer
26
+ */
27
+ protected $margin = 4;
28
+
29
+ /**
30
+ * Requested width of the rendered image.
31
+ *
32
+ * @var integer
33
+ */
34
+ protected $width = 0;
35
+
36
+ /**
37
+ * Requested height of the rendered image.
38
+ *
39
+ * @var integer
40
+ */
41
+ protected $height = 0;
42
+
43
+ /**
44
+ * Whether dimensions should be rounded down.
45
+ *
46
+ * @var boolean
47
+ */
48
+ protected $roundDimensions = true;
49
+
50
+ /**
51
+ * Final width of the image.
52
+ *
53
+ * @var integer
54
+ */
55
+ protected $finalWidth;
56
+
57
+ /**
58
+ * Final height of the image.
59
+ *
60
+ * @var integer
61
+ */
62
+ protected $finalHeight;
63
+
64
+ /**
65
+ * Size of each individual block.
66
+ *
67
+ * @var integer
68
+ */
69
+ protected $blockSize;
70
+
71
+ /**
72
+ * Background color.
73
+ *
74
+ * @var Color\ColorInterface
75
+ */
76
+ protected $backgroundColor;
77
+
78
+ /**
79
+ * Whether dimensions should be rounded down
80
+ *
81
+ * @var boolean
82
+ */
83
+ protected $floorToClosestDimension;
84
+
85
+ /**
86
+ * Foreground color.
87
+ *
88
+ * @var Color\ColorInterface
89
+ */
90
+ protected $foregroundColor;
91
+
92
+ /**
93
+ * Decorators used on QR codes.
94
+ *
95
+ * @var array
96
+ */
97
+ protected $decorators = array();
98
+
99
+ /**
100
+ * Sets the margin around the QR code.
101
+ *
102
+ * @param integer $margin
103
+ * @return AbstractRenderer
104
+ * @throws Exception\InvalidArgumentException
105
+ */
106
+ public function setMargin($margin)
107
+ {
108
+ if ($margin < 0) {
109
+ throw new Exception\InvalidArgumentException('Margin must be equal to greater than 0');
110
+ }
111
+
112
+ $this->margin = (int) $margin;
113
+ return $this;
114
+ }
115
+
116
+ /**
117
+ * Gets the margin around the QR code.
118
+ *
119
+ * @return integer
120
+ */
121
+ public function getMargin()
122
+ {
123
+ return $this->margin;
124
+ }
125
+
126
+ /**
127
+ * Sets the height around the renderd image.
128
+ *
129
+ * If the width is smaller than the matrix width plus padding, the renderer
130
+ * will automatically use that as the width instead of the specified one.
131
+ *
132
+ * @param integer $width
133
+ * @return AbstractRenderer
134
+ */
135
+ public function setWidth($width)
136
+ {
137
+ $this->width = (int) $width;
138
+ return $this;
139
+ }
140
+
141
+ /**
142
+ * Gets the width of the rendered image.
143
+ *
144
+ * @return integer
145
+ */
146
+ public function getWidth()
147
+ {
148
+ return $this->width;
149
+ }
150
+
151
+ /**
152
+ * Sets the height around the renderd image.
153
+ *
154
+ * If the height is smaller than the matrix height plus padding, the
155
+ * renderer will automatically use that as the height instead of the
156
+ * specified one.
157
+ *
158
+ * @param integer $height
159
+ * @return AbstractRenderer
160
+ */
161
+ public function setHeight($height)
162
+ {
163
+ $this->height = (int) $height;
164
+ return $this;
165
+ }
166
+
167
+ /**
168
+ * Gets the height around the rendered image.
169
+ *
170
+ * @return integer
171
+ */
172
+ public function getHeight()
173
+ {
174
+ return $this->height;
175
+ }
176
+
177
+ /**
178
+ * Sets whether dimensions should be rounded down.
179
+ *
180
+ * @param boolean $flag
181
+ * @return AbstractRenderer
182
+ */
183
+ public function setRoundDimensions($flag)
184
+ {
185
+ $this->floorToClosestDimension = $flag;
186
+ return $this;
187
+ }
188
+
189
+ /**
190
+ * Gets whether dimensions should be rounded down.
191
+ *
192
+ * @return boolean
193
+ */
194
+ public function shouldRoundDimensions()
195
+ {
196
+ return $this->floorToClosestDimension;
197
+ }
198
+
199
+ /**
200
+ * Sets background color.
201
+ *
202
+ * @param Color\ColorInterface $color
203
+ * @return AbstractRenderer
204
+ */
205
+ public function setBackgroundColor(Color\ColorInterface $color)
206
+ {
207
+ $this->backgroundColor = $color;
208
+ return $this;
209
+ }
210
+
211
+ /**
212
+ * Gets background color.
213
+ *
214
+ * @return Color\ColorInterface
215
+ */
216
+ public function getBackgroundColor()
217
+ {
218
+ if ($this->backgroundColor === null) {
219
+ $this->backgroundColor = new Color\Gray(100);
220
+ }
221
+
222
+ return $this->backgroundColor;
223
+ }
224
+
225
+ /**
226
+ * Sets foreground color.
227
+ *
228
+ * @param Color\ColorInterface $color
229
+ * @return AbstractRenderer
230
+ */
231
+ public function setForegroundColor(Color\ColorInterface $color)
232
+ {
233
+ $this->foregroundColor = $color;
234
+ return $this;
235
+ }
236
+
237
+ /**
238
+ * Gets foreground color.
239
+ *
240
+ * @return Color\ColorInterface
241
+ */
242
+ public function getForegroundColor()
243
+ {
244
+ if ($this->foregroundColor === null) {
245
+ $this->foregroundColor = new Color\Gray(0);
246
+ }
247
+
248
+ return $this->foregroundColor;
249
+ }
250
+
251
+ /**
252
+ * Adds a decorator to the renderer.
253
+ *
254
+ * @param DecoratorInterface $decorator
255
+ * @return AbstractRenderer
256
+ */
257
+ public function addDecorator(DecoratorInterface $decorator)
258
+ {
259
+ $this->decorators[] = $decorator;
260
+ return $this;
261
+ }
262
+
263
+ /**
264
+ * render(): defined by RendererInterface.
265
+ *
266
+ * @see RendererInterface::render()
267
+ * @param QrCode $qrCode
268
+ * @return string
269
+ */
270
+ public function render(QrCode $qrCode)
271
+ {
272
+ $input = $qrCode->getMatrix();
273
+ $inputWidth = $input->getWidth();
274
+ $inputHeight = $input->getHeight();
275
+ $qrWidth = $inputWidth + ($this->getMargin() << 1);
276
+ $qrHeight = $inputHeight + ($this->getMargin() << 1);
277
+ $outputWidth = max($this->getWidth(), $qrWidth);
278
+ $outputHeight = max($this->getHeight(), $qrHeight);
279
+ $multiple = (int) min($outputWidth / $qrWidth, $outputHeight / $qrHeight);
280
+
281
+ if ($this->shouldRoundDimensions()) {
282
+ $outputWidth -= $outputWidth % $multiple;
283
+ $outputHeight -= $outputHeight % $multiple;
284
+ }
285
+
286
+ // Padding includes both the quiet zone and the extra white pixels to
287
+ // accommodate the requested dimensions. For example, if input is 25x25
288
+ // the QR will be 33x33 including the quiet zone. If the requested size
289
+ // is 200x160, the multiple will be 4, for a QR of 132x132. These will
290
+ // handle all the padding from 100x100 (the actual QR) up to 200x160.
291
+ $leftPadding = (int) (($outputWidth - ($inputWidth * $multiple)) / 2);
292
+ $topPadding = (int) (($outputHeight - ($inputHeight * $multiple)) / 2);
293
+
294
+ // Store calculated parameters
295
+ $this->finalWidth = $outputWidth;
296
+ $this->finalHeight = $outputHeight;
297
+ $this->blockSize = $multiple;
298
+
299
+ $this->init();
300
+ $this->addColor('background', $this->getBackgroundColor());
301
+ $this->addColor('foreground', $this->getForegroundColor());
302
+ $this->drawBackground('background');
303
+
304
+ foreach ($this->decorators as $decorator) {
305
+ $decorator->preProcess(
306
+ $qrCode,
307
+ $this,
308
+ $outputWidth,
309
+ $outputHeight,
310
+ $leftPadding,
311
+ $topPadding,
312
+ $multiple
313
+ );
314
+ }
315
+
316
+ for ($inputY = 0, $outputY = $topPadding; $inputY < $inputHeight; $inputY++, $outputY += $multiple) {
317
+ for ($inputX = 0, $outputX = $leftPadding; $inputX < $inputWidth; $inputX++, $outputX += $multiple) {
318
+ if ($input->get($inputX, $inputY) === 1) {
319
+ $this->drawBlock($outputX, $outputY, 'foreground');
320
+ }
321
+ }
322
+ }
323
+
324
+ foreach ($this->decorators as $decorator) {
325
+ $decorator->postProcess(
326
+ $qrCode,
327
+ $this,
328
+ $outputWidth,
329
+ $outputHeight,
330
+ $leftPadding,
331
+ $topPadding,
332
+ $multiple
333
+ );
334
+ }
335
+
336
+ return $this->getByteStream();
337
+ }
338
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Decorator/DecoratorInterface.php ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Renderer\Image\Decorator;
11
+
12
+ use BaconQrCode\Encoder\QrCode;
13
+ use BaconQrCode\Renderer\Image\RendererInterface;
14
+
15
+ /**
16
+ * Decorator interface.
17
+ */
18
+ interface DecoratorInterface
19
+ {
20
+ /**
21
+ * Pre-process a QR code.
22
+ *
23
+ * @param QrCode $qrCode
24
+ * @param RendererInterface $renderer
25
+ * @param integer $outputWidth
26
+ * @param integer $outputHeight
27
+ * @param integer $leftPadding
28
+ * @param integer $topPadding
29
+ * @param integer $multiple
30
+ * @return void
31
+ */
32
+ public function preProcess(
33
+ QrCode $qrCode,
34
+ RendererInterface $renderer,
35
+ $outputWidth,
36
+ $outputHeight,
37
+ $leftPadding,
38
+ $topPadding,
39
+ $multiple
40
+ );
41
+
42
+ /**
43
+ * Post-process a QR code.
44
+ *
45
+ * @param QrCode $qrCode
46
+ * @param RendererInterface $renderer
47
+ * @param integer $outputWidth
48
+ * @param integer $outputHeight
49
+ * @param integer $leftPadding
50
+ * @param integer $topPadding
51
+ * @param integer $multiple
52
+ * @return void
53
+ */
54
+ public function postProcess(
55
+ QrCode $qrCode,
56
+ RendererInterface $renderer,
57
+ $outputWidth,
58
+ $outputHeight,
59
+ $leftPadding,
60
+ $topPadding,
61
+ $multiple
62
+ );
63
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Decorator/FinderPattern.php ADDED
@@ -0,0 +1,210 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Renderer\Image\Decorator;
11
+
12
+ use BaconQrCode\Encoder\QrCode;
13
+ use BaconQrCode\Renderer\Image\RendererInterface;
14
+ use BaconQrCode\Renderer\Color;
15
+
16
+ /**
17
+ * Finder pattern decorator.
18
+ */
19
+ class FinderPattern implements DecoratorInterface
20
+ {
21
+ /**
22
+ * @var Color\ColorInterface
23
+ */
24
+ protected $innerColor;
25
+
26
+ /**
27
+ * @varColor\ColorInterface
28
+ */
29
+ protected $outerColor;
30
+
31
+ /**
32
+ * Outer position detection pattern.
33
+ *
34
+ * @var array
35
+ */
36
+ protected static $outerPositionDetectionPattern = array(
37
+ array(1, 1, 1, 1, 1, 1, 1),
38
+ array(1, 0, 0, 0, 0, 0, 1),
39
+ array(1, 0, 0, 0, 0, 0, 1),
40
+ array(1, 0, 0, 0, 0, 0, 1),
41
+ array(1, 0, 0, 0, 0, 0, 1),
42
+ array(1, 0, 0, 0, 0, 0, 1),
43
+ array(1, 1, 1, 1, 1, 1, 1),
44
+ );
45
+
46
+ /**
47
+ * Inner position detection pattern.
48
+ *
49
+ * @var array
50
+ */
51
+ protected static $innerPositionDetectionPattern = array(
52
+ array(0, 0, 0, 0, 0, 0, 0),
53
+ array(0, 0, 0, 0, 0, 0, 0),
54
+ array(0, 0, 1, 1, 1, 0, 0),
55
+ array(0, 0, 1, 1, 1, 0, 0),
56
+ array(0, 0, 1, 1, 1, 0, 0),
57
+ array(0, 0, 0, 0, 0, 0, 0),
58
+ array(0, 0, 0, 0, 0, 0, 0),
59
+ );
60
+
61
+ /**
62
+ * Sets outer color.
63
+ *
64
+ * @param Color\ColorInterface $color
65
+ * @return FinderPattern
66
+ */
67
+ public function setOuterColor(Color\ColorInterface $color)
68
+ {
69
+ $this->outerColor = $color;
70
+ return $this;
71
+ }
72
+
73
+ /**
74
+ * Gets outer color.
75
+ *
76
+ * @return Color\ColorInterface
77
+ */
78
+ public function getOuterColor()
79
+ {
80
+ if ($this->outerColor === null) {
81
+ $this->outerColor = new Color\Gray(100);
82
+ }
83
+
84
+ return $this->outerColor;
85
+ }
86
+
87
+ /**
88
+ * Sets inner color.
89
+ *
90
+ * @param Color\ColorInterface $color
91
+ * @return FinderPattern
92
+ */
93
+ public function setInnerColor(Color\ColorInterface $color)
94
+ {
95
+ $this->innerColor = $color;
96
+ return $this;
97
+ }
98
+
99
+ /**
100
+ * Gets inner color.
101
+ *
102
+ * @return Color\ColorInterface
103
+ */
104
+ public function getInnerColor()
105
+ {
106
+ if ($this->innerColor === null) {
107
+ $this->innerColor = new Color\Gray(0);
108
+ }
109
+
110
+ return $this->innerColor;
111
+ }
112
+
113
+ /**
114
+ * preProcess(): defined by DecoratorInterface.
115
+ *
116
+ * @see DecoratorInterface::preProcess()
117
+ * @param QrCode $qrCode
118
+ * @param RendererInterface $renderer
119
+ * @param integer $outputWidth
120
+ * @param integer $outputHeight
121
+ * @param integer $leftPadding
122
+ * @param integer $topPadding
123
+ * @param integer $multiple
124
+ * @return void
125
+ */
126
+ public function preProcess(
127
+ QrCode $qrCode,
128
+ RendererInterface $renderer,
129
+ $outputWidth,
130
+ $outputHeight,
131
+ $leftPadding,
132
+ $topPadding,
133
+ $multiple
134
+ ) {
135
+ $matrix = $qrCode->getMatrix();
136
+ $positions = array(
137
+ array(0, 0),
138
+ array($matrix->getWidth() - 7, 0),
139
+ array(0, $matrix->getHeight() - 7),
140
+ );
141
+
142
+ foreach (self::$outerPositionDetectionPattern as $y => $row) {
143
+ foreach ($row as $x => $isSet) {
144
+ foreach ($positions as $position) {
145
+ $matrix->set($x + $position[0], $y + $position[1], 0);
146
+ }
147
+ }
148
+ }
149
+ }
150
+
151
+ /**
152
+ * postProcess(): defined by DecoratorInterface.
153
+ *
154
+ * @see DecoratorInterface::postProcess()
155
+ *
156
+ * @param QrCode $qrCode
157
+ * @param RendererInterface $renderer
158
+ * @param integer $outputWidth
159
+ * @param integer $outputHeight
160
+ * @param integer $leftPadding
161
+ * @param integer $topPadding
162
+ * @param integer $multiple
163
+ * @return void
164
+ */
165
+ public function postProcess(
166
+ QrCode $qrCode,
167
+ RendererInterface $renderer,
168
+ $outputWidth,
169
+ $outputHeight,
170
+ $leftPadding,
171
+ $topPadding,
172
+ $multiple
173
+ ) {
174
+ $matrix = $qrCode->getMatrix();
175
+ $positions = array(
176
+ array(0, 0),
177
+ array($matrix->getWidth() - 7, 0),
178
+ array(0, $matrix->getHeight() - 7),
179
+ );
180
+
181
+ $renderer->addColor('finder-outer', $this->getOuterColor());
182
+ $renderer->addColor('finder-inner', $this->getInnerColor());
183
+
184
+ foreach (self::$outerPositionDetectionPattern as $y => $row) {
185
+ foreach ($row as $x => $isOuterSet) {
186
+ $isInnerSet = self::$innerPositionDetectionPattern[$y][$x];
187
+
188
+ if ($isOuterSet) {
189
+ foreach ($positions as $position) {
190
+ $renderer->drawBlock(
191
+ $leftPadding + $x * $multiple + $position[0] * $multiple,
192
+ $topPadding + $y * $multiple + $position[1] * $multiple,
193
+ 'finder-outer'
194
+ );
195
+ }
196
+ }
197
+
198
+ if ($isInnerSet) {
199
+ foreach ($positions as $position) {
200
+ $renderer->drawBlock(
201
+ $leftPadding + $x * $multiple + $position[0] * $multiple,
202
+ $topPadding + $y * $multiple + $position[1] * $multiple,
203
+ 'finder-inner'
204
+ );
205
+ }
206
+ }
207
+ }
208
+ }
209
+ }
210
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Eps.php ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Renderer\Image;
11
+
12
+ use BaconQrCode\Renderer\Color\ColorInterface;
13
+ use BaconQrCode\Renderer\Color\Rgb;
14
+ use BaconQrCode\Renderer\Color\Cmyk;
15
+ use BaconQrCode\Renderer\Color\Gray;
16
+
17
+ /**
18
+ * EPS backend.
19
+ */
20
+ class Eps extends AbstractRenderer
21
+ {
22
+ /**
23
+ * EPS string.
24
+ *
25
+ * @var string
26
+ */
27
+ protected $eps;
28
+
29
+ /**
30
+ * Colors used for drawing.
31
+ *
32
+ * @var array
33
+ */
34
+ protected $colors = array();
35
+
36
+ /**
37
+ * Current color.
38
+ *
39
+ * @var string
40
+ */
41
+ protected $currentColor;
42
+
43
+ /**
44
+ * init(): defined by RendererInterface.
45
+ *
46
+ * @see ImageRendererInterface::init()
47
+ * @return void
48
+ */
49
+ public function init()
50
+ {
51
+ $this->eps = "%!PS-Adobe-3.0 EPSF-3.0\n"
52
+ . "%%BoundingBox: 0 0 " . $this->finalWidth . " " . $this->finalHeight . "\n"
53
+ . "/F { rectfill } def\n";
54
+ }
55
+
56
+ /**
57
+ * addColor(): defined by RendererInterface.
58
+ *
59
+ * @see ImageRendererInterface::addColor()
60
+ * @param string $id
61
+ * @param ColorInterface $color
62
+ * @return void
63
+ */
64
+ public function addColor($id, ColorInterface $color)
65
+ {
66
+ if (
67
+ !$color instanceof Rgb
68
+ && !$color instanceof Cmyk
69
+ && !$color instanceof Gray
70
+ ) {
71
+ $color = $color->toCmyk();
72
+ }
73
+
74
+ $this->colors[$id] = $color;
75
+ }
76
+
77
+ /**
78
+ * drawBackground(): defined by RendererInterface.
79
+ *
80
+ * @see ImageRendererInterface::drawBackground()
81
+ * @param string $colorId
82
+ * @return void
83
+ */
84
+ public function drawBackground($colorId)
85
+ {
86
+ $this->setColor($colorId);
87
+ $this->eps .= "0 0 " . $this->finalWidth . " " . $this->finalHeight . " F\n";
88
+ }
89
+
90
+ /**
91
+ * drawBlock(): defined by RendererInterface.
92
+ *
93
+ * @see ImageRendererInterface::drawBlock()
94
+ * @param integer $x
95
+ * @param integer $y
96
+ * @param string $colorId
97
+ * @return void
98
+ */
99
+ public function drawBlock($x, $y, $colorId)
100
+ {
101
+ $this->setColor($colorId);
102
+ $this->eps .= $x . " " . ($this->finalHeight - $y - $this->blockSize) . " " . $this->blockSize . " " . $this->blockSize . " F\n";
103
+ }
104
+
105
+ /**
106
+ * getByteStream(): defined by RendererInterface.
107
+ *
108
+ * @see ImageRendererInterface::getByteStream()
109
+ * @return string
110
+ */
111
+ public function getByteStream()
112
+ {
113
+ return $this->eps;
114
+ }
115
+
116
+ /**
117
+ * Sets color to use.
118
+ *
119
+ * @param string $colorId
120
+ * @return void
121
+ */
122
+ protected function setColor($colorId)
123
+ {
124
+ if ($colorId !== $this->currentColor) {
125
+ $color = $this->colors[$colorId];
126
+
127
+ if ($color instanceof Rgb) {
128
+ $this->eps .= sprintf(
129
+ "%F %F %F setrgbcolor\n",
130
+ $color->getRed() / 100,
131
+ $color->getGreen() / 100,
132
+ $color->getBlue() / 100
133
+ );
134
+ } elseif ($color instanceof Cmyk) {
135
+ $this->eps .= sprintf(
136
+ "%F %F %F %F setcmykcolor\n",
137
+ $color->getCyan() / 100,
138
+ $color->getMagenta() / 100,
139
+ $color->getYellow() / 100,
140
+ $color->getBlack() / 100
141
+ );
142
+ } elseif ($color instanceof Gray) {
143
+ $this->eps .= sprintf(
144
+ "%F setgray\n",
145
+ $color->getGray() / 100
146
+ );
147
+ }
148
+
149
+ $this->currentColor = $colorId;
150
+ }
151
+ }
152
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Png.php ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Renderer\Image;
11
+
12
+ use BaconQrCode\Exception;
13
+ use BaconQrCode\Renderer\Color\ColorInterface;
14
+
15
+ /**
16
+ * PNG backend.
17
+ */
18
+ class Png extends AbstractRenderer
19
+ {
20
+ /**
21
+ * Image resource used when drawing.
22
+ *
23
+ * @var resource
24
+ */
25
+ protected $image;
26
+
27
+ /**
28
+ * Colors used for drawing.
29
+ *
30
+ * @var array
31
+ */
32
+ protected $colors = array();
33
+
34
+ /**
35
+ * init(): defined by RendererInterface.
36
+ *
37
+ * @see ImageRendererInterface::init()
38
+ * @return void
39
+ */
40
+ public function init()
41
+ {
42
+ $this->image = imagecreatetruecolor($this->finalWidth, $this->finalHeight);
43
+ }
44
+
45
+ /**
46
+ * addColor(): defined by RendererInterface.
47
+ *
48
+ * @see ImageRendererInterface::addColor()
49
+ * @param string $id
50
+ * @param ColorInterface $color
51
+ * @return void
52
+ * @throws Exception\RuntimeException
53
+ */
54
+ public function addColor($id, ColorInterface $color)
55
+ {
56
+ if ($this->image === null) {
57
+ throw new Exception\RuntimeException('Colors can only be added after init');
58
+ }
59
+
60
+ $color = $color->toRgb();
61
+
62
+ $this->colors[$id] = imagecolorallocate(
63
+ $this->image,
64
+ $color->getRed(),
65
+ $color->getGreen(),
66
+ $color->getBlue()
67
+ );
68
+ }
69
+
70
+ /**
71
+ * drawBackground(): defined by RendererInterface.
72
+ *
73
+ * @see ImageRendererInterface::drawBackground()
74
+ * @param string $colorId
75
+ * @return void
76
+ */
77
+ public function drawBackground($colorId)
78
+ {
79
+ imagefill($this->image, 0, 0, $this->colors[$colorId]);
80
+ }
81
+
82
+ /**
83
+ * drawBlock(): defined by RendererInterface.
84
+ *
85
+ * @see ImageRendererInterface::drawBlock()
86
+ * @param integer $x
87
+ * @param integer $y
88
+ * @param string $colorId
89
+ * @return void
90
+ */
91
+ public function drawBlock($x, $y, $colorId)
92
+ {
93
+ imagefilledrectangle(
94
+ $this->image,
95
+ $x,
96
+ $y,
97
+ $x + $this->blockSize - 1,
98
+ $y + $this->blockSize - 1,
99
+ $this->colors[$colorId]
100
+ );
101
+ }
102
+
103
+ /**
104
+ * getByteStream(): defined by RendererInterface.
105
+ *
106
+ * @see ImageRendererInterface::getByteStream()
107
+ * @return string
108
+ */
109
+ public function getByteStream()
110
+ {
111
+ ob_start();
112
+ imagepng($this->image);
113
+ return ob_get_clean();
114
+ }
115
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/RendererInterface.php ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Renderer\Image;
11
+
12
+ use BaconQrCode\Renderer\Color\ColorInterface;
13
+ use BaconQrCode\Renderer\RendererInterface as GeneralRendererInterface;
14
+
15
+ /**
16
+ * Renderer interface.
17
+ */
18
+ interface RendererInterface extends GeneralRendererInterface
19
+ {
20
+ /**
21
+ * Initiates the drawing area.
22
+ *
23
+ * @return void
24
+ */
25
+ public function init();
26
+
27
+ /**
28
+ * Adds a color to the drawing area.
29
+ *
30
+ * @param string $id
31
+ * @param ColorInterface $color
32
+ * @return void
33
+ */
34
+ public function addColor($id, ColorInterface $color);
35
+
36
+ /**
37
+ * Draws the background.
38
+ *
39
+ * @param string $colorId
40
+ * @return void
41
+ */
42
+ public function drawBackground($colorId);
43
+
44
+ /**
45
+ * Draws a block at a specified position.
46
+ *
47
+ * @param integer $x
48
+ * @param integer $y
49
+ * @param string $colorId
50
+ * @return void
51
+ */
52
+ public function drawBlock($x, $y, $colorId);
53
+
54
+ /**
55
+ * Returns the byte stream representing the QR code.
56
+ *
57
+ * @return string
58
+ */
59
+ public function getByteStream();
60
+
61
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Svg.php ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Renderer\Image;
11
+
12
+ use BaconQrCode\Exception;
13
+ use BaconQrCode\Renderer\Color\ColorInterface;
14
+ use SimpleXMLElement;
15
+
16
+ /**
17
+ * SVG backend.
18
+ */
19
+ class Svg extends AbstractRenderer
20
+ {
21
+ /**
22
+ * SVG resource.
23
+ *
24
+ * @var SimpleXMLElement
25
+ */
26
+ protected $svg;
27
+
28
+ /**
29
+ * Colors used for drawing.
30
+ *
31
+ * @var array
32
+ */
33
+ protected $colors = array();
34
+
35
+ /**
36
+ * Prototype IDs.
37
+ *
38
+ * @var array
39
+ */
40
+ protected $prototypeIds = array();
41
+
42
+ /**
43
+ * init(): defined by RendererInterface.
44
+ *
45
+ * @see ImageRendererInterface::init()
46
+ * @return void
47
+ */
48
+ public function init()
49
+ {
50
+ $this->svg = new SimpleXMLElement(
51
+ '<?xml version="1.0" encoding="UTF-8"?>'
52
+ . '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"/>'
53
+ );
54
+ $this->svg->addAttribute('version', '1.1');
55
+ $this->svg->addAttribute('width', $this->finalWidth . 'px');
56
+ $this->svg->addAttribute('height', $this->finalHeight . 'px');
57
+ $this->svg->addAttribute('viewBox', '0 0 ' . $this->finalWidth . ' ' . $this->finalHeight);
58
+ $this->svg->addChild('defs');
59
+ }
60
+
61
+ /**
62
+ * addColor(): defined by RendererInterface.
63
+ *
64
+ * @see ImageRendererInterface::addColor()
65
+ * @param string $id
66
+ * @param ColorInterface $color
67
+ * @return void
68
+ * @throws Exception\InvalidArgumentException
69
+ */
70
+ public function addColor($id, ColorInterface $color)
71
+ {
72
+ $this->colors[$id] = (string) $color->toRgb();
73
+ }
74
+
75
+ /**
76
+ * drawBackground(): defined by RendererInterface.
77
+ *
78
+ * @see ImageRendererInterface::drawBackground()
79
+ * @param string $colorId
80
+ * @return void
81
+ */
82
+ public function drawBackground($colorId)
83
+ {
84
+ $rect = $this->svg->addChild('rect');
85
+ $rect->addAttribute('x', 0);
86
+ $rect->addAttribute('y', 0);
87
+ $rect->addAttribute('width', $this->finalWidth);
88
+ $rect->addAttribute('height', $this->finalHeight);
89
+ $rect->addAttribute('fill', '#' . $this->colors[$colorId]);
90
+ }
91
+
92
+ /**
93
+ * drawBlock(): defined by RendererInterface.
94
+ *
95
+ * @see ImageRendererInterface::drawBlock()
96
+ * @param integer $x
97
+ * @param integer $y
98
+ * @param string $colorId
99
+ * @return void
100
+ */
101
+ public function drawBlock($x, $y, $colorId)
102
+ {
103
+ $use = $this->svg->addChild('use');
104
+ $use->addAttribute('x', $x);
105
+ $use->addAttribute('y', $y);
106
+ $use->addAttribute(
107
+ 'xlink:href',
108
+ $this->getRectPrototypeId($colorId),
109
+ 'http://www.w3.org/1999/xlink'
110
+ );
111
+ }
112
+
113
+ /**
114
+ * getByteStream(): defined by RendererInterface.
115
+ *
116
+ * @see ImageRendererInterface::getByteStream()
117
+ * @return string
118
+ */
119
+ public function getByteStream()
120
+ {
121
+ return $this->svg->asXML();
122
+ }
123
+
124
+ /**
125
+ * Get the prototype ID for a color.
126
+ *
127
+ * @param integer $colorId
128
+ * @return string
129
+ */
130
+ protected function getRectPrototypeId($colorId)
131
+ {
132
+ if (!isset($this->prototypeIds[$colorId])) {
133
+ $id = 'r' . dechex(count($this->prototypeIds));
134
+
135
+ $rect = $this->svg->defs->addChild('rect');
136
+ $rect->addAttribute('id', $id);
137
+ $rect->addAttribute('width', $this->blockSize);
138
+ $rect->addAttribute('height', $this->blockSize);
139
+ $rect->addAttribute('fill', '#' . $this->colors[$colorId]);
140
+
141
+ $this->prototypeIds[$colorId] = '#' . $id;
142
+ }
143
+
144
+ return $this->prototypeIds[$colorId];
145
+ }
146
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/RendererInterface.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Renderer;
11
+
12
+ use BaconQrCode\Encoder\QrCode;
13
+
14
+ /**
15
+ * Renderer interface.
16
+ */
17
+ interface RendererInterface
18
+ {
19
+ /**
20
+ * Renders a QR code.
21
+ *
22
+ * @param QrCode $qrCode
23
+ * @return string
24
+ */
25
+ public function render(QrCode $qrCode);
26
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Text/Html.php ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Renderer\Text;
11
+
12
+ use BaconQrCode\Encoder\QrCode;
13
+
14
+ /**
15
+ * Html renderer.
16
+ */
17
+ class Html extends Plain
18
+ {
19
+ /**
20
+ * HTML CSS class attribute value.
21
+ *
22
+ * @var string
23
+ */
24
+ protected $class = '';
25
+
26
+ /**
27
+ * HTML CSS style definition for the code element.
28
+ *
29
+ * @var string
30
+ */
31
+ protected $style = 'font-family: monospace; line-height: 0.65em; letter-spacing: -1px';
32
+
33
+ /**
34
+ * Set CSS class name.
35
+ *
36
+ * @param string $class
37
+ */
38
+ public function setClass($class)
39
+ {
40
+ $this->class = $class;
41
+ }
42
+
43
+ /**
44
+ * Get CSS class name.
45
+ *
46
+ * @return string
47
+ */
48
+ public function getClass()
49
+ {
50
+ return $this->class;
51
+ }
52
+
53
+ /**
54
+ * Set CSS style value.
55
+ *
56
+ * @param string $style
57
+ */
58
+ public function setStyle($style)
59
+ {
60
+ $this->style = $style;
61
+ }
62
+
63
+ /**
64
+ * Get CSS style value.
65
+ *
66
+ * @return string
67
+ */
68
+ public function getStyle()
69
+ {
70
+ return $this->style;
71
+ }
72
+
73
+ /**
74
+ * render(): defined by RendererInterface.
75
+ *
76
+ * @see RendererInterface::render()
77
+ * @param QrCode $qrCode
78
+ * @return string
79
+ */
80
+ public function render(QrCode $qrCode)
81
+ {
82
+ $textCode = parent::render($qrCode);
83
+
84
+ $result = '<pre'
85
+ . ' style="' . htmlspecialchars($this->style, ENT_QUOTES, 'utf-8') . '"'
86
+ . ' class="' . htmlspecialchars($this->class, ENT_QUOTES, 'utf-8') . '"'
87
+ . '>' . $textCode . '</pre>';
88
+
89
+ return $result;
90
+ }
91
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Text/Plain.php ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode\Renderer\Text;
11
+
12
+ use BaconQrCode\Exception;
13
+ use BaconQrCode\Encoder\QrCode;
14
+ use BaconQrCode\Renderer\RendererInterface;
15
+
16
+ /**
17
+ * Plaintext renderer.
18
+ */
19
+ class Plain implements RendererInterface
20
+ {
21
+ /**
22
+ * Margin around the QR code, also known as quiet zone.
23
+ *
24
+ * @var integer
25
+ */
26
+ protected $margin = 1;
27
+
28
+ /**
29
+ * Char used for full block.
30
+ *
31
+ * UTF-8 FULL BLOCK (U+2588)
32
+ *
33
+ * @var string
34
+ * @link http://www.fileformat.info/info/unicode/char/2588/index.htm
35
+ */
36
+ protected $fullBlock = "\xE2\x96\x88";
37
+
38
+ /**
39
+ * Char used for empty space
40
+ *
41
+ * @var string
42
+ */
43
+ protected $emptyBlock = ' ';
44
+
45
+ /**
46
+ * Set char used as full block (occupied space, "black").
47
+ *
48
+ * @param string $fullBlock
49
+ */
50
+ public function setFullBlock($fullBlock)
51
+ {
52
+ $this->fullBlock = $fullBlock;
53
+ }
54
+
55
+ /**
56
+ * Get char used as full block (occupied space, "black").
57
+ *
58
+ * @return string
59
+ */
60
+ public function getFullBlock()
61
+ {
62
+ return $this->fullBlock;
63
+ }
64
+
65
+ /**
66
+ * Set char used as empty block (empty space, "white").
67
+ *
68
+ * @param string $emptyBlock
69
+ */
70
+ public function setEmptyBlock($emptyBlock)
71
+ {
72
+ $this->emptyBlock = $emptyBlock;
73
+ }
74
+
75
+ /**
76
+ * Get char used as empty block (empty space, "white").
77
+ *
78
+ * @return string
79
+ */
80
+ public function getEmptyBlock()
81
+ {
82
+ return $this->emptyBlock;
83
+ }
84
+
85
+ /**
86
+ * Sets the margin around the QR code.
87
+ *
88
+ * @param integer $margin
89
+ * @return AbstractRenderer
90
+ * @throws Exception\InvalidArgumentException
91
+ */
92
+ public function setMargin($margin)
93
+ {
94
+ if ($margin < 0) {
95
+ throw new Exception\InvalidArgumentException('Margin must be equal to greater than 0');
96
+ }
97
+
98
+ $this->margin = (int) $margin;
99
+
100
+ return $this;
101
+ }
102
+
103
+ /**
104
+ * Gets the margin around the QR code.
105
+ *
106
+ * @return integer
107
+ */
108
+ public function getMargin()
109
+ {
110
+ return $this->margin;
111
+ }
112
+
113
+ /**
114
+ * render(): defined by RendererInterface.
115
+ *
116
+ * @see RendererInterface::render()
117
+ * @param QrCode $qrCode
118
+ * @return string
119
+ */
120
+ public function render(QrCode $qrCode)
121
+ {
122
+ $result = '';
123
+ $matrix = $qrCode->getMatrix();
124
+ $width = $matrix->getWidth();
125
+
126
+ // Top margin
127
+ for ($x = 0; $x < $this->margin; $x++) {
128
+ $result .= str_repeat($this->emptyBlock, $width + 2 * $this->margin)."\n";
129
+ }
130
+
131
+ // Body
132
+ $array = $matrix->getArray();
133
+
134
+ foreach ($array as $row) {
135
+ $result .= str_repeat($this->emptyBlock, $this->margin); // left margin
136
+ foreach ($row as $byte) {
137
+ $result .= $byte ? $this->fullBlock : $this->emptyBlock;
138
+ }
139
+ $result .= str_repeat($this->emptyBlock, $this->margin); // right margin
140
+ $result .= "\n";
141
+ }
142
+
143
+ // Bottom margin
144
+ for ($x = 0; $x < $this->margin; $x++) {
145
+ $result .= str_repeat($this->emptyBlock, $width + 2 * $this->margin)."\n";
146
+ }
147
+
148
+ return $result;
149
+ }
150
+ }
src/lib/vendor/bacon/bacon-qr-code/src/BaconQrCode/Writer.php ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * BaconQrCode
4
+ *
5
+ * @link http://github.com/Bacon/BaconQrCode For the canonical source repository
6
+ * @copyright 2013 Ben 'DASPRiD' Scholzen
7
+ * @license http://opensource.org/licenses/BSD-2-Clause Simplified BSD License
8
+ */
9
+
10
+ namespace BaconQrCode;
11
+
12
+ use BaconQrCode\Common\ErrorCorrectionLevel;
13
+ use BaconQrCode\Encoder\Encoder;
14
+ use BaconQrCode\Exception;
15
+ use BaconQrCode\Renderer\RendererInterface;
16
+
17
+ /**
18
+ * QR code writer.
19
+ */
20
+ class Writer
21
+ {
22
+ /**
23
+ * Renderer instance.
24
+ *
25
+ * @var RendererInterface
26
+ */
27
+ protected $renderer;
28
+
29
+ /**
30
+ * Creates a new writer with a specific renderer.
31
+ *
32
+ * @param RendererInterface $renderer
33
+ */
34
+ public function __construct(RendererInterface $renderer)
35
+ {
36
+ $this->renderer = $renderer;
37
+ }
38
+
39
+ /**
40
+ * Sets the renderer used to create a byte stream.
41
+ *
42
+ * @param RendererInterface $renderer
43
+ * @return Writer
44
+ */
45
+ public function setRenderer(RendererInterface $renderer)
46
+ {
47
+ $this->renderer = $renderer;
48
+ return $this;
49
+ }
50
+
51
+ /**
52
+ * Gets the renderer used to create a byte stream.
53
+ *
54
+ * @return RendererInterface
55
+ */
56
+ public function getRenderer()
57
+ {
58
+ return $this->renderer;
59
+ }
60
+
61
+ /**
62
+ * Writes QR code and returns it as string.
63
+ *
64
+ * Content is a string which *should* be encoded in UTF-8, in case there are
65
+ * non ASCII-characters present.
66
+ *
67
+ * @param string $content
68
+ * @param string $encoding
69
+ * @param integer $ecLevel
70
+ * @return string
71
+ * @throws Exception\InvalidArgumentException
72
+ */
73
+ public function writeString(
74
+ $content,
75
+ $encoding = Encoder::DEFAULT_BYTE_MODE_ECODING,
76
+ $ecLevel = ErrorCorrectionLevel::L
77
+ ) {
78
+ if (strlen($content) === 0) {
79
+ throw new Exception\InvalidArgumentException('Found empty contents');
80
+ }
81
+
82
+ $qrCode = Encoder::encode($content, new ErrorCorrectionLevel($ecLevel), $encoding);
83
+
84
+ return $this->getRenderer()->render($qrCode);
85
+ }
86
+
87
+ /**
88
+ * Writes QR code to a file.
89
+ *
90
+ * @see Writer::writeString()
91
+ * @param string $content
92
+ * @param string $filename
93
+ * @param string $encoding
94
+ * @param integer $ecLevel
95
+ * @return void
96
+ */
97
+ public function writeFile(
98
+ $content,
99
+ $filename,
100
+ $encoding = Encoder::DEFAULT_BYTE_MODE_ECODING,
101
+ $ecLevel = ErrorCorrectionLevel::L
102
+ ) {
103
+ file_put_contents($filename, $this->writeString($content, $encoding, $ecLevel));
104
+ }
105
+ }
src/lib/vendor/composer/autoload_classmap.php CHANGED
@@ -6,6 +6,45 @@ $vendorDir = dirname(dirname(__FILE__));
6
  $baseDir = dirname($vendorDir);
7
 
8
  return array(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  'Base32\\Base32' => $vendorDir . '/christian-riesen/base32/src/Base32.php',
10
  'Carbon\\Carbon' => $vendorDir . '/nesbot/carbon/src/Carbon/Carbon.php',
11
  'Carbon\\CarbonInterval' => $vendorDir . '/nesbot/carbon/src/Carbon/CarbonInterval.php',
@@ -23,11 +62,40 @@ return array(
23
  'Dolondro\\GoogleAuthenticator\\SecretFactory' => $vendorDir . '/dolondro/google-authenticator/src/SecretFactory.php',
24
  'Elliotchance\\Iterator\\AbstractPagedIterator' => $vendorDir . '/elliotchance/iterator/src/Elliotchance/Iterator/AbstractPagedIterator.php',
25
  'Elliotchance\\Iterator\\PagedIteratorTest' => $vendorDir . '/elliotchance/iterator/tests/Elliotchance/Iterator/PagedIteratorTest.php',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  'FernleafSystems\\Utilities\\Data\\Adapter\\DynProperties' => $vendorDir . '/fernleafsystems/utilities/src/Data/Adapter/DynProperties.php',
27
  'FernleafSystems\\Utilities\\Data\\Adapter\\DynPropertiesClass' => $vendorDir . '/fernleafsystems/utilities/src/Data/Adapter/DynPropertiesClass.php',
28
  'FernleafSystems\\Utilities\\Data\\Adapter\\DynamicProperties' => $vendorDir . '/fernleafsystems/utilities/src/Data/Adapter/DynamicProperties.php',
29
  'FernleafSystems\\Utilities\\Data\\Adapter\\StdClassAdapter' => $vendorDir . '/fernleafsystems/utilities/src/Data/Adapter/StdClassAdapter.php',
30
  'FernleafSystems\\Utilities\\Data\\CaptureOutput' => $vendorDir . '/fernleafsystems/utilities/src/Data/CaptureOutput.php',
 
31
  'FernleafSystems\\Utilities\\Logic\\ExecOnce' => $vendorDir . '/fernleafsystems/utilities/src/Logic/ExecOnce.php',
32
  'FernleafSystems\\Utilities\\Logic\\OneTimeExecute' => $vendorDir . '/fernleafsystems/utilities/src/Logic/OneTimeExecute.php',
33
  'FernleafSystems\\Utilities\\Response' => $vendorDir . '/fernleafsystems/utilities/src/Response.php',
@@ -63,6 +131,7 @@ return array(
63
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Ajax\\Response' => $baseDir . '/src/Controller/Ajax/Response.php',
64
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Assets\\Enqueue' => $baseDir . '/src/Controller/Assets/Enqueue.php',
65
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Assets\\Paths' => $baseDir . '/src/Controller/Assets/Paths.php',
 
66
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Assets\\Urls' => $baseDir . '/src/Controller/Assets/Urls.php',
67
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Config\\ConfigVO' => $baseDir . '/src/Controller/Config/ConfigVO.php',
68
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Config\\Ops\\LoadConfig' => $baseDir . '/src/Controller/Config/Ops/LoadConfig.php',
@@ -206,21 +275,33 @@ return array(
206
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Autoupdates\\Processor' => $baseDir . '/src/Modules/Autoupdates/Processor.php',
207
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Autoupdates\\Strings' => $baseDir . '/src/Modules/Autoupdates/Strings.php',
208
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Autoupdates\\UI' => $baseDir . '/src/Modules/Autoupdates/UI.php',
 
209
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\AjaxHandler' => $baseDir . '/src/Modules/BaseShield/AjaxHandler.php',
210
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\ModCon' => $baseDir . '/src/Modules/BaseShield/ModCon.php',
211
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\Options' => $baseDir . '/src/Modules/BaseShield/Options.php',
212
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\Processor' => $baseDir . '/src/Modules/BaseShield/Processor.php',
213
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\UI' => $baseDir . '/src/Modules/BaseShield/UI.php',
214
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\AdminNotices' => $baseDir . '/src/Modules/Base/AdminNotices.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',
222
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Processor' => $baseDir . '/src/Modules/Base/Processor.php',
223
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Reporting' => $baseDir . '/src/Modules/Base/Reporting.php',
 
224
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Strings' => $baseDir . '/src/Modules/Base/Strings.php',
225
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\UI' => $baseDir . '/src/Modules/Base/UI.php',
226
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Upgrade' => $baseDir . '/src/Modules/Base/Upgrade.php',
@@ -408,14 +489,45 @@ return array(
408
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\WpCli\\BaseAddRemove' => $baseDir . '/src/Modules/IPs/WpCli/BaseAddRemove.php',
409
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\WpCli\\Enumerate' => $baseDir . '/src/Modules/IPs/WpCli/Enumerate.php',
410
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\WpCli\\Remove' => $baseDir . '/src/Modules/IPs/WpCli/Remove.php',
 
411
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\AjaxHandler' => $baseDir . '/src/Modules/Insights/AjaxHandler.php',
412
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Lib\\OverviewCards' => $baseDir . '/src/Modules/Insights/Lib/OverviewCards.php',
413
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Lib\\Requests\\DynamicPageLoader' => $baseDir . '/src/Modules/Insights/Lib/Requests/DynamicPageLoader.php',
414
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Lib\\SideMenuBuilder' => $baseDir . '/src/Modules/Insights/Lib/SideMenuBuilder.php',
 
415
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\ModCon' => $baseDir . '/src/Modules/Insights/ModCon.php',
416
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Options' => $baseDir . '/src/Modules/Insights/Options.php',
417
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Strings' => $baseDir . '/src/Modules/Insights/Strings.php',
418
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\UI' => $baseDir . '/src/Modules/Insights/UI.php',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
419
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\MainWP\\Client\\Actions\\ApiActionInit' => $baseDir . '/src/Modules/Integrations/Lib/MainWP/Client/Actions/ApiActionInit.php',
420
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\MainWP\\Client\\Actions\\Init' => $baseDir . '/src/Modules/Integrations/Lib/MainWP/Client/Actions/Init.php',
421
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\MainWP\\Client\\Actions\\Sync' => $baseDir . '/src/Modules/Integrations/Lib/MainWP/Client/Actions/Sync.php',
@@ -460,6 +572,8 @@ return array(
460
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Options' => $baseDir . '/src/Modules/Integrations/Options.php',
461
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Processor' => $baseDir . '/src/Modules/Integrations/Processor.php',
462
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Strings' => $baseDir . '/src/Modules/Integrations/Strings.php',
 
 
463
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\AdminNotices' => $baseDir . '/src/Modules/License/AdminNotices.php',
464
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\AjaxHandler' => $baseDir . '/src/Modules/License/AjaxHandler.php',
465
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Lib\\LicenseEmails' => $baseDir . '/src/Modules/License/Lib/LicenseEmails.php',
@@ -510,11 +624,11 @@ return array(
510
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\LoginIntentPage' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/LoginIntentPage.php',
511
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\MfaController' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/MfaController.php',
512
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\MfaControllerConsumer' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/MfaControllerConsumer.php',
 
513
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\MfaSkip' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/MfaSkip.php',
514
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Profiles\\CustomForms' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Profiles/CustomForms.php',
515
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\Backup' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Backup.php',
516
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\BaseProvider' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/BaseProvider.php',
517
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\BaseProviderV2' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/BaseProviderV2.php',
518
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\Email' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Email.php',
519
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\GoogleAuth' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/GoogleAuth.php',
520
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\ProviderInterface' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/ProviderInterface.php',
@@ -604,8 +718,8 @@ return array(
604
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\Restrictions\\WpOptions' => $baseDir . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/WpOptions.php',
605
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\SecurityAdminController' => $baseDir . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/SecurityAdminController.php',
606
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\VerifySecurityAdminList' => $baseDir . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/VerifySecurityAdminList.php',
607
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\WhiteLabel\\ApplyLabels' => $baseDir . '/src/Modules/SecurityAdmin/Lib/WhiteLabel/ApplyLabels.php',
608
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\WhiteLabel\\BuildOptions' => $baseDir . '/src/Modules/SecurityAdmin/Lib/WhiteLabel/BuildOptions.php',
 
609
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\ModCon' => $baseDir . '/src/Modules/SecurityAdmin/ModCon.php',
610
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Options' => $baseDir . '/src/Modules/SecurityAdmin/Options.php',
611
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Processor' => $baseDir . '/src/Modules/SecurityAdmin/Processor.php',
@@ -615,6 +729,7 @@ return array(
615
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\WpCli\\AdminAdd' => $baseDir . '/src/Modules/SecurityAdmin/WpCli/AdminAdd.php',
616
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\WpCli\\AdminRemove' => $baseDir . '/src/Modules/SecurityAdmin/WpCli/AdminRemove.php',
617
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\WpCli\\Pin' => $baseDir . '/src/Modules/SecurityAdmin/WpCli/Pin.php',
 
618
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Sessions\\Lib\\Ops\\Terminate' => $baseDir . '/src/Modules/Sessions/Lib/Ops/Terminate.php',
619
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Sessions\\Lib\\SessionController' => $baseDir . '/src/Modules/Sessions/Lib/SessionController.php',
620
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Sessions\\ModCon' => $baseDir . '/src/Modules/Sessions/ModCon.php',
@@ -774,6 +889,10 @@ return array(
774
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Build\\ScanWpv' => $baseDir . '/src/Tables/Build/ScanWpv.php',
775
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Build\\Sessions' => $baseDir . '/src/Tables/Build/Sessions.php',
776
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Build\\Traffic' => $baseDir . '/src/Tables/Build/Traffic.php',
 
 
 
 
777
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\WpCliTable\\AuditTrail' => $baseDir . '/src/Tables/Render/WpCliTable/AuditTrail.php',
778
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\WpCliTable\\Base' => $baseDir . '/src/Tables/Render/WpCliTable/Base.php',
779
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\WpListTable\\AdminNotes' => $baseDir . '/src/Tables/Render/WpListTable/AdminNotes.php',
@@ -921,7 +1040,6 @@ return array(
921
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Keyless\\Base' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Base.php',
922
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Keyless\\Lookup' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Lookup.php',
923
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Keyless\\Ping' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Ping.php',
924
- 'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Lookup' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Lookup.php',
925
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\BaseIP' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Net/BaseIP.php',
926
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\FindSourceFromIp' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Net/FindSourceFromIp.php',
927
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\IpID' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Net/IpID.php',
@@ -978,6 +1096,7 @@ return array(
978
  'LZCompressor\\LZString' => $vendorDir . '/nullpunkt/lz-string-php/src/LZCompressor/LZString.php',
979
  'LZCompressor\\LZUtil' => $vendorDir . '/nullpunkt/lz-string-php/src/LZCompressor/LZUtil.php',
980
  'LZCompressor\\LZUtil16' => $vendorDir . '/nullpunkt/lz-string-php/src/LZCompressor/LZUtil16.php',
 
981
  'Pimple\\Container' => $vendorDir . '/pimple/pimple/src/Pimple/Container.php',
982
  'Pimple\\Exception\\ExpectedInvokableException' => $vendorDir . '/pimple/pimple/src/Pimple/Exception/ExpectedInvokableException.php',
983
  'Pimple\\Exception\\FrozenServiceException' => $vendorDir . '/pimple/pimple/src/Pimple/Exception/FrozenServiceException.php',
@@ -1003,6 +1122,7 @@ return array(
1003
  'Psr\\Container\\ContainerExceptionInterface' => $vendorDir . '/psr/container/src/ContainerExceptionInterface.php',
1004
  'Psr\\Container\\ContainerInterface' => $vendorDir . '/psr/container/src/ContainerInterface.php',
1005
  'Psr\\Container\\NotFoundExceptionInterface' => $vendorDir . '/psr/container/src/NotFoundExceptionInterface.php',
 
1006
  'Ramsey\\Uuid\\BinaryUtils' => $vendorDir . '/ramsey/uuid/src/BinaryUtils.php',
1007
  'Ramsey\\Uuid\\Builder\\DefaultUuidBuilder' => $vendorDir . '/ramsey/uuid/src/Builder/DefaultUuidBuilder.php',
1008
  'Ramsey\\Uuid\\Builder\\DegradedUuidBuilder' => $vendorDir . '/ramsey/uuid/src/Builder/DegradedUuidBuilder.php',
@@ -1058,6 +1178,36 @@ return array(
1058
  'ReCaptcha\\RequestMethod\\SocketPost' => $vendorDir . '/google/recaptcha/src/ReCaptcha/RequestMethod/SocketPost.php',
1059
  'ReCaptcha\\RequestParameters' => $vendorDir . '/google/recaptcha/src/ReCaptcha/RequestParameters.php',
1060
  'ReCaptcha\\Response' => $vendorDir . '/google/recaptcha/src/ReCaptcha/Response.php',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1061
  'Symfony\\Component\\Translation\\Catalogue\\AbstractOperation' => $vendorDir . '/symfony/translation/Catalogue/AbstractOperation.php',
1062
  'Symfony\\Component\\Translation\\Catalogue\\MergeOperation' => $vendorDir . '/symfony/translation/Catalogue/MergeOperation.php',
1063
  'Symfony\\Component\\Translation\\Catalogue\\OperationInterface' => $vendorDir . '/symfony/translation/Catalogue/OperationInterface.php',
@@ -1527,6 +1677,64 @@ return array(
1527
  'ZxcvbnPhp\\Scorer' => $vendorDir . '/fernleafsystems/zxcvbn-php/src/Scorer.php',
1528
  'ZxcvbnPhp\\TimeEstimator' => $vendorDir . '/fernleafsystems/zxcvbn-php/src/TimeEstimator.php',
1529
  'ZxcvbnPhp\\Zxcvbn' => $vendorDir . '/fernleafsystems/zxcvbn-php/src/Zxcvbn.php',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1530
  'u2flib_server\\Error' => $baseDir . '/custom/U2F/Yubico/U2F.php',
1531
  'u2flib_server\\RegisterRequest' => $baseDir . '/custom/U2F/Yubico/U2F.php',
1532
  'u2flib_server\\Registration' => $baseDir . '/custom/U2F/Yubico/U2F.php',
6
  $baseDir = dirname($vendorDir);
7
 
8
  return array(
9
+ 'BaconQrCode\\Common\\AbstractEnum' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Common/AbstractEnum.php',
10
+ 'BaconQrCode\\Common\\BitArray' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Common/BitArray.php',
11
+ 'BaconQrCode\\Common\\BitMatrix' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Common/BitMatrix.php',
12
+ 'BaconQrCode\\Common\\BitUtils' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Common/BitUtils.php',
13
+ 'BaconQrCode\\Common\\CharacterSetEci' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Common/CharacterSetEci.php',
14
+ 'BaconQrCode\\Common\\EcBlock' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Common/EcBlock.php',
15
+ 'BaconQrCode\\Common\\EcBlocks' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Common/EcBlocks.php',
16
+ 'BaconQrCode\\Common\\ErrorCorrectionLevel' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Common/ErrorCorrectionLevel.php',
17
+ 'BaconQrCode\\Common\\FormatInformation' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Common/FormatInformation.php',
18
+ 'BaconQrCode\\Common\\Mode' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Common/Mode.php',
19
+ 'BaconQrCode\\Common\\ReedSolomonCodec' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Common/ReedSolomonCodec.php',
20
+ 'BaconQrCode\\Common\\Version' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Common/Version.php',
21
+ 'BaconQrCode\\Encoder\\BlockPair' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Encoder/BlockPair.php',
22
+ 'BaconQrCode\\Encoder\\ByteMatrix' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Encoder/ByteMatrix.php',
23
+ 'BaconQrCode\\Encoder\\Encoder' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Encoder/Encoder.php',
24
+ 'BaconQrCode\\Encoder\\MaskUtil' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Encoder/MaskUtil.php',
25
+ 'BaconQrCode\\Encoder\\MatrixUtil' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Encoder/MatrixUtil.php',
26
+ 'BaconQrCode\\Encoder\\QrCode' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Encoder/QrCode.php',
27
+ 'BaconQrCode\\Exception\\ExceptionInterface' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Exception/ExceptionInterface.php',
28
+ 'BaconQrCode\\Exception\\InvalidArgumentException' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Exception/InvalidArgumentException.php',
29
+ 'BaconQrCode\\Exception\\OutOfBoundsException' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Exception/OutOfBoundsException.php',
30
+ 'BaconQrCode\\Exception\\RuntimeException' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Exception/RuntimeException.php',
31
+ 'BaconQrCode\\Exception\\UnexpectedValueException' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Exception/UnexpectedValueException.php',
32
+ 'BaconQrCode\\Exception\\WriterException' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Exception/WriterException.php',
33
+ 'BaconQrCode\\Renderer\\Color\\Cmyk' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/Cmyk.php',
34
+ 'BaconQrCode\\Renderer\\Color\\ColorInterface' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/ColorInterface.php',
35
+ 'BaconQrCode\\Renderer\\Color\\Gray' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/Gray.php',
36
+ 'BaconQrCode\\Renderer\\Color\\Rgb' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/Rgb.php',
37
+ 'BaconQrCode\\Renderer\\Image\\AbstractRenderer' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/AbstractRenderer.php',
38
+ 'BaconQrCode\\Renderer\\Image\\Decorator\\DecoratorInterface' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Decorator/DecoratorInterface.php',
39
+ 'BaconQrCode\\Renderer\\Image\\Decorator\\FinderPattern' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Decorator/FinderPattern.php',
40
+ 'BaconQrCode\\Renderer\\Image\\Eps' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Eps.php',
41
+ 'BaconQrCode\\Renderer\\Image\\Png' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Png.php',
42
+ 'BaconQrCode\\Renderer\\Image\\RendererInterface' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/RendererInterface.php',
43
+ 'BaconQrCode\\Renderer\\Image\\Svg' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Svg.php',
44
+ 'BaconQrCode\\Renderer\\RendererInterface' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/RendererInterface.php',
45
+ 'BaconQrCode\\Renderer\\Text\\Html' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Text/Html.php',
46
+ 'BaconQrCode\\Renderer\\Text\\Plain' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Text/Plain.php',
47
+ 'BaconQrCode\\Writer' => $vendorDir . '/bacon/bacon-qr-code/src/BaconQrCode/Writer.php',
48
  'Base32\\Base32' => $vendorDir . '/christian-riesen/base32/src/Base32.php',
49
  'Carbon\\Carbon' => $vendorDir . '/nesbot/carbon/src/Carbon/Carbon.php',
50
  'Carbon\\CarbonInterval' => $vendorDir . '/nesbot/carbon/src/Carbon/CarbonInterval.php',
62
  'Dolondro\\GoogleAuthenticator\\SecretFactory' => $vendorDir . '/dolondro/google-authenticator/src/SecretFactory.php',
63
  'Elliotchance\\Iterator\\AbstractPagedIterator' => $vendorDir . '/elliotchance/iterator/src/Elliotchance/Iterator/AbstractPagedIterator.php',
64
  'Elliotchance\\Iterator\\PagedIteratorTest' => $vendorDir . '/elliotchance/iterator/tests/Elliotchance/Iterator/PagedIteratorTest.php',
65
+ 'Endroid\\QrCode\\Bundle\\QrCodeBundle\\Controller\\QrCodeController' => $vendorDir . '/endroid/qr-code/src/Bundle/QrCodeBundle/Controller/QrCodeController.php',
66
+ 'Endroid\\QrCode\\Bundle\\QrCodeBundle\\DependencyInjection\\Compiler\\WriterRegistryCompilerPass' => $vendorDir . '/endroid/qr-code/src/Bundle/QrCodeBundle/DependencyInjection/Compiler/WriterRegistryCompilerPass.php',
67
+ 'Endroid\\QrCode\\Bundle\\QrCodeBundle\\DependencyInjection\\Configuration' => $vendorDir . '/endroid/qr-code/src/Bundle/QrCodeBundle/DependencyInjection/Configuration.php',
68
+ 'Endroid\\QrCode\\Bundle\\QrCodeBundle\\DependencyInjection\\EndroidQrCodeExtension' => $vendorDir . '/endroid/qr-code/src/Bundle/QrCodeBundle/DependencyInjection/EndroidQrCodeExtension.php',
69
+ 'Endroid\\QrCode\\Bundle\\QrCodeBundle\\EndroidQrCodeBundle' => $vendorDir . '/endroid/qr-code/src/Bundle/QrCodeBundle/EndroidQrCodeBundle.php',
70
+ 'Endroid\\QrCode\\ErrorCorrectionLevel' => $vendorDir . '/endroid/qr-code/src/ErrorCorrectionLevel.php',
71
+ 'Endroid\\QrCode\\Exception\\InvalidPathException' => $vendorDir . '/endroid/qr-code/src/Exception/InvalidPathException.php',
72
+ 'Endroid\\QrCode\\Exception\\InvalidWriterException' => $vendorDir . '/endroid/qr-code/src/Exception/InvalidWriterException.php',
73
+ 'Endroid\\QrCode\\Exception\\MissingFunctionException' => $vendorDir . '/endroid/qr-code/src/Exception/MissingFunctionException.php',
74
+ 'Endroid\\QrCode\\Exception\\QrCodeException' => $vendorDir . '/endroid/qr-code/src/Exception/QrCodeException.php',
75
+ 'Endroid\\QrCode\\Exception\\UnsupportedExtensionException' => $vendorDir . '/endroid/qr-code/src/Exception/UnsupportedExtensionException.php',
76
+ 'Endroid\\QrCode\\Exception\\ValidationException' => $vendorDir . '/endroid/qr-code/src/Exception/ValidationException.php',
77
+ 'Endroid\\QrCode\\Factory\\QrCodeFactory' => $vendorDir . '/endroid/qr-code/src/Factory/QrCodeFactory.php',
78
+ 'Endroid\\QrCode\\LabelAlignment' => $vendorDir . '/endroid/qr-code/src/LabelAlignment.php',
79
+ 'Endroid\\QrCode\\QrCode' => $vendorDir . '/endroid/qr-code/src/QrCode.php',
80
+ 'Endroid\\QrCode\\QrCodeInterface' => $vendorDir . '/endroid/qr-code/src/QrCodeInterface.php',
81
+ 'Endroid\\QrCode\\StaticWriterRegistry' => $vendorDir . '/endroid/qr-code/src/StaticWriterRegistry.php',
82
+ 'Endroid\\QrCode\\Twig\\Extension\\QrCodeExtension' => $vendorDir . '/endroid/qr-code/src/Twig/Extension/QrCodeExtension.php',
83
+ 'Endroid\\QrCode\\WriterRegistry' => $vendorDir . '/endroid/qr-code/src/WriterRegistry.php',
84
+ 'Endroid\\QrCode\\WriterRegistryInterface' => $vendorDir . '/endroid/qr-code/src/WriterRegistryInterface.php',
85
+ 'Endroid\\QrCode\\Writer\\AbstractBaconWriter' => $vendorDir . '/endroid/qr-code/src/Writer/AbstractBaconWriter.php',
86
+ 'Endroid\\QrCode\\Writer\\AbstractWriter' => $vendorDir . '/endroid/qr-code/src/Writer/AbstractWriter.php',
87
+ 'Endroid\\QrCode\\Writer\\BinaryWriter' => $vendorDir . '/endroid/qr-code/src/Writer/BinaryWriter.php',
88
+ 'Endroid\\QrCode\\Writer\\DebugWriter' => $vendorDir . '/endroid/qr-code/src/Writer/DebugWriter.php',
89
+ 'Endroid\\QrCode\\Writer\\EpsWriter' => $vendorDir . '/endroid/qr-code/src/Writer/EpsWriter.php',
90
+ 'Endroid\\QrCode\\Writer\\PngWriter' => $vendorDir . '/endroid/qr-code/src/Writer/PngWriter.php',
91
+ 'Endroid\\QrCode\\Writer\\SvgWriter' => $vendorDir . '/endroid/qr-code/src/Writer/SvgWriter.php',
92
+ 'Endroid\\QrCode\\Writer\\WriterInterface' => $vendorDir . '/endroid/qr-code/src/Writer/WriterInterface.php',
93
  'FernleafSystems\\Utilities\\Data\\Adapter\\DynProperties' => $vendorDir . '/fernleafsystems/utilities/src/Data/Adapter/DynProperties.php',
94
  'FernleafSystems\\Utilities\\Data\\Adapter\\DynPropertiesClass' => $vendorDir . '/fernleafsystems/utilities/src/Data/Adapter/DynPropertiesClass.php',
95
  'FernleafSystems\\Utilities\\Data\\Adapter\\DynamicProperties' => $vendorDir . '/fernleafsystems/utilities/src/Data/Adapter/DynamicProperties.php',
96
  'FernleafSystems\\Utilities\\Data\\Adapter\\StdClassAdapter' => $vendorDir . '/fernleafsystems/utilities/src/Data/Adapter/StdClassAdapter.php',
97
  'FernleafSystems\\Utilities\\Data\\CaptureOutput' => $vendorDir . '/fernleafsystems/utilities/src/Data/CaptureOutput.php',
98
+ 'FernleafSystems\\Utilities\\Data\\Response\\StdResponse' => $vendorDir . '/fernleafsystems/utilities/src/Data/Response/StdResponse.php',
99
  'FernleafSystems\\Utilities\\Logic\\ExecOnce' => $vendorDir . '/fernleafsystems/utilities/src/Logic/ExecOnce.php',
100
  'FernleafSystems\\Utilities\\Logic\\OneTimeExecute' => $vendorDir . '/fernleafsystems/utilities/src/Logic/OneTimeExecute.php',
101
  'FernleafSystems\\Utilities\\Response' => $vendorDir . '/fernleafsystems/utilities/src/Response.php',
131
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Ajax\\Response' => $baseDir . '/src/Controller/Ajax/Response.php',
132
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Assets\\Enqueue' => $baseDir . '/src/Controller/Assets/Enqueue.php',
133
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Assets\\Paths' => $baseDir . '/src/Controller/Assets/Paths.php',
134
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Assets\\Svgs' => $baseDir . '/src/Controller/Assets/Svgs.php',
135
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Assets\\Urls' => $baseDir . '/src/Controller/Assets/Urls.php',
136
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Config\\ConfigVO' => $baseDir . '/src/Controller/Config/ConfigVO.php',
137
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Config\\Ops\\LoadConfig' => $baseDir . '/src/Controller/Config/Ops/LoadConfig.php',
275
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Autoupdates\\Processor' => $baseDir . '/src/Modules/Autoupdates/Processor.php',
276
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Autoupdates\\Strings' => $baseDir . '/src/Modules/Autoupdates/Strings.php',
277
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Autoupdates\\UI' => $baseDir . '/src/Modules/Autoupdates/UI.php',
278
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\AdminPage' => $baseDir . '/src/Modules/BaseShield/AdminPage.php',
279
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\AjaxHandler' => $baseDir . '/src/Modules/BaseShield/AjaxHandler.php',
280
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\ModCon' => $baseDir . '/src/Modules/BaseShield/ModCon.php',
281
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\Options' => $baseDir . '/src/Modules/BaseShield/Options.php',
282
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\Processor' => $baseDir . '/src/Modules/BaseShield/Processor.php',
283
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\UI' => $baseDir . '/src/Modules/BaseShield/UI.php',
284
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\AdminNotices' => $baseDir . '/src/Modules/Base/AdminNotices.php',
285
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\AdminPage' => $baseDir . '/src/Modules/Base/AdminPage.php',
286
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\AjaxHandler' => $baseDir . '/src/Modules/Base/AjaxHandler.php',
287
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Common\\ExecOnceModConsumer' => $baseDir . '/src/Modules/Base/Common/ExecOnceModConsumer.php',
288
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Debug' => $baseDir . '/src/Modules/Base/Debug.php',
289
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Insights\\OverviewCards' => $baseDir . '/src/Modules/Base/Insights/OverviewCards.php',
290
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Request\\FormParams' => $baseDir . '/src/Modules/Base/Lib/Request/FormParams.php',
291
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\RequestVoConsumer' => $baseDir . '/src/Modules/Base/Lib/Rest/RequestVoConsumer.php',
292
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Request\\Process' => $baseDir . '/src/Modules/Base/Lib/Rest/Request/Process.php',
293
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Request\\RequestVO' => $baseDir . '/src/Modules/Base/Lib/Rest/Request/RequestVO.php',
294
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Route\\RestRouteConsumer' => $baseDir . '/src/Modules/Base/Lib/Rest/Route/RestRouteConsumer.php',
295
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Route\\RouteBase' => $baseDir . '/src/Modules/Base/Lib/Rest/Route/RouteBase.php',
296
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Route\\RouteCache' => $baseDir . '/src/Modules/Base/Lib/Rest/Route/RouteCache.php',
297
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Utility\\PreChecks' => $baseDir . '/src/Modules/Base/Lib/Rest/Utility/PreChecks.php',
298
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Utility\\RestLocker' => $baseDir . '/src/Modules/Base/Lib/Rest/Utility/RestLocker.php',
299
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\ModCon' => $baseDir . '/src/Modules/Base/ModCon.php',
300
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Options' => $baseDir . '/src/Modules/Base/Options.php',
301
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Options\\OptValueSanitize' => $baseDir . '/src/Modules/Base/Options/OptValueSanitize.php',
302
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Processor' => $baseDir . '/src/Modules/Base/Processor.php',
303
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Reporting' => $baseDir . '/src/Modules/Base/Reporting.php',
304
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\RestHandler' => $baseDir . '/src/Modules/Base/RestHandler.php',
305
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Strings' => $baseDir . '/src/Modules/Base/Strings.php',
306
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\UI' => $baseDir . '/src/Modules/Base/UI.php',
307
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Upgrade' => $baseDir . '/src/Modules/Base/Upgrade.php',
489
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\WpCli\\BaseAddRemove' => $baseDir . '/src/Modules/IPs/WpCli/BaseAddRemove.php',
490
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\WpCli\\Enumerate' => $baseDir . '/src/Modules/IPs/WpCli/Enumerate.php',
491
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\WpCli\\Remove' => $baseDir . '/src/Modules/IPs/WpCli/Remove.php',
492
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\AdminPage' => $baseDir . '/src/Modules/Insights/AdminPage.php',
493
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\AjaxHandler' => $baseDir . '/src/Modules/Insights/AjaxHandler.php',
494
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Lib\\OverviewCards' => $baseDir . '/src/Modules/Insights/Lib/OverviewCards.php',
495
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Lib\\Requests\\DynamicPageLoader' => $baseDir . '/src/Modules/Insights/Lib/Requests/DynamicPageLoader.php',
496
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Lib\\SideMenuBuilder' => $baseDir . '/src/Modules/Insights/Lib/SideMenuBuilder.php',
497
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Lib\\SummaryCards' => $baseDir . '/src/Modules/Insights/Lib/SummaryCards.php',
498
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\ModCon' => $baseDir . '/src/Modules/Insights/ModCon.php',
499
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Options' => $baseDir . '/src/Modules/Insights/Options.php',
500
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Strings' => $baseDir . '/src/Modules/Insights/Strings.php',
501
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\UI' => $baseDir . '/src/Modules/Insights/UI.php',
502
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Common\\BaseBotDetectionController' => $baseDir . '/src/Modules/Integrations/Lib/Bots/Common/BaseBotDetectionController.php',
503
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Common\\BaseHandler' => $baseDir . '/src/Modules/Integrations/Lib/Bots/Common/BaseHandler.php',
504
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\Handlers\\Base' => $baseDir . '/src/Modules/Integrations/Lib/Bots/Spam/Handlers/Base.php',
505
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\Handlers\\ContactForm7' => $baseDir . '/src/Modules/Integrations/Lib/Bots/Spam/Handlers/ContactForm7.php',
506
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\Handlers\\ElementorPro' => $baseDir . '/src/Modules/Integrations/Lib/Bots/Spam/Handlers/ElementorPro.php',
507
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\Handlers\\FluentForms' => $baseDir . '/src/Modules/Integrations/Lib/Bots/Spam/Handlers/FluentForms.php',
508
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\Handlers\\FormidableForms' => $baseDir . '/src/Modules/Integrations/Lib/Bots/Spam/Handlers/FormidableForms.php',
509
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\Handlers\\Forminator' => $baseDir . '/src/Modules/Integrations/Lib/Bots/Spam/Handlers/Forminator.php',
510
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\Handlers\\GravityForms' => $baseDir . '/src/Modules/Integrations/Lib/Bots/Spam/Handlers/GravityForms.php',
511
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\Handlers\\Groundhogg' => $baseDir . '/src/Modules/Integrations/Lib/Bots/Spam/Handlers/Groundhogg.php',
512
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\Handlers\\Helpers\\NinjaForms_ShieldSpamAction' => $baseDir . '/src/Modules/Integrations/Lib/Bots/Spam/Handlers/Helpers/NinjaForms_ShieldSpamAction.php',
513
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\Handlers\\KaliForms' => $baseDir . '/src/Modules/Integrations/Lib/Bots/Spam/Handlers/KaliForms.php',
514
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\Handlers\\NinjaForms' => $baseDir . '/src/Modules/Integrations/Lib/Bots/Spam/Handlers/NinjaForms.php',
515
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\Handlers\\WPForms' => $baseDir . '/src/Modules/Integrations/Lib/Bots/Spam/Handlers/WPForms.php',
516
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\Handlers\\WpForo' => $baseDir . '/src/Modules/Integrations/Lib/Bots/Spam/Handlers/WpForo.php',
517
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\SpamController' => $baseDir . '/src/Modules/Integrations/Lib/Bots/Spam/SpamController.php',
518
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\UserForms\\Handlers\\Base' => $baseDir . '/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/Base.php',
519
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\UserForms\\Handlers\\Buddypress' => $baseDir . '/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/Buddypress.php',
520
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\UserForms\\Handlers\\EasyDigitalDownloads' => $baseDir . '/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/EasyDigitalDownloads.php',
521
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\UserForms\\Handlers\\LearnPress' => $baseDir . '/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/LearnPress.php',
522
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\UserForms\\Handlers\\LifterLMS' => $baseDir . '/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/LifterLMS.php',
523
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\UserForms\\Handlers\\MemberPress' => $baseDir . '/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/MemberPress.php',
524
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\UserForms\\Handlers\\PaidMemberSubscriptions' => $baseDir . '/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/PaidMemberSubscriptions.php',
525
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\UserForms\\Handlers\\ProfileBuilder' => $baseDir . '/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/ProfileBuilder.php',
526
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\UserForms\\Handlers\\UltimateMember' => $baseDir . '/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/UltimateMember.php',
527
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\UserForms\\Handlers\\WPMembers' => $baseDir . '/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/WPMembers.php',
528
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\UserForms\\Handlers\\WooCommerce' => $baseDir . '/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/WooCommerce.php',
529
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\UserForms\\Handlers\\WordPress' => $baseDir . '/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/WordPress.php',
530
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\UserForms\\UserFormsController' => $baseDir . '/src/Modules/Integrations/Lib/Bots/UserForms/UserFormsController.php',
531
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\MainWP\\Client\\Actions\\ApiActionInit' => $baseDir . '/src/Modules/Integrations/Lib/MainWP/Client/Actions/ApiActionInit.php',
532
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\MainWP\\Client\\Actions\\Init' => $baseDir . '/src/Modules/Integrations/Lib/MainWP/Client/Actions/Init.php',
533
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\MainWP\\Client\\Actions\\Sync' => $baseDir . '/src/Modules/Integrations/Lib/MainWP/Client/Actions/Sync.php',
572
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Options' => $baseDir . '/src/Modules/Integrations/Options.php',
573
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Processor' => $baseDir . '/src/Modules/Integrations/Processor.php',
574
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Strings' => $baseDir . '/src/Modules/Integrations/Strings.php',
575
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\UI' => $baseDir . '/src/Modules/Integrations/UI.php',
576
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Upgrade' => $baseDir . '/src/Modules/Integrations/Upgrade.php',
577
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\AdminNotices' => $baseDir . '/src/Modules/License/AdminNotices.php',
578
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\AjaxHandler' => $baseDir . '/src/Modules/License/AjaxHandler.php',
579
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Lib\\LicenseEmails' => $baseDir . '/src/Modules/License/Lib/LicenseEmails.php',
624
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\LoginIntentPage' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/LoginIntentPage.php',
625
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\MfaController' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/MfaController.php',
626
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\MfaControllerConsumer' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/MfaControllerConsumer.php',
627
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\MfaProfilesController' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/MfaProfilesController.php',
628
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\MfaSkip' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/MfaSkip.php',
629
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Profiles\\RenderCustomForms' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Profiles/RenderCustomForms.php',
630
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\BackupCodes' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/BackupCodes.php',
631
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\BaseProvider' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/BaseProvider.php',
 
632
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\Email' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Email.php',
633
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\GoogleAuth' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/GoogleAuth.php',
634
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\ProviderInterface' => $baseDir . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/ProviderInterface.php',
718
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\Restrictions\\WpOptions' => $baseDir . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/WpOptions.php',
719
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\SecurityAdminController' => $baseDir . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/SecurityAdminController.php',
720
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\VerifySecurityAdminList' => $baseDir . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/VerifySecurityAdminList.php',
 
721
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\WhiteLabel\\BuildOptions' => $baseDir . '/src/Modules/SecurityAdmin/Lib/WhiteLabel/BuildOptions.php',
722
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\WhiteLabel\\WhitelabelController' => $baseDir . '/src/Modules/SecurityAdmin/Lib/WhiteLabel/WhitelabelController.php',
723
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\ModCon' => $baseDir . '/src/Modules/SecurityAdmin/ModCon.php',
724
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Options' => $baseDir . '/src/Modules/SecurityAdmin/Options.php',
725
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Processor' => $baseDir . '/src/Modules/SecurityAdmin/Processor.php',
729
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\WpCli\\AdminAdd' => $baseDir . '/src/Modules/SecurityAdmin/WpCli/AdminAdd.php',
730
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\WpCli\\AdminRemove' => $baseDir . '/src/Modules/SecurityAdmin/WpCli/AdminRemove.php',
731
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\WpCli\\Pin' => $baseDir . '/src/Modules/SecurityAdmin/WpCli/Pin.php',
732
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Sessions\\Lib\\Ops\\Retrieve' => $baseDir . '/src/Modules/Sessions/Lib/Ops/Retrieve.php',
733
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Sessions\\Lib\\Ops\\Terminate' => $baseDir . '/src/Modules/Sessions/Lib/Ops/Terminate.php',
734
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Sessions\\Lib\\SessionController' => $baseDir . '/src/Modules/Sessions/Lib/SessionController.php',
735
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Sessions\\ModCon' => $baseDir . '/src/Modules/Sessions/ModCon.php',
889
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Build\\ScanWpv' => $baseDir . '/src/Tables/Build/ScanWpv.php',
890
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Build\\Sessions' => $baseDir . '/src/Tables/Build/Sessions.php',
891
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Build\\Traffic' => $baseDir . '/src/Tables/Build/Traffic.php',
892
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\Common\\BaseTable' => $baseDir . '/src/Tables/Render/Common/BaseTable.php',
893
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\DataTable\\Base' => $baseDir . '/src/Tables/Render/DataTable/Base.php',
894
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\DataTable\\ScanBase' => $baseDir . '/src/Tables/Render/DataTable/ScanBase.php',
895
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\DataTable\\ScanWcf' => $baseDir . '/src/Tables/Render/DataTable/ScanWcf.php',
896
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\WpCliTable\\AuditTrail' => $baseDir . '/src/Tables/Render/WpCliTable/AuditTrail.php',
897
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\WpCliTable\\Base' => $baseDir . '/src/Tables/Render/WpCliTable/Base.php',
898
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\WpListTable\\AdminNotes' => $baseDir . '/src/Tables/Render/WpListTable/AdminNotes.php',
1040
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Keyless\\Base' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Base.php',
1041
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Keyless\\Lookup' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Lookup.php',
1042
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Keyless\\Ping' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Ping.php',
 
1043
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\BaseIP' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Net/BaseIP.php',
1044
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\FindSourceFromIp' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Net/FindSourceFromIp.php',
1045
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\IpID' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Net/IpID.php',
1096
  'LZCompressor\\LZString' => $vendorDir . '/nullpunkt/lz-string-php/src/LZCompressor/LZString.php',
1097
  'LZCompressor\\LZUtil' => $vendorDir . '/nullpunkt/lz-string-php/src/LZCompressor/LZUtil.php',
1098
  'LZCompressor\\LZUtil16' => $vendorDir . '/nullpunkt/lz-string-php/src/LZCompressor/LZUtil16.php',
1099
+ 'MyCLabs\\Enum\\Enum' => $vendorDir . '/myclabs/php-enum/src/Enum.php',
1100
  'Pimple\\Container' => $vendorDir . '/pimple/pimple/src/Pimple/Container.php',
1101
  'Pimple\\Exception\\ExpectedInvokableException' => $vendorDir . '/pimple/pimple/src/Pimple/Exception/ExpectedInvokableException.php',
1102
  'Pimple\\Exception\\FrozenServiceException' => $vendorDir . '/pimple/pimple/src/Pimple/Exception/FrozenServiceException.php',
1122
  'Psr\\Container\\ContainerExceptionInterface' => $vendorDir . '/psr/container/src/ContainerExceptionInterface.php',
1123
  'Psr\\Container\\ContainerInterface' => $vendorDir . '/psr/container/src/ContainerInterface.php',
1124
  'Psr\\Container\\NotFoundExceptionInterface' => $vendorDir . '/psr/container/src/NotFoundExceptionInterface.php',
1125
+ 'QrReader' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/QrReader.php',
1126
  'Ramsey\\Uuid\\BinaryUtils' => $vendorDir . '/ramsey/uuid/src/BinaryUtils.php',
1127
  'Ramsey\\Uuid\\Builder\\DefaultUuidBuilder' => $vendorDir . '/ramsey/uuid/src/Builder/DefaultUuidBuilder.php',
1128
  'Ramsey\\Uuid\\Builder\\DegradedUuidBuilder' => $vendorDir . '/ramsey/uuid/src/Builder/DegradedUuidBuilder.php',
1178
  'ReCaptcha\\RequestMethod\\SocketPost' => $vendorDir . '/google/recaptcha/src/ReCaptcha/RequestMethod/SocketPost.php',
1179
  'ReCaptcha\\RequestParameters' => $vendorDir . '/google/recaptcha/src/ReCaptcha/RequestParameters.php',
1180
  'ReCaptcha\\Response' => $vendorDir . '/google/recaptcha/src/ReCaptcha/Response.php',
1181
+ 'Symfony\\Component\\OptionsResolver\\Exception\\AccessException' => $vendorDir . '/symfony/options-resolver/Exception/AccessException.php',
1182
+ 'Symfony\\Component\\OptionsResolver\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/options-resolver/Exception/ExceptionInterface.php',
1183
+ 'Symfony\\Component\\OptionsResolver\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/options-resolver/Exception/InvalidArgumentException.php',
1184
+ 'Symfony\\Component\\OptionsResolver\\Exception\\InvalidOptionsException' => $vendorDir . '/symfony/options-resolver/Exception/InvalidOptionsException.php',
1185
+ 'Symfony\\Component\\OptionsResolver\\Exception\\MissingOptionsException' => $vendorDir . '/symfony/options-resolver/Exception/MissingOptionsException.php',
1186
+ 'Symfony\\Component\\OptionsResolver\\Exception\\NoSuchOptionException' => $vendorDir . '/symfony/options-resolver/Exception/NoSuchOptionException.php',
1187
+ 'Symfony\\Component\\OptionsResolver\\Exception\\OptionDefinitionException' => $vendorDir . '/symfony/options-resolver/Exception/OptionDefinitionException.php',
1188
+ 'Symfony\\Component\\OptionsResolver\\Exception\\UndefinedOptionsException' => $vendorDir . '/symfony/options-resolver/Exception/UndefinedOptionsException.php',
1189
+ 'Symfony\\Component\\OptionsResolver\\Options' => $vendorDir . '/symfony/options-resolver/Options.php',
1190
+ 'Symfony\\Component\\OptionsResolver\\OptionsResolver' => $vendorDir . '/symfony/options-resolver/OptionsResolver.php',
1191
+ 'Symfony\\Component\\OptionsResolver\\OptionsResolverInterface' => $vendorDir . '/symfony/options-resolver/OptionsResolverInterface.php',
1192
+ 'Symfony\\Component\\PropertyAccess\\Exception\\AccessException' => $vendorDir . '/symfony/property-access/Exception/AccessException.php',
1193
+ 'Symfony\\Component\\PropertyAccess\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/property-access/Exception/ExceptionInterface.php',
1194
+ 'Symfony\\Component\\PropertyAccess\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/property-access/Exception/InvalidArgumentException.php',
1195
+ 'Symfony\\Component\\PropertyAccess\\Exception\\InvalidPropertyPathException' => $vendorDir . '/symfony/property-access/Exception/InvalidPropertyPathException.php',
1196
+ 'Symfony\\Component\\PropertyAccess\\Exception\\NoSuchIndexException' => $vendorDir . '/symfony/property-access/Exception/NoSuchIndexException.php',
1197
+ 'Symfony\\Component\\PropertyAccess\\Exception\\NoSuchPropertyException' => $vendorDir . '/symfony/property-access/Exception/NoSuchPropertyException.php',
1198
+ 'Symfony\\Component\\PropertyAccess\\Exception\\OutOfBoundsException' => $vendorDir . '/symfony/property-access/Exception/OutOfBoundsException.php',
1199
+ 'Symfony\\Component\\PropertyAccess\\Exception\\RuntimeException' => $vendorDir . '/symfony/property-access/Exception/RuntimeException.php',
1200
+ 'Symfony\\Component\\PropertyAccess\\Exception\\UnexpectedTypeException' => $vendorDir . '/symfony/property-access/Exception/UnexpectedTypeException.php',
1201
+ 'Symfony\\Component\\PropertyAccess\\PropertyAccess' => $vendorDir . '/symfony/property-access/PropertyAccess.php',
1202
+ 'Symfony\\Component\\PropertyAccess\\PropertyAccessor' => $vendorDir . '/symfony/property-access/PropertyAccessor.php',
1203
+ 'Symfony\\Component\\PropertyAccess\\PropertyAccessorBuilder' => $vendorDir . '/symfony/property-access/PropertyAccessorBuilder.php',
1204
+ 'Symfony\\Component\\PropertyAccess\\PropertyAccessorInterface' => $vendorDir . '/symfony/property-access/PropertyAccessorInterface.php',
1205
+ 'Symfony\\Component\\PropertyAccess\\PropertyPath' => $vendorDir . '/symfony/property-access/PropertyPath.php',
1206
+ 'Symfony\\Component\\PropertyAccess\\PropertyPathBuilder' => $vendorDir . '/symfony/property-access/PropertyPathBuilder.php',
1207
+ 'Symfony\\Component\\PropertyAccess\\PropertyPathInterface' => $vendorDir . '/symfony/property-access/PropertyPathInterface.php',
1208
+ 'Symfony\\Component\\PropertyAccess\\PropertyPathIterator' => $vendorDir . '/symfony/property-access/PropertyPathIterator.php',
1209
+ 'Symfony\\Component\\PropertyAccess\\PropertyPathIteratorInterface' => $vendorDir . '/symfony/property-access/PropertyPathIteratorInterface.php',
1210
+ 'Symfony\\Component\\PropertyAccess\\StringUtil' => $vendorDir . '/symfony/property-access/StringUtil.php',
1211
  'Symfony\\Component\\Translation\\Catalogue\\AbstractOperation' => $vendorDir . '/symfony/translation/Catalogue/AbstractOperation.php',
1212
  'Symfony\\Component\\Translation\\Catalogue\\MergeOperation' => $vendorDir . '/symfony/translation/Catalogue/MergeOperation.php',
1213
  'Symfony\\Component\\Translation\\Catalogue\\OperationInterface' => $vendorDir . '/symfony/translation/Catalogue/OperationInterface.php',
1677
  'ZxcvbnPhp\\Scorer' => $vendorDir . '/fernleafsystems/zxcvbn-php/src/Scorer.php',
1678
  'ZxcvbnPhp\\TimeEstimator' => $vendorDir . '/fernleafsystems/zxcvbn-php/src/TimeEstimator.php',
1679
  'ZxcvbnPhp\\Zxcvbn' => $vendorDir . '/fernleafsystems/zxcvbn-php/src/Zxcvbn.php',
1680
+ 'Zxing\\Binarizer' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/Binarizer.php',
1681
+ 'Zxing\\BinaryBitmap' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/BinaryBitmap.php',
1682
+ 'Zxing\\ChecksumException' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/ChecksumException.php',
1683
+ 'Zxing\\Common\\BitArray' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/BitArray.php',
1684
+ 'Zxing\\Common\\BitMatrix' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/BitMatrix.php',
1685
+ 'Zxing\\Common\\BitSource' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/BitSource.php',
1686
+ 'Zxing\\Common\\CharacterSetECI' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/CharacterSetEci.php',
1687
+ 'Zxing\\Common\\CharacterSetEci\\AbstractEnum\\AbstractEnum' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/AbstractEnum.php',
1688
+ 'Zxing\\Common\\DecoderResult' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/DecoderResult.php',
1689
+ 'Zxing\\Common\\DefaultGridSampler' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/DefaultGridSampler.php',
1690
+ 'Zxing\\Common\\DetectorResult' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/DetectorResult.php',
1691
+ 'Zxing\\Common\\Detector\\MathUtils' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/detector/MathUtils.php',
1692
+ 'Zxing\\Common\\Detector\\MonochromeRectangleDetector' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/detector/MonochromeRectangleDetector.php',
1693
+ 'Zxing\\Common\\GlobalHistogramBinarizer' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/GlobalHistogramBinarizer.php',
1694
+ 'Zxing\\Common\\GridSampler' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/GridSampler.php',
1695
+ 'Zxing\\Common\\HybridBinarizer' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/HybridBinarizer.php',
1696
+ 'Zxing\\Common\\PerspectiveTransform' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/PerspectiveTransform.php',
1697
+ 'Zxing\\Common\\Reedsolomon\\GenericGF' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/GenericGF.php',
1698
+ 'Zxing\\Common\\Reedsolomon\\GenericGFPoly' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/GenericGFPoly.php',
1699
+ 'Zxing\\Common\\Reedsolomon\\ReedSolomonDecoder' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/ReedSolomonDecoder.php',
1700
+ 'Zxing\\Common\\Reedsolomon\\ReedSolomonException' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/ReedSolomonException.php',
1701
+ 'Zxing\\FormatException' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/FormatException.php',
1702
+ 'Zxing\\GDLuminanceSource' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/GDLuminanceSource.php',
1703
+ 'Zxing\\IMagickLuminanceSource' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/IMagickLuminanceSource.php',
1704
+ 'Zxing\\LuminanceSource' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/LuminanceSource.php',
1705
+ 'Zxing\\NotFoundException' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/NotFoundException.php',
1706
+ 'Zxing\\PlanarYUVLuminanceSource' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/PlanarYUVLuminanceSource.php',
1707
+ 'Zxing\\Qrcode\\Decoder\\BitMatrixParser' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/BitMatrixParser.php',
1708
+ 'Zxing\\Qrcode\\Decoder\\DataBlock' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataBlock.php',
1709
+ 'Zxing\\Qrcode\\Decoder\\DataMask' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
1710
+ 'Zxing\\Qrcode\\Decoder\\DataMask000' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
1711
+ 'Zxing\\Qrcode\\Decoder\\DataMask001' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
1712
+ 'Zxing\\Qrcode\\Decoder\\DataMask010' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
1713
+ 'Zxing\\Qrcode\\Decoder\\DataMask011' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
1714
+ 'Zxing\\Qrcode\\Decoder\\DataMask100' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
1715
+ 'Zxing\\Qrcode\\Decoder\\DataMask101' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
1716
+ 'Zxing\\Qrcode\\Decoder\\DataMask110' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
1717
+ 'Zxing\\Qrcode\\Decoder\\DataMask111' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
1718
+ 'Zxing\\Qrcode\\Decoder\\DecodedBitStreamParser' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DecodedBitStreamParser.php',
1719
+ 'Zxing\\Qrcode\\Decoder\\Decoder' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Decoder.php',
1720
+ 'Zxing\\Qrcode\\Decoder\\ECB' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Version.php',
1721
+ 'Zxing\\Qrcode\\Decoder\\ECBlocks' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Version.php',
1722
+ 'Zxing\\Qrcode\\Decoder\\ErrorCorrectionLevel' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/ErrorCorrectionLevel.php',
1723
+ 'Zxing\\Qrcode\\Decoder\\FormatInformation' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/FormatInformation.php',
1724
+ 'Zxing\\Qrcode\\Decoder\\Mode' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Mode.php',
1725
+ 'Zxing\\Qrcode\\Decoder\\Version' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Version.php',
1726
+ 'Zxing\\Qrcode\\Detector\\AlignmentPattern' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/AlignmentPattern.php',
1727
+ 'Zxing\\Qrcode\\Detector\\AlignmentPatternFinder' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/AlignmentPatternFinder.php',
1728
+ 'Zxing\\Qrcode\\Detector\\Detector' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/Detector.php',
1729
+ 'Zxing\\Qrcode\\Detector\\FinderPattern' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/FinderPattern.php',
1730
+ 'Zxing\\Qrcode\\Detector\\FinderPatternFinder' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/FinderPatternFinder.php',
1731
+ 'Zxing\\Qrcode\\Detector\\FinderPatternInfo' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/FinderPatternInfo.php',
1732
+ 'Zxing\\Qrcode\\QRCodeReader' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/QRCodeReader.php',
1733
+ 'Zxing\\RGBLuminanceSource' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/RGBLuminanceSource.php',
1734
+ 'Zxing\\Reader' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/Reader.php',
1735
+ 'Zxing\\ReaderException' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/ReaderException.php',
1736
+ 'Zxing\\Result' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/Result.php',
1737
+ 'Zxing\\ResultPoint' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/ResultPoint.php',
1738
  'u2flib_server\\Error' => $baseDir . '/custom/U2F/Yubico/U2F.php',
1739
  'u2flib_server\\RegisterRequest' => $baseDir . '/custom/U2F/Yubico/U2F.php',
1740
  'u2flib_server\\Registration' => $baseDir . '/custom/U2F/Yubico/U2F.php',
src/lib/vendor/composer/autoload_files.php CHANGED
@@ -6,8 +6,9 @@ $vendorDir = dirname(dirname(__FILE__));
6
  $baseDir = dirname($vendorDir);
7
 
8
  return array(
9
- '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
10
  '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
 
 
11
  'e39a8b23c42d4e1452234d762b03835a' => $vendorDir . '/ramsey/uuid/src/functions.php',
12
  'def43f6c87e4f8dfd0c9e1b1bab14fe8' => $vendorDir . '/symfony/polyfill-iconv/bootstrap.php',
13
  'b14ca0bb4d408c293d6ea9b68f1b4abe' => $baseDir . '/functions/functions.php',
6
  $baseDir = dirname($vendorDir);
7
 
8
  return array(
 
9
  '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
10
+ '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
11
+ '626dcc41390ebdaa619faa02d99943b0' => $vendorDir . '/khanamiryan/qrcode-detector-decoder/lib/common/customFunctions.php',
12
  'e39a8b23c42d4e1452234d762b03835a' => $vendorDir . '/ramsey/uuid/src/functions.php',
13
  'def43f6c87e4f8dfd0c9e1b1bab14fe8' => $vendorDir . '/symfony/polyfill-iconv/bootstrap.php',
14
  'b14ca0bb4d408c293d6ea9b68f1b4abe' => $baseDir . '/functions/functions.php',
src/lib/vendor/composer/autoload_namespaces.php CHANGED
@@ -9,5 +9,6 @@ return array(
9
  'UpdateHelper\\' => array($vendorDir . '/kylekatarnls/update-helper/src'),
10
  'Twig_' => array($vendorDir . '/twig/twig/lib'),
11
  'Pimple' => array($vendorDir . '/pimple/pimple/src'),
 
12
  '' => array($vendorDir . '/elliotchance/iterator/tests', $vendorDir . '/elliotchance/iterator/src'),
13
  );
9
  'UpdateHelper\\' => array($vendorDir . '/kylekatarnls/update-helper/src'),
10
  'Twig_' => array($vendorDir . '/twig/twig/lib'),
11
  'Pimple' => array($vendorDir . '/pimple/pimple/src'),
12
+ 'BaconQrCode' => array($vendorDir . '/bacon/bacon-qr-code/src'),
13
  '' => array($vendorDir . '/elliotchance/iterator/tests', $vendorDir . '/elliotchance/iterator/src'),
14
  );
src/lib/vendor/composer/autoload_psr4.php CHANGED
@@ -13,15 +13,19 @@ return array(
13
  'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
14
  'Symfony\\Component\\Yaml\\' => array($vendorDir . '/symfony/yaml'),
15
  'Symfony\\Component\\Translation\\' => array($vendorDir . '/symfony/translation'),
 
 
16
  'ReCaptcha\\' => array($vendorDir . '/google/recaptcha/src/ReCaptcha'),
17
  'Ramsey\\Uuid\\' => array($vendorDir . '/ramsey/uuid/src'),
18
  'Psr\\Container\\' => array($vendorDir . '/psr/container/src'),
19
  'Psr\\Cache\\' => array($vendorDir . '/psr/cache/src'),
 
20
  'LZCompressor\\' => array($vendorDir . '/nullpunkt/lz-string-php/src/LZCompressor'),
21
  'Html2Text\\' => array($vendorDir . '/soundasleep/html2text/src'),
22
  'FernleafSystems\\Wordpress\\Services\\' => array($vendorDir . '/fernleafsystems/wordpress-services/src'),
23
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\' => array($baseDir . '/src'),
24
  'FernleafSystems\\Utilities\\' => array($vendorDir . '/fernleafsystems/utilities/src'),
 
25
  'Dolondro\\GoogleAuthenticator\\' => array($vendorDir . '/dolondro/google-authenticator/src'),
26
  'Base32\\' => array($vendorDir . '/christian-riesen/base32/src'),
27
  '' => array($vendorDir . '/nesbot/carbon/src'),
13
  'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
14
  'Symfony\\Component\\Yaml\\' => array($vendorDir . '/symfony/yaml'),
15
  'Symfony\\Component\\Translation\\' => array($vendorDir . '/symfony/translation'),
16
+ 'Symfony\\Component\\PropertyAccess\\' => array($vendorDir . '/symfony/property-access'),
17
+ 'Symfony\\Component\\OptionsResolver\\' => array($vendorDir . '/symfony/options-resolver'),
18
  'ReCaptcha\\' => array($vendorDir . '/google/recaptcha/src/ReCaptcha'),
19
  'Ramsey\\Uuid\\' => array($vendorDir . '/ramsey/uuid/src'),
20
  'Psr\\Container\\' => array($vendorDir . '/psr/container/src'),
21
  'Psr\\Cache\\' => array($vendorDir . '/psr/cache/src'),
22
+ 'MyCLabs\\Enum\\' => array($vendorDir . '/myclabs/php-enum/src'),
23
  'LZCompressor\\' => array($vendorDir . '/nullpunkt/lz-string-php/src/LZCompressor'),
24
  'Html2Text\\' => array($vendorDir . '/soundasleep/html2text/src'),
25
  'FernleafSystems\\Wordpress\\Services\\' => array($vendorDir . '/fernleafsystems/wordpress-services/src'),
26
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\' => array($baseDir . '/src'),
27
  'FernleafSystems\\Utilities\\' => array($vendorDir . '/fernleafsystems/utilities/src'),
28
+ 'Endroid\\QrCode\\' => array($vendorDir . '/endroid/qr-code/src'),
29
  'Dolondro\\GoogleAuthenticator\\' => array($vendorDir . '/dolondro/google-authenticator/src'),
30
  'Base32\\' => array($vendorDir . '/christian-riesen/base32/src'),
31
  '' => array($vendorDir . '/nesbot/carbon/src'),
src/lib/vendor/composer/autoload_static.php CHANGED
@@ -7,8 +7,9 @@ namespace Composer\Autoload;
7
  class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
8
  {
9
  public static $files = array (
10
- '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
11
  '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
 
 
12
  'e39a8b23c42d4e1452234d762b03835a' => __DIR__ . '/..' . '/ramsey/uuid/src/functions.php',
13
  'def43f6c87e4f8dfd0c9e1b1bab14fe8' => __DIR__ . '/..' . '/symfony/polyfill-iconv/bootstrap.php',
14
  'b14ca0bb4d408c293d6ea9b68f1b4abe' => __DIR__ . '/../..' . '/functions/functions.php',
@@ -30,6 +31,8 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
30
  'Symfony\\Polyfill\\Ctype\\' => 23,
31
  'Symfony\\Component\\Yaml\\' => 23,
32
  'Symfony\\Component\\Translation\\' => 30,
 
 
33
  ),
34
  'R' =>
35
  array (
@@ -41,6 +44,10 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
41
  'Psr\\Container\\' => 14,
42
  'Psr\\Cache\\' => 10,
43
  ),
 
 
 
 
44
  'L' =>
45
  array (
46
  'LZCompressor\\' => 13,
@@ -55,6 +62,10 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
55
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\' => 40,
56
  'FernleafSystems\\Utilities\\' => 26,
57
  ),
 
 
 
 
58
  'D' =>
59
  array (
60
  'Dolondro\\GoogleAuthenticator\\' => 29,
@@ -94,6 +105,14 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
94
  array (
95
  0 => __DIR__ . '/..' . '/symfony/translation',
96
  ),
 
 
 
 
 
 
 
 
97
  'ReCaptcha\\' =>
98
  array (
99
  0 => __DIR__ . '/..' . '/google/recaptcha/src/ReCaptcha',
@@ -110,6 +129,10 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
110
  array (
111
  0 => __DIR__ . '/..' . '/psr/cache/src',
112
  ),
 
 
 
 
113
  'LZCompressor\\' =>
114
  array (
115
  0 => __DIR__ . '/..' . '/nullpunkt/lz-string-php/src/LZCompressor',
@@ -130,6 +153,10 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
130
  array (
131
  0 => __DIR__ . '/..' . '/fernleafsystems/utilities/src',
132
  ),
 
 
 
 
133
  'Dolondro\\GoogleAuthenticator\\' =>
134
  array (
135
  0 => __DIR__ . '/..' . '/dolondro/google-authenticator/src',
@@ -166,6 +193,13 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
166
  0 => __DIR__ . '/..' . '/pimple/pimple/src',
167
  ),
168
  ),
 
 
 
 
 
 
 
169
  );
170
 
171
  public static $fallbackDirsPsr0 = array (
@@ -174,6 +208,45 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
174
  );
175
 
176
  public static $classMap = array (
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  'Base32\\Base32' => __DIR__ . '/..' . '/christian-riesen/base32/src/Base32.php',
178
  'Carbon\\Carbon' => __DIR__ . '/..' . '/nesbot/carbon/src/Carbon/Carbon.php',
179
  'Carbon\\CarbonInterval' => __DIR__ . '/..' . '/nesbot/carbon/src/Carbon/CarbonInterval.php',
@@ -191,11 +264,40 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
191
  'Dolondro\\GoogleAuthenticator\\SecretFactory' => __DIR__ . '/..' . '/dolondro/google-authenticator/src/SecretFactory.php',
192
  'Elliotchance\\Iterator\\AbstractPagedIterator' => __DIR__ . '/..' . '/elliotchance/iterator/src/Elliotchance/Iterator/AbstractPagedIterator.php',
193
  'Elliotchance\\Iterator\\PagedIteratorTest' => __DIR__ . '/..' . '/elliotchance/iterator/tests/Elliotchance/Iterator/PagedIteratorTest.php',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
  'FernleafSystems\\Utilities\\Data\\Adapter\\DynProperties' => __DIR__ . '/..' . '/fernleafsystems/utilities/src/Data/Adapter/DynProperties.php',
195
  'FernleafSystems\\Utilities\\Data\\Adapter\\DynPropertiesClass' => __DIR__ . '/..' . '/fernleafsystems/utilities/src/Data/Adapter/DynPropertiesClass.php',
196
  'FernleafSystems\\Utilities\\Data\\Adapter\\DynamicProperties' => __DIR__ . '/..' . '/fernleafsystems/utilities/src/Data/Adapter/DynamicProperties.php',
197
  'FernleafSystems\\Utilities\\Data\\Adapter\\StdClassAdapter' => __DIR__ . '/..' . '/fernleafsystems/utilities/src/Data/Adapter/StdClassAdapter.php',
198
  'FernleafSystems\\Utilities\\Data\\CaptureOutput' => __DIR__ . '/..' . '/fernleafsystems/utilities/src/Data/CaptureOutput.php',
 
199
  'FernleafSystems\\Utilities\\Logic\\ExecOnce' => __DIR__ . '/..' . '/fernleafsystems/utilities/src/Logic/ExecOnce.php',
200
  'FernleafSystems\\Utilities\\Logic\\OneTimeExecute' => __DIR__ . '/..' . '/fernleafsystems/utilities/src/Logic/OneTimeExecute.php',
201
  'FernleafSystems\\Utilities\\Response' => __DIR__ . '/..' . '/fernleafsystems/utilities/src/Response.php',
@@ -231,6 +333,7 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
231
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Ajax\\Response' => __DIR__ . '/../..' . '/src/Controller/Ajax/Response.php',
232
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Assets\\Enqueue' => __DIR__ . '/../..' . '/src/Controller/Assets/Enqueue.php',
233
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Assets\\Paths' => __DIR__ . '/../..' . '/src/Controller/Assets/Paths.php',
 
234
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Assets\\Urls' => __DIR__ . '/../..' . '/src/Controller/Assets/Urls.php',
235
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Config\\ConfigVO' => __DIR__ . '/../..' . '/src/Controller/Config/ConfigVO.php',
236
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Config\\Ops\\LoadConfig' => __DIR__ . '/../..' . '/src/Controller/Config/Ops/LoadConfig.php',
@@ -374,21 +477,33 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
374
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Autoupdates\\Processor' => __DIR__ . '/../..' . '/src/Modules/Autoupdates/Processor.php',
375
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Autoupdates\\Strings' => __DIR__ . '/../..' . '/src/Modules/Autoupdates/Strings.php',
376
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Autoupdates\\UI' => __DIR__ . '/../..' . '/src/Modules/Autoupdates/UI.php',
 
377
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\AjaxHandler' => __DIR__ . '/../..' . '/src/Modules/BaseShield/AjaxHandler.php',
378
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\ModCon' => __DIR__ . '/../..' . '/src/Modules/BaseShield/ModCon.php',
379
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\Options' => __DIR__ . '/../..' . '/src/Modules/BaseShield/Options.php',
380
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\Processor' => __DIR__ . '/../..' . '/src/Modules/BaseShield/Processor.php',
381
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\UI' => __DIR__ . '/../..' . '/src/Modules/BaseShield/UI.php',
382
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\AdminNotices' => __DIR__ . '/../..' . '/src/Modules/Base/AdminNotices.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',
390
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Processor' => __DIR__ . '/../..' . '/src/Modules/Base/Processor.php',
391
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Reporting' => __DIR__ . '/../..' . '/src/Modules/Base/Reporting.php',
 
392
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Strings' => __DIR__ . '/../..' . '/src/Modules/Base/Strings.php',
393
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\UI' => __DIR__ . '/../..' . '/src/Modules/Base/UI.php',
394
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Upgrade' => __DIR__ . '/../..' . '/src/Modules/Base/Upgrade.php',
@@ -576,14 +691,45 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
576
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\WpCli\\BaseAddRemove' => __DIR__ . '/../..' . '/src/Modules/IPs/WpCli/BaseAddRemove.php',
577
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\WpCli\\Enumerate' => __DIR__ . '/../..' . '/src/Modules/IPs/WpCli/Enumerate.php',
578
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\WpCli\\Remove' => __DIR__ . '/../..' . '/src/Modules/IPs/WpCli/Remove.php',
 
579
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\AjaxHandler' => __DIR__ . '/../..' . '/src/Modules/Insights/AjaxHandler.php',
580
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Lib\\OverviewCards' => __DIR__ . '/../..' . '/src/Modules/Insights/Lib/OverviewCards.php',
581
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Lib\\Requests\\DynamicPageLoader' => __DIR__ . '/../..' . '/src/Modules/Insights/Lib/Requests/DynamicPageLoader.php',
582
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Lib\\SideMenuBuilder' => __DIR__ . '/../..' . '/src/Modules/Insights/Lib/SideMenuBuilder.php',
 
583
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\ModCon' => __DIR__ . '/../..' . '/src/Modules/Insights/ModCon.php',
584
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Options' => __DIR__ . '/../..' . '/src/Modules/Insights/Options.php',
585
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Strings' => __DIR__ . '/../..' . '/src/Modules/Insights/Strings.php',
586
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\UI' => __DIR__ . '/../..' . '/src/Modules/Insights/UI.php',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
587
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\MainWP\\Client\\Actions\\ApiActionInit' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/MainWP/Client/Actions/ApiActionInit.php',
588
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\MainWP\\Client\\Actions\\Init' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/MainWP/Client/Actions/Init.php',
589
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\MainWP\\Client\\Actions\\Sync' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/MainWP/Client/Actions/Sync.php',
@@ -628,6 +774,8 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
628
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Options' => __DIR__ . '/../..' . '/src/Modules/Integrations/Options.php',
629
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Processor' => __DIR__ . '/../..' . '/src/Modules/Integrations/Processor.php',
630
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Strings' => __DIR__ . '/../..' . '/src/Modules/Integrations/Strings.php',
 
 
631
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\AdminNotices' => __DIR__ . '/../..' . '/src/Modules/License/AdminNotices.php',
632
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\AjaxHandler' => __DIR__ . '/../..' . '/src/Modules/License/AjaxHandler.php',
633
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Lib\\LicenseEmails' => __DIR__ . '/../..' . '/src/Modules/License/Lib/LicenseEmails.php',
@@ -678,11 +826,11 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
678
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\LoginIntentPage' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/LoginIntentPage.php',
679
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\MfaController' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/MfaController.php',
680
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\MfaControllerConsumer' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/MfaControllerConsumer.php',
 
681
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\MfaSkip' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/MfaSkip.php',
682
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Profiles\\CustomForms' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Profiles/CustomForms.php',
683
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\Backup' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Backup.php',
684
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\BaseProvider' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/BaseProvider.php',
685
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\BaseProviderV2' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/BaseProviderV2.php',
686
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\Email' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Email.php',
687
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\GoogleAuth' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/GoogleAuth.php',
688
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\ProviderInterface' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/ProviderInterface.php',
@@ -772,8 +920,8 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
772
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\Restrictions\\WpOptions' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/WpOptions.php',
773
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\SecurityAdminController' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/SecurityAdminController.php',
774
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\VerifySecurityAdminList' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/VerifySecurityAdminList.php',
775
- 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\WhiteLabel\\ApplyLabels' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/WhiteLabel/ApplyLabels.php',
776
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\WhiteLabel\\BuildOptions' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/WhiteLabel/BuildOptions.php',
 
777
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\ModCon' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/ModCon.php',
778
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Options' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Options.php',
779
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Processor' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Processor.php',
@@ -783,6 +931,7 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
783
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\WpCli\\AdminAdd' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/WpCli/AdminAdd.php',
784
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\WpCli\\AdminRemove' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/WpCli/AdminRemove.php',
785
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\WpCli\\Pin' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/WpCli/Pin.php',
 
786
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Sessions\\Lib\\Ops\\Terminate' => __DIR__ . '/../..' . '/src/Modules/Sessions/Lib/Ops/Terminate.php',
787
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Sessions\\Lib\\SessionController' => __DIR__ . '/../..' . '/src/Modules/Sessions/Lib/SessionController.php',
788
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Sessions\\ModCon' => __DIR__ . '/../..' . '/src/Modules/Sessions/ModCon.php',
@@ -942,6 +1091,10 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
942
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Build\\ScanWpv' => __DIR__ . '/../..' . '/src/Tables/Build/ScanWpv.php',
943
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Build\\Sessions' => __DIR__ . '/../..' . '/src/Tables/Build/Sessions.php',
944
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Build\\Traffic' => __DIR__ . '/../..' . '/src/Tables/Build/Traffic.php',
 
 
 
 
945
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\WpCliTable\\AuditTrail' => __DIR__ . '/../..' . '/src/Tables/Render/WpCliTable/AuditTrail.php',
946
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\WpCliTable\\Base' => __DIR__ . '/../..' . '/src/Tables/Render/WpCliTable/Base.php',
947
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\WpListTable\\AdminNotes' => __DIR__ . '/../..' . '/src/Tables/Render/WpListTable/AdminNotes.php',
@@ -1089,7 +1242,6 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
1089
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Keyless\\Base' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Base.php',
1090
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Keyless\\Lookup' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Lookup.php',
1091
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Keyless\\Ping' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Ping.php',
1092
- 'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Lookup' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Lookup.php',
1093
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\BaseIP' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Net/BaseIP.php',
1094
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\FindSourceFromIp' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Net/FindSourceFromIp.php',
1095
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\IpID' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Net/IpID.php',
@@ -1146,6 +1298,7 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
1146
  'LZCompressor\\LZString' => __DIR__ . '/..' . '/nullpunkt/lz-string-php/src/LZCompressor/LZString.php',
1147
  'LZCompressor\\LZUtil' => __DIR__ . '/..' . '/nullpunkt/lz-string-php/src/LZCompressor/LZUtil.php',
1148
  'LZCompressor\\LZUtil16' => __DIR__ . '/..' . '/nullpunkt/lz-string-php/src/LZCompressor/LZUtil16.php',
 
1149
  'Pimple\\Container' => __DIR__ . '/..' . '/pimple/pimple/src/Pimple/Container.php',
1150
  'Pimple\\Exception\\ExpectedInvokableException' => __DIR__ . '/..' . '/pimple/pimple/src/Pimple/Exception/ExpectedInvokableException.php',
1151
  'Pimple\\Exception\\FrozenServiceException' => __DIR__ . '/..' . '/pimple/pimple/src/Pimple/Exception/FrozenServiceException.php',
@@ -1171,6 +1324,7 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
1171
  'Psr\\Container\\ContainerExceptionInterface' => __DIR__ . '/..' . '/psr/container/src/ContainerExceptionInterface.php',
1172
  'Psr\\Container\\ContainerInterface' => __DIR__ . '/..' . '/psr/container/src/ContainerInterface.php',
1173
  'Psr\\Container\\NotFoundExceptionInterface' => __DIR__ . '/..' . '/psr/container/src/NotFoundExceptionInterface.php',
 
1174
  'Ramsey\\Uuid\\BinaryUtils' => __DIR__ . '/..' . '/ramsey/uuid/src/BinaryUtils.php',
1175
  'Ramsey\\Uuid\\Builder\\DefaultUuidBuilder' => __DIR__ . '/..' . '/ramsey/uuid/src/Builder/DefaultUuidBuilder.php',
1176
  'Ramsey\\Uuid\\Builder\\DegradedUuidBuilder' => __DIR__ . '/..' . '/ramsey/uuid/src/Builder/DegradedUuidBuilder.php',
@@ -1226,6 +1380,36 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
1226
  'ReCaptcha\\RequestMethod\\SocketPost' => __DIR__ . '/..' . '/google/recaptcha/src/ReCaptcha/RequestMethod/SocketPost.php',
1227
  'ReCaptcha\\RequestParameters' => __DIR__ . '/..' . '/google/recaptcha/src/ReCaptcha/RequestParameters.php',
1228
  'ReCaptcha\\Response' => __DIR__ . '/..' . '/google/recaptcha/src/ReCaptcha/Response.php',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1229
  'Symfony\\Component\\Translation\\Catalogue\\AbstractOperation' => __DIR__ . '/..' . '/symfony/translation/Catalogue/AbstractOperation.php',
1230
  'Symfony\\Component\\Translation\\Catalogue\\MergeOperation' => __DIR__ . '/..' . '/symfony/translation/Catalogue/MergeOperation.php',
1231
  'Symfony\\Component\\Translation\\Catalogue\\OperationInterface' => __DIR__ . '/..' . '/symfony/translation/Catalogue/OperationInterface.php',
@@ -1695,6 +1879,64 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
1695
  'ZxcvbnPhp\\Scorer' => __DIR__ . '/..' . '/fernleafsystems/zxcvbn-php/src/Scorer.php',
1696
  'ZxcvbnPhp\\TimeEstimator' => __DIR__ . '/..' . '/fernleafsystems/zxcvbn-php/src/TimeEstimator.php',
1697
  'ZxcvbnPhp\\Zxcvbn' => __DIR__ . '/..' . '/fernleafsystems/zxcvbn-php/src/Zxcvbn.php',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1698
  'u2flib_server\\Error' => __DIR__ . '/../..' . '/custom/U2F/Yubico/U2F.php',
1699
  'u2flib_server\\RegisterRequest' => __DIR__ . '/../..' . '/custom/U2F/Yubico/U2F.php',
1700
  'u2flib_server\\Registration' => __DIR__ . '/../..' . '/custom/U2F/Yubico/U2F.php',
7
  class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
8
  {
9
  public static $files = array (
 
10
  '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
11
+ '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
12
+ '626dcc41390ebdaa619faa02d99943b0' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/customFunctions.php',
13
  'e39a8b23c42d4e1452234d762b03835a' => __DIR__ . '/..' . '/ramsey/uuid/src/functions.php',
14
  'def43f6c87e4f8dfd0c9e1b1bab14fe8' => __DIR__ . '/..' . '/symfony/polyfill-iconv/bootstrap.php',
15
  'b14ca0bb4d408c293d6ea9b68f1b4abe' => __DIR__ . '/../..' . '/functions/functions.php',
31
  'Symfony\\Polyfill\\Ctype\\' => 23,
32
  'Symfony\\Component\\Yaml\\' => 23,
33
  'Symfony\\Component\\Translation\\' => 30,
34
+ 'Symfony\\Component\\PropertyAccess\\' => 33,
35
+ 'Symfony\\Component\\OptionsResolver\\' => 34,
36
  ),
37
  'R' =>
38
  array (
44
  'Psr\\Container\\' => 14,
45
  'Psr\\Cache\\' => 10,
46
  ),
47
+ 'M' =>
48
+ array (
49
+ 'MyCLabs\\Enum\\' => 13,
50
+ ),
51
  'L' =>
52
  array (
53
  'LZCompressor\\' => 13,
62
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\' => 40,
63
  'FernleafSystems\\Utilities\\' => 26,
64
  ),
65
+ 'E' =>
66
+ array (
67
+ 'Endroid\\QrCode\\' => 15,
68
+ ),
69
  'D' =>
70
  array (
71
  'Dolondro\\GoogleAuthenticator\\' => 29,
105
  array (
106
  0 => __DIR__ . '/..' . '/symfony/translation',
107
  ),
108
+ 'Symfony\\Component\\PropertyAccess\\' =>
109
+ array (
110
+ 0 => __DIR__ . '/..' . '/symfony/property-access',
111
+ ),
112
+ 'Symfony\\Component\\OptionsResolver\\' =>
113
+ array (
114
+ 0 => __DIR__ . '/..' . '/symfony/options-resolver',
115
+ ),
116
  'ReCaptcha\\' =>
117
  array (
118
  0 => __DIR__ . '/..' . '/google/recaptcha/src/ReCaptcha',
129
  array (
130
  0 => __DIR__ . '/..' . '/psr/cache/src',
131
  ),
132
+ 'MyCLabs\\Enum\\' =>
133
+ array (
134
+ 0 => __DIR__ . '/..' . '/myclabs/php-enum/src',
135
+ ),
136
  'LZCompressor\\' =>
137
  array (
138
  0 => __DIR__ . '/..' . '/nullpunkt/lz-string-php/src/LZCompressor',
153
  array (
154
  0 => __DIR__ . '/..' . '/fernleafsystems/utilities/src',
155
  ),
156
+ 'Endroid\\QrCode\\' =>
157
+ array (
158
+ 0 => __DIR__ . '/..' . '/endroid/qr-code/src',
159
+ ),
160
  'Dolondro\\GoogleAuthenticator\\' =>
161
  array (
162
  0 => __DIR__ . '/..' . '/dolondro/google-authenticator/src',
193
  0 => __DIR__ . '/..' . '/pimple/pimple/src',
194
  ),
195
  ),
196
+ 'B' =>
197
+ array (
198
+ 'BaconQrCode' =>
199
+ array (
200
+ 0 => __DIR__ . '/..' . '/bacon/bacon-qr-code/src',
201
+ ),
202
+ ),
203
  );
204
 
205
  public static $fallbackDirsPsr0 = array (
208
  );
209
 
210
  public static $classMap = array (
211
+ 'BaconQrCode\\Common\\AbstractEnum' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Common/AbstractEnum.php',
212
+ 'BaconQrCode\\Common\\BitArray' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Common/BitArray.php',
213
+ 'BaconQrCode\\Common\\BitMatrix' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Common/BitMatrix.php',
214
+ 'BaconQrCode\\Common\\BitUtils' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Common/BitUtils.php',
215
+ 'BaconQrCode\\Common\\CharacterSetEci' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Common/CharacterSetEci.php',
216
+ 'BaconQrCode\\Common\\EcBlock' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Common/EcBlock.php',
217
+ 'BaconQrCode\\Common\\EcBlocks' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Common/EcBlocks.php',
218
+ 'BaconQrCode\\Common\\ErrorCorrectionLevel' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Common/ErrorCorrectionLevel.php',
219
+ 'BaconQrCode\\Common\\FormatInformation' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Common/FormatInformation.php',
220
+ 'BaconQrCode\\Common\\Mode' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Common/Mode.php',
221
+ 'BaconQrCode\\Common\\ReedSolomonCodec' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Common/ReedSolomonCodec.php',
222
+ 'BaconQrCode\\Common\\Version' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Common/Version.php',
223
+ 'BaconQrCode\\Encoder\\BlockPair' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Encoder/BlockPair.php',
224
+ 'BaconQrCode\\Encoder\\ByteMatrix' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Encoder/ByteMatrix.php',
225
+ 'BaconQrCode\\Encoder\\Encoder' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Encoder/Encoder.php',
226
+ 'BaconQrCode\\Encoder\\MaskUtil' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Encoder/MaskUtil.php',
227
+ 'BaconQrCode\\Encoder\\MatrixUtil' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Encoder/MatrixUtil.php',
228
+ 'BaconQrCode\\Encoder\\QrCode' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Encoder/QrCode.php',
229
+ 'BaconQrCode\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Exception/ExceptionInterface.php',
230
+ 'BaconQrCode\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Exception/InvalidArgumentException.php',
231
+ 'BaconQrCode\\Exception\\OutOfBoundsException' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Exception/OutOfBoundsException.php',
232
+ 'BaconQrCode\\Exception\\RuntimeException' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Exception/RuntimeException.php',
233
+ 'BaconQrCode\\Exception\\UnexpectedValueException' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Exception/UnexpectedValueException.php',
234
+ 'BaconQrCode\\Exception\\WriterException' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Exception/WriterException.php',
235
+ 'BaconQrCode\\Renderer\\Color\\Cmyk' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/Cmyk.php',
236
+ 'BaconQrCode\\Renderer\\Color\\ColorInterface' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/ColorInterface.php',
237
+ 'BaconQrCode\\Renderer\\Color\\Gray' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/Gray.php',
238
+ 'BaconQrCode\\Renderer\\Color\\Rgb' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Color/Rgb.php',
239
+ 'BaconQrCode\\Renderer\\Image\\AbstractRenderer' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/AbstractRenderer.php',
240
+ 'BaconQrCode\\Renderer\\Image\\Decorator\\DecoratorInterface' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Decorator/DecoratorInterface.php',
241
+ 'BaconQrCode\\Renderer\\Image\\Decorator\\FinderPattern' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Decorator/FinderPattern.php',
242
+ 'BaconQrCode\\Renderer\\Image\\Eps' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Eps.php',
243
+ 'BaconQrCode\\Renderer\\Image\\Png' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Png.php',
244
+ 'BaconQrCode\\Renderer\\Image\\RendererInterface' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/RendererInterface.php',
245
+ 'BaconQrCode\\Renderer\\Image\\Svg' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Image/Svg.php',
246
+ 'BaconQrCode\\Renderer\\RendererInterface' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/RendererInterface.php',
247
+ 'BaconQrCode\\Renderer\\Text\\Html' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Text/Html.php',
248
+ 'BaconQrCode\\Renderer\\Text\\Plain' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Renderer/Text/Plain.php',
249
+ 'BaconQrCode\\Writer' => __DIR__ . '/..' . '/bacon/bacon-qr-code/src/BaconQrCode/Writer.php',
250
  'Base32\\Base32' => __DIR__ . '/..' . '/christian-riesen/base32/src/Base32.php',
251
  'Carbon\\Carbon' => __DIR__ . '/..' . '/nesbot/carbon/src/Carbon/Carbon.php',
252
  'Carbon\\CarbonInterval' => __DIR__ . '/..' . '/nesbot/carbon/src/Carbon/CarbonInterval.php',
264
  'Dolondro\\GoogleAuthenticator\\SecretFactory' => __DIR__ . '/..' . '/dolondro/google-authenticator/src/SecretFactory.php',
265
  'Elliotchance\\Iterator\\AbstractPagedIterator' => __DIR__ . '/..' . '/elliotchance/iterator/src/Elliotchance/Iterator/AbstractPagedIterator.php',
266
  'Elliotchance\\Iterator\\PagedIteratorTest' => __DIR__ . '/..' . '/elliotchance/iterator/tests/Elliotchance/Iterator/PagedIteratorTest.php',
267
+ 'Endroid\\QrCode\\Bundle\\QrCodeBundle\\Controller\\QrCodeController' => __DIR__ . '/..' . '/endroid/qr-code/src/Bundle/QrCodeBundle/Controller/QrCodeController.php',
268
+ 'Endroid\\QrCode\\Bundle\\QrCodeBundle\\DependencyInjection\\Compiler\\WriterRegistryCompilerPass' => __DIR__ . '/..' . '/endroid/qr-code/src/Bundle/QrCodeBundle/DependencyInjection/Compiler/WriterRegistryCompilerPass.php',
269
+ 'Endroid\\QrCode\\Bundle\\QrCodeBundle\\DependencyInjection\\Configuration' => __DIR__ . '/..' . '/endroid/qr-code/src/Bundle/QrCodeBundle/DependencyInjection/Configuration.php',
270
+ 'Endroid\\QrCode\\Bundle\\QrCodeBundle\\DependencyInjection\\EndroidQrCodeExtension' => __DIR__ . '/..' . '/endroid/qr-code/src/Bundle/QrCodeBundle/DependencyInjection/EndroidQrCodeExtension.php',
271
+ 'Endroid\\QrCode\\Bundle\\QrCodeBundle\\EndroidQrCodeBundle' => __DIR__ . '/..' . '/endroid/qr-code/src/Bundle/QrCodeBundle/EndroidQrCodeBundle.php',
272
+ 'Endroid\\QrCode\\ErrorCorrectionLevel' => __DIR__ . '/..' . '/endroid/qr-code/src/ErrorCorrectionLevel.php',
273
+ 'Endroid\\QrCode\\Exception\\InvalidPathException' => __DIR__ . '/..' . '/endroid/qr-code/src/Exception/InvalidPathException.php',
274
+ 'Endroid\\QrCode\\Exception\\InvalidWriterException' => __DIR__ . '/..' . '/endroid/qr-code/src/Exception/InvalidWriterException.php',
275
+ 'Endroid\\QrCode\\Exception\\MissingFunctionException' => __DIR__ . '/..' . '/endroid/qr-code/src/Exception/MissingFunctionException.php',
276
+ 'Endroid\\QrCode\\Exception\\QrCodeException' => __DIR__ . '/..' . '/endroid/qr-code/src/Exception/QrCodeException.php',
277
+ 'Endroid\\QrCode\\Exception\\UnsupportedExtensionException' => __DIR__ . '/..' . '/endroid/qr-code/src/Exception/UnsupportedExtensionException.php',
278
+ 'Endroid\\QrCode\\Exception\\ValidationException' => __DIR__ . '/..' . '/endroid/qr-code/src/Exception/ValidationException.php',
279
+ 'Endroid\\QrCode\\Factory\\QrCodeFactory' => __DIR__ . '/..' . '/endroid/qr-code/src/Factory/QrCodeFactory.php',
280
+ 'Endroid\\QrCode\\LabelAlignment' => __DIR__ . '/..' . '/endroid/qr-code/src/LabelAlignment.php',
281
+ 'Endroid\\QrCode\\QrCode' => __DIR__ . '/..' . '/endroid/qr-code/src/QrCode.php',
282
+ 'Endroid\\QrCode\\QrCodeInterface' => __DIR__ . '/..' . '/endroid/qr-code/src/QrCodeInterface.php',
283
+ 'Endroid\\QrCode\\StaticWriterRegistry' => __DIR__ . '/..' . '/endroid/qr-code/src/StaticWriterRegistry.php',
284
+ 'Endroid\\QrCode\\Twig\\Extension\\QrCodeExtension' => __DIR__ . '/..' . '/endroid/qr-code/src/Twig/Extension/QrCodeExtension.php',
285
+ 'Endroid\\QrCode\\WriterRegistry' => __DIR__ . '/..' . '/endroid/qr-code/src/WriterRegistry.php',
286
+ 'Endroid\\QrCode\\WriterRegistryInterface' => __DIR__ . '/..' . '/endroid/qr-code/src/WriterRegistryInterface.php',
287
+ 'Endroid\\QrCode\\Writer\\AbstractBaconWriter' => __DIR__ . '/..' . '/endroid/qr-code/src/Writer/AbstractBaconWriter.php',
288
+ 'Endroid\\QrCode\\Writer\\AbstractWriter' => __DIR__ . '/..' . '/endroid/qr-code/src/Writer/AbstractWriter.php',
289
+ 'Endroid\\QrCode\\Writer\\BinaryWriter' => __DIR__ . '/..' . '/endroid/qr-code/src/Writer/BinaryWriter.php',
290
+ 'Endroid\\QrCode\\Writer\\DebugWriter' => __DIR__ . '/..' . '/endroid/qr-code/src/Writer/DebugWriter.php',
291
+ 'Endroid\\QrCode\\Writer\\EpsWriter' => __DIR__ . '/..' . '/endroid/qr-code/src/Writer/EpsWriter.php',
292
+ 'Endroid\\QrCode\\Writer\\PngWriter' => __DIR__ . '/..' . '/endroid/qr-code/src/Writer/PngWriter.php',
293
+ 'Endroid\\QrCode\\Writer\\SvgWriter' => __DIR__ . '/..' . '/endroid/qr-code/src/Writer/SvgWriter.php',
294
+ 'Endroid\\QrCode\\Writer\\WriterInterface' => __DIR__ . '/..' . '/endroid/qr-code/src/Writer/WriterInterface.php',
295
  'FernleafSystems\\Utilities\\Data\\Adapter\\DynProperties' => __DIR__ . '/..' . '/fernleafsystems/utilities/src/Data/Adapter/DynProperties.php',
296
  'FernleafSystems\\Utilities\\Data\\Adapter\\DynPropertiesClass' => __DIR__ . '/..' . '/fernleafsystems/utilities/src/Data/Adapter/DynPropertiesClass.php',
297
  'FernleafSystems\\Utilities\\Data\\Adapter\\DynamicProperties' => __DIR__ . '/..' . '/fernleafsystems/utilities/src/Data/Adapter/DynamicProperties.php',
298
  'FernleafSystems\\Utilities\\Data\\Adapter\\StdClassAdapter' => __DIR__ . '/..' . '/fernleafsystems/utilities/src/Data/Adapter/StdClassAdapter.php',
299
  'FernleafSystems\\Utilities\\Data\\CaptureOutput' => __DIR__ . '/..' . '/fernleafsystems/utilities/src/Data/CaptureOutput.php',
300
+ 'FernleafSystems\\Utilities\\Data\\Response\\StdResponse' => __DIR__ . '/..' . '/fernleafsystems/utilities/src/Data/Response/StdResponse.php',
301
  'FernleafSystems\\Utilities\\Logic\\ExecOnce' => __DIR__ . '/..' . '/fernleafsystems/utilities/src/Logic/ExecOnce.php',
302
  'FernleafSystems\\Utilities\\Logic\\OneTimeExecute' => __DIR__ . '/..' . '/fernleafsystems/utilities/src/Logic/OneTimeExecute.php',
303
  'FernleafSystems\\Utilities\\Response' => __DIR__ . '/..' . '/fernleafsystems/utilities/src/Response.php',
333
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Ajax\\Response' => __DIR__ . '/../..' . '/src/Controller/Ajax/Response.php',
334
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Assets\\Enqueue' => __DIR__ . '/../..' . '/src/Controller/Assets/Enqueue.php',
335
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Assets\\Paths' => __DIR__ . '/../..' . '/src/Controller/Assets/Paths.php',
336
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Assets\\Svgs' => __DIR__ . '/../..' . '/src/Controller/Assets/Svgs.php',
337
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Assets\\Urls' => __DIR__ . '/../..' . '/src/Controller/Assets/Urls.php',
338
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Config\\ConfigVO' => __DIR__ . '/../..' . '/src/Controller/Config/ConfigVO.php',
339
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Config\\Ops\\LoadConfig' => __DIR__ . '/../..' . '/src/Controller/Config/Ops/LoadConfig.php',
477
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Autoupdates\\Processor' => __DIR__ . '/../..' . '/src/Modules/Autoupdates/Processor.php',
478
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Autoupdates\\Strings' => __DIR__ . '/../..' . '/src/Modules/Autoupdates/Strings.php',
479
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Autoupdates\\UI' => __DIR__ . '/../..' . '/src/Modules/Autoupdates/UI.php',
480
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\AdminPage' => __DIR__ . '/../..' . '/src/Modules/BaseShield/AdminPage.php',
481
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\AjaxHandler' => __DIR__ . '/../..' . '/src/Modules/BaseShield/AjaxHandler.php',
482
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\ModCon' => __DIR__ . '/../..' . '/src/Modules/BaseShield/ModCon.php',
483
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\Options' => __DIR__ . '/../..' . '/src/Modules/BaseShield/Options.php',
484
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\Processor' => __DIR__ . '/../..' . '/src/Modules/BaseShield/Processor.php',
485
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\UI' => __DIR__ . '/../..' . '/src/Modules/BaseShield/UI.php',
486
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\AdminNotices' => __DIR__ . '/../..' . '/src/Modules/Base/AdminNotices.php',
487
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\AdminPage' => __DIR__ . '/../..' . '/src/Modules/Base/AdminPage.php',
488
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\AjaxHandler' => __DIR__ . '/../..' . '/src/Modules/Base/AjaxHandler.php',
489
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Common\\ExecOnceModConsumer' => __DIR__ . '/../..' . '/src/Modules/Base/Common/ExecOnceModConsumer.php',
490
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Debug' => __DIR__ . '/../..' . '/src/Modules/Base/Debug.php',
491
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Insights\\OverviewCards' => __DIR__ . '/../..' . '/src/Modules/Base/Insights/OverviewCards.php',
492
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Request\\FormParams' => __DIR__ . '/../..' . '/src/Modules/Base/Lib/Request/FormParams.php',
493
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\RequestVoConsumer' => __DIR__ . '/../..' . '/src/Modules/Base/Lib/Rest/RequestVoConsumer.php',
494
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Request\\Process' => __DIR__ . '/../..' . '/src/Modules/Base/Lib/Rest/Request/Process.php',
495
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Request\\RequestVO' => __DIR__ . '/../..' . '/src/Modules/Base/Lib/Rest/Request/RequestVO.php',
496
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Route\\RestRouteConsumer' => __DIR__ . '/../..' . '/src/Modules/Base/Lib/Rest/Route/RestRouteConsumer.php',
497
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Route\\RouteBase' => __DIR__ . '/../..' . '/src/Modules/Base/Lib/Rest/Route/RouteBase.php',
498
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Route\\RouteCache' => __DIR__ . '/../..' . '/src/Modules/Base/Lib/Rest/Route/RouteCache.php',
499
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Utility\\PreChecks' => __DIR__ . '/../..' . '/src/Modules/Base/Lib/Rest/Utility/PreChecks.php',
500
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Lib\\Rest\\Utility\\RestLocker' => __DIR__ . '/../..' . '/src/Modules/Base/Lib/Rest/Utility/RestLocker.php',
501
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\ModCon' => __DIR__ . '/../..' . '/src/Modules/Base/ModCon.php',
502
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Options' => __DIR__ . '/../..' . '/src/Modules/Base/Options.php',
503
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Options\\OptValueSanitize' => __DIR__ . '/../..' . '/src/Modules/Base/Options/OptValueSanitize.php',
504
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Processor' => __DIR__ . '/../..' . '/src/Modules/Base/Processor.php',
505
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Reporting' => __DIR__ . '/../..' . '/src/Modules/Base/Reporting.php',
506
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\RestHandler' => __DIR__ . '/../..' . '/src/Modules/Base/RestHandler.php',
507
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Strings' => __DIR__ . '/../..' . '/src/Modules/Base/Strings.php',
508
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\UI' => __DIR__ . '/../..' . '/src/Modules/Base/UI.php',
509
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Upgrade' => __DIR__ . '/../..' . '/src/Modules/Base/Upgrade.php',
691
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\WpCli\\BaseAddRemove' => __DIR__ . '/../..' . '/src/Modules/IPs/WpCli/BaseAddRemove.php',
692
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\WpCli\\Enumerate' => __DIR__ . '/../..' . '/src/Modules/IPs/WpCli/Enumerate.php',
693
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\WpCli\\Remove' => __DIR__ . '/../..' . '/src/Modules/IPs/WpCli/Remove.php',
694
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\AdminPage' => __DIR__ . '/../..' . '/src/Modules/Insights/AdminPage.php',
695
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\AjaxHandler' => __DIR__ . '/../..' . '/src/Modules/Insights/AjaxHandler.php',
696
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Lib\\OverviewCards' => __DIR__ . '/../..' . '/src/Modules/Insights/Lib/OverviewCards.php',
697
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Lib\\Requests\\DynamicPageLoader' => __DIR__ . '/../..' . '/src/Modules/Insights/Lib/Requests/DynamicPageLoader.php',
698
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Lib\\SideMenuBuilder' => __DIR__ . '/../..' . '/src/Modules/Insights/Lib/SideMenuBuilder.php',
699
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Lib\\SummaryCards' => __DIR__ . '/../..' . '/src/Modules/Insights/Lib/SummaryCards.php',
700
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\ModCon' => __DIR__ . '/../..' . '/src/Modules/Insights/ModCon.php',
701
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Options' => __DIR__ . '/../..' . '/src/Modules/Insights/Options.php',
702
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\Strings' => __DIR__ . '/../..' . '/src/Modules/Insights/Strings.php',
703
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Insights\\UI' => __DIR__ . '/../..' . '/src/Modules/Insights/UI.php',
704
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Common\\BaseBotDetectionController' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/Common/BaseBotDetectionController.php',
705
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Common\\BaseHandler' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/Common/BaseHandler.php',
706
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\Handlers\\Base' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/Spam/Handlers/Base.php',
707
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\Handlers\\ContactForm7' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/Spam/Handlers/ContactForm7.php',
708
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\Handlers\\ElementorPro' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/Spam/Handlers/ElementorPro.php',
709
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\Handlers\\FluentForms' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/Spam/Handlers/FluentForms.php',
710
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\Handlers\\FormidableForms' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/Spam/Handlers/FormidableForms.php',
711
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\Handlers\\Forminator' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/Spam/Handlers/Forminator.php',
712
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\Handlers\\GravityForms' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/Spam/Handlers/GravityForms.php',
713
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\Handlers\\Groundhogg' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/Spam/Handlers/Groundhogg.php',
714
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\Handlers\\Helpers\\NinjaForms_ShieldSpamAction' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/Spam/Handlers/Helpers/NinjaForms_ShieldSpamAction.php',
715
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\Handlers\\KaliForms' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/Spam/Handlers/KaliForms.php',
716
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\Handlers\\NinjaForms' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/Spam/Handlers/NinjaForms.php',
717
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\Handlers\\WPForms' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/Spam/Handlers/WPForms.php',
718
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\Handlers\\WpForo' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/Spam/Handlers/WpForo.php',
719
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\Spam\\SpamController' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/Spam/SpamController.php',
720
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\UserForms\\Handlers\\Base' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/Base.php',
721
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\UserForms\\Handlers\\Buddypress' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/Buddypress.php',
722
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\UserForms\\Handlers\\EasyDigitalDownloads' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/EasyDigitalDownloads.php',
723
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\UserForms\\Handlers\\LearnPress' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/LearnPress.php',
724
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\UserForms\\Handlers\\LifterLMS' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/LifterLMS.php',
725
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\UserForms\\Handlers\\MemberPress' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/MemberPress.php',
726
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\UserForms\\Handlers\\PaidMemberSubscriptions' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/PaidMemberSubscriptions.php',
727
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\UserForms\\Handlers\\ProfileBuilder' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/ProfileBuilder.php',
728
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\UserForms\\Handlers\\UltimateMember' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/UltimateMember.php',
729
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\UserForms\\Handlers\\WPMembers' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/WPMembers.php',
730
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\UserForms\\Handlers\\WooCommerce' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/WooCommerce.php',
731
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\UserForms\\Handlers\\WordPress' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/UserForms/Handlers/WordPress.php',
732
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Bots\\UserForms\\UserFormsController' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Bots/UserForms/UserFormsController.php',
733
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\MainWP\\Client\\Actions\\ApiActionInit' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/MainWP/Client/Actions/ApiActionInit.php',
734
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\MainWP\\Client\\Actions\\Init' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/MainWP/Client/Actions/Init.php',
735
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\MainWP\\Client\\Actions\\Sync' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/MainWP/Client/Actions/Sync.php',
774
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Options' => __DIR__ . '/../..' . '/src/Modules/Integrations/Options.php',
775
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Processor' => __DIR__ . '/../..' . '/src/Modules/Integrations/Processor.php',
776
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Strings' => __DIR__ . '/../..' . '/src/Modules/Integrations/Strings.php',
777
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\UI' => __DIR__ . '/../..' . '/src/Modules/Integrations/UI.php',
778
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Upgrade' => __DIR__ . '/../..' . '/src/Modules/Integrations/Upgrade.php',
779
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\AdminNotices' => __DIR__ . '/../..' . '/src/Modules/License/AdminNotices.php',
780
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\AjaxHandler' => __DIR__ . '/../..' . '/src/Modules/License/AjaxHandler.php',
781
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\License\\Lib\\LicenseEmails' => __DIR__ . '/../..' . '/src/Modules/License/Lib/LicenseEmails.php',
826
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\LoginIntentPage' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/LoginIntentPage.php',
827
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\MfaController' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/MfaController.php',
828
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\MfaControllerConsumer' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/MfaControllerConsumer.php',
829
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\MfaProfilesController' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/MfaProfilesController.php',
830
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\MfaSkip' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/MfaSkip.php',
831
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Profiles\\RenderCustomForms' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Profiles/RenderCustomForms.php',
832
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\BackupCodes' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/BackupCodes.php',
833
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\BaseProvider' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/BaseProvider.php',
 
834
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\Email' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Email.php',
835
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\GoogleAuth' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/GoogleAuth.php',
836
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\TwoFactor\\Provider\\ProviderInterface' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/TwoFactor/Provider/ProviderInterface.php',
920
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\Restrictions\\WpOptions' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/Restrictions/WpOptions.php',
921
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\SecurityAdminController' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/SecurityAdminController.php',
922
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\SecurityAdmin\\VerifySecurityAdminList' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/SecurityAdmin/VerifySecurityAdminList.php',
 
923
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\WhiteLabel\\BuildOptions' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/WhiteLabel/BuildOptions.php',
924
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Lib\\WhiteLabel\\WhitelabelController' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Lib/WhiteLabel/WhitelabelController.php',
925
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\ModCon' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/ModCon.php',
926
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Options' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Options.php',
927
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\Processor' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/Processor.php',
931
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\WpCli\\AdminAdd' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/WpCli/AdminAdd.php',
932
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\WpCli\\AdminRemove' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/WpCli/AdminRemove.php',
933
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\SecurityAdmin\\WpCli\\Pin' => __DIR__ . '/../..' . '/src/Modules/SecurityAdmin/WpCli/Pin.php',
934
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Sessions\\Lib\\Ops\\Retrieve' => __DIR__ . '/../..' . '/src/Modules/Sessions/Lib/Ops/Retrieve.php',
935
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Sessions\\Lib\\Ops\\Terminate' => __DIR__ . '/../..' . '/src/Modules/Sessions/Lib/Ops/Terminate.php',
936
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Sessions\\Lib\\SessionController' => __DIR__ . '/../..' . '/src/Modules/Sessions/Lib/SessionController.php',
937
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Sessions\\ModCon' => __DIR__ . '/../..' . '/src/Modules/Sessions/ModCon.php',
1091
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Build\\ScanWpv' => __DIR__ . '/../..' . '/src/Tables/Build/ScanWpv.php',
1092
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Build\\Sessions' => __DIR__ . '/../..' . '/src/Tables/Build/Sessions.php',
1093
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Build\\Traffic' => __DIR__ . '/../..' . '/src/Tables/Build/Traffic.php',
1094
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\Common\\BaseTable' => __DIR__ . '/../..' . '/src/Tables/Render/Common/BaseTable.php',
1095
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\DataTable\\Base' => __DIR__ . '/../..' . '/src/Tables/Render/DataTable/Base.php',
1096
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\DataTable\\ScanBase' => __DIR__ . '/../..' . '/src/Tables/Render/DataTable/ScanBase.php',
1097
+ 'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\DataTable\\ScanWcf' => __DIR__ . '/../..' . '/src/Tables/Render/DataTable/ScanWcf.php',
1098
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\WpCliTable\\AuditTrail' => __DIR__ . '/../..' . '/src/Tables/Render/WpCliTable/AuditTrail.php',
1099
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\WpCliTable\\Base' => __DIR__ . '/../..' . '/src/Tables/Render/WpCliTable/Base.php',
1100
  'FernleafSystems\\Wordpress\\Plugin\\Shield\\Tables\\Render\\WpListTable\\AdminNotes' => __DIR__ . '/../..' . '/src/Tables/Render/WpListTable/AdminNotes.php',
1242
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Keyless\\Base' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Base.php',
1243
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Keyless\\Lookup' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Lookup.php',
1244
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Keyless\\Ping' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Keyless/Ping.php',
 
1245
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\BaseIP' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Net/BaseIP.php',
1246
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\FindSourceFromIp' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Net/FindSourceFromIp.php',
1247
  'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\IpID' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Net/IpID.php',
1298
  'LZCompressor\\LZString' => __DIR__ . '/..' . '/nullpunkt/lz-string-php/src/LZCompressor/LZString.php',
1299
  'LZCompressor\\LZUtil' => __DIR__ . '/..' . '/nullpunkt/lz-string-php/src/LZCompressor/LZUtil.php',
1300
  'LZCompressor\\LZUtil16' => __DIR__ . '/..' . '/nullpunkt/lz-string-php/src/LZCompressor/LZUtil16.php',
1301
+ 'MyCLabs\\Enum\\Enum' => __DIR__ . '/..' . '/myclabs/php-enum/src/Enum.php',
1302
  'Pimple\\Container' => __DIR__ . '/..' . '/pimple/pimple/src/Pimple/Container.php',
1303
  'Pimple\\Exception\\ExpectedInvokableException' => __DIR__ . '/..' . '/pimple/pimple/src/Pimple/Exception/ExpectedInvokableException.php',
1304
  'Pimple\\Exception\\FrozenServiceException' => __DIR__ . '/..' . '/pimple/pimple/src/Pimple/Exception/FrozenServiceException.php',
1324
  'Psr\\Container\\ContainerExceptionInterface' => __DIR__ . '/..' . '/psr/container/src/ContainerExceptionInterface.php',
1325
  'Psr\\Container\\ContainerInterface' => __DIR__ . '/..' . '/psr/container/src/ContainerInterface.php',
1326
  'Psr\\Container\\NotFoundExceptionInterface' => __DIR__ . '/..' . '/psr/container/src/NotFoundExceptionInterface.php',
1327
+ 'QrReader' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/QrReader.php',
1328
  'Ramsey\\Uuid\\BinaryUtils' => __DIR__ . '/..' . '/ramsey/uuid/src/BinaryUtils.php',
1329
  'Ramsey\\Uuid\\Builder\\DefaultUuidBuilder' => __DIR__ . '/..' . '/ramsey/uuid/src/Builder/DefaultUuidBuilder.php',
1330
  'Ramsey\\Uuid\\Builder\\DegradedUuidBuilder' => __DIR__ . '/..' . '/ramsey/uuid/src/Builder/DegradedUuidBuilder.php',
1380
  'ReCaptcha\\RequestMethod\\SocketPost' => __DIR__ . '/..' . '/google/recaptcha/src/ReCaptcha/RequestMethod/SocketPost.php',
1381
  'ReCaptcha\\RequestParameters' => __DIR__ . '/..' . '/google/recaptcha/src/ReCaptcha/RequestParameters.php',
1382
  'ReCaptcha\\Response' => __DIR__ . '/..' . '/google/recaptcha/src/ReCaptcha/Response.php',
1383
+ 'Symfony\\Component\\OptionsResolver\\Exception\\AccessException' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/AccessException.php',
1384
+ 'Symfony\\Component\\OptionsResolver\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/ExceptionInterface.php',
1385
+ 'Symfony\\Component\\OptionsResolver\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/InvalidArgumentException.php',
1386
+ 'Symfony\\Component\\OptionsResolver\\Exception\\InvalidOptionsException' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/InvalidOptionsException.php',
1387
+ 'Symfony\\Component\\OptionsResolver\\Exception\\MissingOptionsException' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/MissingOptionsException.php',
1388
+ 'Symfony\\Component\\OptionsResolver\\Exception\\NoSuchOptionException' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/NoSuchOptionException.php',
1389
+ 'Symfony\\Component\\OptionsResolver\\Exception\\OptionDefinitionException' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/OptionDefinitionException.php',
1390
+ 'Symfony\\Component\\OptionsResolver\\Exception\\UndefinedOptionsException' => __DIR__ . '/..' . '/symfony/options-resolver/Exception/UndefinedOptionsException.php',
1391
+ 'Symfony\\Component\\OptionsResolver\\Options' => __DIR__ . '/..' . '/symfony/options-resolver/Options.php',
1392
+ 'Symfony\\Component\\OptionsResolver\\OptionsResolver' => __DIR__ . '/..' . '/symfony/options-resolver/OptionsResolver.php',
1393
+ 'Symfony\\Component\\OptionsResolver\\OptionsResolverInterface' => __DIR__ . '/..' . '/symfony/options-resolver/OptionsResolverInterface.php',
1394
+ 'Symfony\\Component\\PropertyAccess\\Exception\\AccessException' => __DIR__ . '/..' . '/symfony/property-access/Exception/AccessException.php',
1395
+ 'Symfony\\Component\\PropertyAccess\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/property-access/Exception/ExceptionInterface.php',
1396
+ 'Symfony\\Component\\PropertyAccess\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/property-access/Exception/InvalidArgumentException.php',
1397
+ 'Symfony\\Component\\PropertyAccess\\Exception\\InvalidPropertyPathException' => __DIR__ . '/..' . '/symfony/property-access/Exception/InvalidPropertyPathException.php',
1398
+ 'Symfony\\Component\\PropertyAccess\\Exception\\NoSuchIndexException' => __DIR__ . '/..' . '/symfony/property-access/Exception/NoSuchIndexException.php',
1399
+ 'Symfony\\Component\\PropertyAccess\\Exception\\NoSuchPropertyException' => __DIR__ . '/..' . '/symfony/property-access/Exception/NoSuchPropertyException.php',
1400
+ 'Symfony\\Component\\PropertyAccess\\Exception\\OutOfBoundsException' => __DIR__ . '/..' . '/symfony/property-access/Exception/OutOfBoundsException.php',
1401
+ 'Symfony\\Component\\PropertyAccess\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/property-access/Exception/RuntimeException.php',
1402
+ 'Symfony\\Component\\PropertyAccess\\Exception\\UnexpectedTypeException' => __DIR__ . '/..' . '/symfony/property-access/Exception/UnexpectedTypeException.php',
1403
+ 'Symfony\\Component\\PropertyAccess\\PropertyAccess' => __DIR__ . '/..' . '/symfony/property-access/PropertyAccess.php',
1404
+ 'Symfony\\Component\\PropertyAccess\\PropertyAccessor' => __DIR__ . '/..' . '/symfony/property-access/PropertyAccessor.php',
1405
+ 'Symfony\\Component\\PropertyAccess\\PropertyAccessorBuilder' => __DIR__ . '/..' . '/symfony/property-access/PropertyAccessorBuilder.php',
1406
+ 'Symfony\\Component\\PropertyAccess\\PropertyAccessorInterface' => __DIR__ . '/..' . '/symfony/property-access/PropertyAccessorInterface.php',
1407
+ 'Symfony\\Component\\PropertyAccess\\PropertyPath' => __DIR__ . '/..' . '/symfony/property-access/PropertyPath.php',
1408
+ 'Symfony\\Component\\PropertyAccess\\PropertyPathBuilder' => __DIR__ . '/..' . '/symfony/property-access/PropertyPathBuilder.php',
1409
+ 'Symfony\\Component\\PropertyAccess\\PropertyPathInterface' => __DIR__ . '/..' . '/symfony/property-access/PropertyPathInterface.php',
1410
+ 'Symfony\\Component\\PropertyAccess\\PropertyPathIterator' => __DIR__ . '/..' . '/symfony/property-access/PropertyPathIterator.php',
1411
+ 'Symfony\\Component\\PropertyAccess\\PropertyPathIteratorInterface' => __DIR__ . '/..' . '/symfony/property-access/PropertyPathIteratorInterface.php',
1412
+ 'Symfony\\Component\\PropertyAccess\\StringUtil' => __DIR__ . '/..' . '/symfony/property-access/StringUtil.php',
1413
  'Symfony\\Component\\Translation\\Catalogue\\AbstractOperation' => __DIR__ . '/..' . '/symfony/translation/Catalogue/AbstractOperation.php',
1414
  'Symfony\\Component\\Translation\\Catalogue\\MergeOperation' => __DIR__ . '/..' . '/symfony/translation/Catalogue/MergeOperation.php',
1415
  'Symfony\\Component\\Translation\\Catalogue\\OperationInterface' => __DIR__ . '/..' . '/symfony/translation/Catalogue/OperationInterface.php',
1879
  'ZxcvbnPhp\\Scorer' => __DIR__ . '/..' . '/fernleafsystems/zxcvbn-php/src/Scorer.php',
1880
  'ZxcvbnPhp\\TimeEstimator' => __DIR__ . '/..' . '/fernleafsystems/zxcvbn-php/src/TimeEstimator.php',
1881
  'ZxcvbnPhp\\Zxcvbn' => __DIR__ . '/..' . '/fernleafsystems/zxcvbn-php/src/Zxcvbn.php',
1882
+ 'Zxing\\Binarizer' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/Binarizer.php',
1883
+ 'Zxing\\BinaryBitmap' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/BinaryBitmap.php',
1884
+ 'Zxing\\ChecksumException' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/ChecksumException.php',
1885
+ 'Zxing\\Common\\BitArray' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/BitArray.php',
1886
+ 'Zxing\\Common\\BitMatrix' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/BitMatrix.php',
1887
+ 'Zxing\\Common\\BitSource' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/BitSource.php',
1888
+ 'Zxing\\Common\\CharacterSetECI' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/CharacterSetEci.php',
1889
+ 'Zxing\\Common\\CharacterSetEci\\AbstractEnum\\AbstractEnum' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/AbstractEnum.php',
1890
+ 'Zxing\\Common\\DecoderResult' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/DecoderResult.php',
1891
+ 'Zxing\\Common\\DefaultGridSampler' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/DefaultGridSampler.php',
1892
+ 'Zxing\\Common\\DetectorResult' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/DetectorResult.php',
1893
+ 'Zxing\\Common\\Detector\\MathUtils' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/detector/MathUtils.php',
1894
+ 'Zxing\\Common\\Detector\\MonochromeRectangleDetector' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/detector/MonochromeRectangleDetector.php',
1895
+ 'Zxing\\Common\\GlobalHistogramBinarizer' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/GlobalHistogramBinarizer.php',
1896
+ 'Zxing\\Common\\GridSampler' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/GridSampler.php',
1897
+ 'Zxing\\Common\\HybridBinarizer' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/HybridBinarizer.php',
1898
+ 'Zxing\\Common\\PerspectiveTransform' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/PerspectiveTransform.php',
1899
+ 'Zxing\\Common\\Reedsolomon\\GenericGF' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/GenericGF.php',
1900
+ 'Zxing\\Common\\Reedsolomon\\GenericGFPoly' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/GenericGFPoly.php',
1901
+ 'Zxing\\Common\\Reedsolomon\\ReedSolomonDecoder' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/ReedSolomonDecoder.php',
1902
+ 'Zxing\\Common\\Reedsolomon\\ReedSolomonException' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/common/reedsolomon/ReedSolomonException.php',
1903
+ 'Zxing\\FormatException' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/FormatException.php',
1904
+ 'Zxing\\GDLuminanceSource' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/GDLuminanceSource.php',
1905
+ 'Zxing\\IMagickLuminanceSource' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/IMagickLuminanceSource.php',
1906
+ 'Zxing\\LuminanceSource' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/LuminanceSource.php',
1907
+ 'Zxing\\NotFoundException' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/NotFoundException.php',
1908
+ 'Zxing\\PlanarYUVLuminanceSource' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/PlanarYUVLuminanceSource.php',
1909
+ 'Zxing\\Qrcode\\Decoder\\BitMatrixParser' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/BitMatrixParser.php',
1910
+ 'Zxing\\Qrcode\\Decoder\\DataBlock' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataBlock.php',
1911
+ 'Zxing\\Qrcode\\Decoder\\DataMask' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
1912
+ 'Zxing\\Qrcode\\Decoder\\DataMask000' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
1913
+ 'Zxing\\Qrcode\\Decoder\\DataMask001' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
1914
+ 'Zxing\\Qrcode\\Decoder\\DataMask010' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
1915
+ 'Zxing\\Qrcode\\Decoder\\DataMask011' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
1916
+ 'Zxing\\Qrcode\\Decoder\\DataMask100' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
1917
+ 'Zxing\\Qrcode\\Decoder\\DataMask101' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
1918
+ 'Zxing\\Qrcode\\Decoder\\DataMask110' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
1919
+ 'Zxing\\Qrcode\\Decoder\\DataMask111' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DataMask.php',
1920
+ 'Zxing\\Qrcode\\Decoder\\DecodedBitStreamParser' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/DecodedBitStreamParser.php',
1921
+ 'Zxing\\Qrcode\\Decoder\\Decoder' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Decoder.php',
1922
+ 'Zxing\\Qrcode\\Decoder\\ECB' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Version.php',
1923
+ 'Zxing\\Qrcode\\Decoder\\ECBlocks' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Version.php',
1924
+ 'Zxing\\Qrcode\\Decoder\\ErrorCorrectionLevel' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/ErrorCorrectionLevel.php',
1925
+ 'Zxing\\Qrcode\\Decoder\\FormatInformation' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/FormatInformation.php',
1926
+ 'Zxing\\Qrcode\\Decoder\\Mode' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Mode.php',
1927
+ 'Zxing\\Qrcode\\Decoder\\Version' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/decoder/Version.php',
1928
+ 'Zxing\\Qrcode\\Detector\\AlignmentPattern' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/AlignmentPattern.php',
1929
+ 'Zxing\\Qrcode\\Detector\\AlignmentPatternFinder' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/AlignmentPatternFinder.php',
1930
+ 'Zxing\\Qrcode\\Detector\\Detector' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/Detector.php',
1931
+ 'Zxing\\Qrcode\\Detector\\FinderPattern' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/FinderPattern.php',
1932
+ 'Zxing\\Qrcode\\Detector\\FinderPatternFinder' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/FinderPatternFinder.php',
1933
+ 'Zxing\\Qrcode\\Detector\\FinderPatternInfo' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/detector/FinderPatternInfo.php',
1934
+ 'Zxing\\Qrcode\\QRCodeReader' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/qrcode/QRCodeReader.php',
1935
+ 'Zxing\\RGBLuminanceSource' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/RGBLuminanceSource.php',
1936
+ 'Zxing\\Reader' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/Reader.php',
1937
+ 'Zxing\\ReaderException' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/ReaderException.php',
1938
+ 'Zxing\\Result' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/Result.php',
1939
+ 'Zxing\\ResultPoint' => __DIR__ . '/..' . '/khanamiryan/qrcode-detector-decoder/lib/ResultPoint.php',
1940
  'u2flib_server\\Error' => __DIR__ . '/../..' . '/custom/U2F/Yubico/U2F.php',
1941
  'u2flib_server\\RegisterRequest' => __DIR__ . '/../..' . '/custom/U2F/Yubico/U2F.php',
1942
  'u2flib_server\\Registration' => __DIR__ . '/../..' . '/custom/U2F/Yubico/U2F.php',
src/lib/vendor/dolondro/google-authenticator/src/GoogleAuthenticator.php CHANGED
@@ -140,11 +140,12 @@ class GoogleAuthenticator
140
  /**
141
  * @param $string1
142
  * @param $string2
 
143
  * @return bool
144
  */
145
  protected function isEqual($string1, $string2)
146
  {
147
- return substr_count($string1 ^ $string2, "\0") * 2 === strlen($string1 . $string2);
148
  }
149
 
150
  /**
140
  /**
141
  * @param $string1
142
  * @param $string2
143
+ *
144
  * @return bool
145
  */
146
  protected function isEqual($string1, $string2)
147
  {
148
+ return substr_count($string1 ^ $string2, "\0") * 2 === strlen($string1.$string2);
149
  }
150
 
151
  /**
src/lib/vendor/dolondro/google-authenticator/src/QrImageGenerator/EndroidQrImageGenerator.php CHANGED
@@ -8,14 +8,16 @@ use Endroid\QrCode\QrCode;
8
  class EndroidQrImageGenerator implements QrImageGeneratorInterface
9
  {
10
  protected $size;
 
11
 
12
- public function __construct($size = 200)
13
  {
14
  if (!is_numeric($size)) {
15
  throw new \InvalidArgumentException("Size is required to be numeric");
16
  }
17
 
18
  $this->size = $size;
 
19
  }
20
 
21
  public function generateUri(Secret $secret)
@@ -23,7 +25,7 @@ class EndroidQrImageGenerator implements QrImageGeneratorInterface
23
  $qrCode = new QrCode($secret->getUri());
24
  $qrCode->setSize($this->size);
25
 
26
- $qrCode->setWriterByName('png');
27
 
28
  return $qrCode->writeDataUri();
29
  }
8
  class EndroidQrImageGenerator implements QrImageGeneratorInterface
9
  {
10
  protected $size;
11
+ protected $writer;
12
 
13
+ public function __construct($size = 200, $writer = 'png')
14
  {
15
  if (!is_numeric($size)) {
16
  throw new \InvalidArgumentException("Size is required to be numeric");
17
  }
18
 
19
  $this->size = $size;
20
+ $this->writer = $writer;
21
  }
22
 
23
  public function generateUri(Secret $secret)
25
  $qrCode = new QrCode($secret->getUri());
26
  $qrCode->setSize($this->size);
27
 
28
+ $qrCode->setWriterByName($this->writer);
29
 
30
  return $qrCode->writeDataUri();
31
  }
src/lib/vendor/endroid/qr-code/src/Bundle/QrCodeBundle/Controller/QrCodeController.php ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * (c) Jeroen van den Enden <info@endroid.nl>
5
+ *
6
+ * This source file is subject to the MIT license that is bundled
7
+ * with this source code in the file LICENSE.
8
+ */
9
+
10
+ namespace Endroid\QrCode\Bundle\QrCodeBundle\Controller;
11
+
12
+ use Endroid\QrCode\Factory\QrCodeFactory;
13
+ use Symfony\Bundle\FrameworkBundle\Controller\Controller;
14
+ use Symfony\Component\HttpFoundation\Response;
15
+ use Symfony\Component\HttpFoundation\Request;
16
+
17
+ /**
18
+ * QR code controller.
19
+ */
20
+ class QrCodeController extends Controller
21
+ {
22
+ /**
23
+ * @param Request $request
24
+ * @param string $text
25
+ * @param string $extension
26
+ *
27
+ * @return Response
28
+ */
29
+ public function generateAction(Request $request, $text, $extension)
30
+ {
31
+ $options = $request->query->all();
32
+
33
+ $qrCode = $this->getQrCodeFactory()->create($text, $options);
34
+ $qrCode->setWriterByExtension($extension);
35
+
36
+ return new Response($qrCode->writeString(), Response::HTTP_OK, ['Content-Type' => $qrCode->getContentType()]);
37
+ }
38
+
39
+ /**
40
+ * @return Response
41
+ */
42
+ public function twigFunctionsAction()
43
+ {
44
+ if (!$this->has('twig')) {
45
+ throw new \LogicException('You can not use the "@Template" annotation if the Twig Bundle is not available.');
46
+ }
47
+
48
+ $param = [
49
+ 'message' => 'QR Code',
50
+ ];
51
+
52
+ $renderedView = $this->get('twig')->render('@EndroidQrCode/QrCode/twigFunctions.html.twig', $param);
53
+
54
+ return new Response($renderedView, Response::HTTP_OK);
55
+ }
56
+
57
+ /**
58
+ * @return QrCodeFactory
59
+ */
60
+ protected function getQrCodeFactory()
61
+ {
62
+ return $this->get('endroid.qrcode.factory');
63
+ }
64
+ }
src/lib/vendor/endroid/qr-code/src/Bundle/QrCodeBundle/DependencyInjection/Compiler/WriterRegistryCompilerPass.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * (c) Jeroen van den Enden <info@endroid.nl>
5
+ *
6
+ * This source file is subject to the MIT license that is bundled
7
+ * with this source code in the file LICENSE.
8
+ */
9
+
10
+ namespace Endroid\QrCode\Bundle\QrCodeBundle\DependencyInjection\Compiler;
11
+
12
+ use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
13
+ use Symfony\Component\DependencyInjection\ContainerBuilder;
14
+ use Symfony\Component\DependencyInjection\Reference;
15
+
16
+ class WriterRegistryCompilerPass implements CompilerPassInterface
17
+ {
18
+ /**
19
+ * {@inheritdoc}
20
+ */
21
+ public function process(ContainerBuilder $container)
22
+ {
23
+ if (!$container->has('endroid.qrcode.writer_registry')) {
24
+ return;
25
+ }
26
+
27
+ $writerRegistryDefinition = $container->findDefinition('endroid.qrcode.writer_registry');
28
+
29
+ $taggedServices = $container->findTaggedServiceIds('endroid.qrcode.writer');
30
+ foreach ($taggedServices as $id => $tags) {
31
+ foreach ($tags as $attributes) {
32
+ $writerRegistryDefinition->addMethodCall('addWriter', [new Reference($id), isset($attributes['set_as_default']) && $attributes['set_as_default']]);
33
+ }
34
+ }
35
+ }
36
+ }
src/lib/vendor/endroid/qr-code/src/Bundle/QrCodeBundle/DependencyInjection/Configuration.php ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * (c) Jeroen van den Enden <info@endroid.nl>
5
+ *
6
+ * This source file is subject to the MIT license that is bundled
7
+ * with this source code in the file LICENSE.
8
+ */
9
+
10
+ namespace Endroid\QrCode\Bundle\QrCodeBundle\DependencyInjection;
11
+
12
+ use Endroid\QrCode\ErrorCorrectionLevel;
13
+ use Endroid\QrCode\LabelAlignment;
14
+ use Predis\Response\Error;
15
+ use Symfony\Component\Config\Definition\Builder\TreeBuilder;
16
+ use Symfony\Component\Config\Definition\ConfigurationInterface;
17
+
18
+ class Configuration implements ConfigurationInterface
19
+ {
20
+ public function getConfigTreeBuilder()
21
+ {
22
+ $treeBuilder = new TreeBuilder();
23
+
24
+ $treeBuilder
25
+ ->root('endroid_qr_code')
26
+ ->children()
27
+ ->scalarNode('writer')->end()
28
+ ->integerNode('size')->min(0)->end()
29
+ ->integerNode('margin')->min(0)->end()
30
+ ->scalarNode('encoding')->defaultValue('UTF-8')->end()
31
+ ->scalarNode('error_correction_level')
32
+ ->validate()
33
+ ->ifNotInArray(ErrorCorrectionLevel::toArray())
34
+ ->thenInvalid('Invalid error correction level %s')
35
+ ->end()
36
+ ->end()
37
+ ->arrayNode('foreground_color')
38
+ ->children()
39
+ ->scalarNode('r')->isRequired()->end()
40
+ ->scalarNode('g')->isRequired()->end()
41
+ ->scalarNode('b')->isRequired()->end()
42
+ ->end()
43
+ ->end()
44
+ ->arrayNode('background_color')
45
+ ->children()
46
+ ->scalarNode('r')->isRequired()->end()
47
+ ->scalarNode('g')->isRequired()->end()
48
+ ->scalarNode('b')->isRequired()->end()
49
+ ->end()
50
+ ->end()
51
+ ->scalarNode('logo_path')->end()
52
+ ->integerNode('logo_width')->end()
53
+ ->scalarNode('label')->end()
54
+ ->integerNode('label_font_size')->end()
55
+ ->scalarNode('label_font_path')->end()
56
+ ->scalarNode('label_alignment')
57
+ ->validate()
58
+ ->ifNotInArray(LabelAlignment::toArray())
59
+ ->thenInvalid('Invalid label alignment %s')
60
+ ->end()
61
+ ->end()
62
+ ->arrayNode('label_margin')
63
+ ->children()
64
+ ->scalarNode('t')->end()
65
+ ->scalarNode('r')->end()
66
+ ->scalarNode('b')->end()
67
+ ->scalarNode('l')->end()
68
+ ->end()
69
+ ->end()
70
+ ->booleanNode('validate_result')->end()
71
+ ->end()
72
+ ->end()
73
+ ;
74
+
75
+ return $treeBuilder;
76
+ }
77
+ }
src/lib/vendor/endroid/qr-code/src/Bundle/QrCodeBundle/DependencyInjection/EndroidQrCodeExtension.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * (c) Jeroen van den Enden <info@endroid.nl>
5
+ *
6
+ * This source file is subject to the MIT license that is bundled
7
+ * with this source code in the file LICENSE.
8
+ */
9
+
10
+ namespace Endroid\QrCode\Bundle\QrCodeBundle\DependencyInjection;
11
+
12
+ use Symfony\Component\Config\Definition\Processor;
13
+ use Symfony\Component\HttpKernel\DependencyInjection\Extension;
14
+ use Symfony\Component\DependencyInjection\ContainerBuilder;
15
+ use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
16
+ use Symfony\Component\Config\FileLocator;
17
+
18
+ class EndroidQrCodeExtension extends Extension
19
+ {
20
+ /**
21
+ * {@inheritdoc}
22
+ */
23
+ public function load(array $configs, ContainerBuilder $container)
24
+ {
25
+ $processor = new Processor();
26
+ $config = $processor->processConfiguration(new Configuration(), $configs);
27
+
28
+ $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
29
+ $loader->load('services.yml');
30
+
31
+ $factoryDefinition = $container->getDefinition('endroid.qrcode.factory');
32
+ $factoryDefinition->replaceArgument(0, $config);
33
+ }
34
+ }
src/lib/vendor/endroid/qr-code/src/Bundle/QrCodeBundle/EndroidQrCodeBundle.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * (c) Jeroen van den Enden <info@endroid.nl>
5
+ *
6
+ * This source file is subject to the MIT license that is bundled
7
+ * with this source code in the file LICENSE.
8
+ */
9
+
10
+ namespace Endroid\QrCode\Bundle\QrCodeBundle;
11
+
12
+ use Endroid\QrCode\Bundle\QrCodeBundle\DependencyInjection\Compiler\WriterRegistryCompilerPass;
13
+ use Symfony\Component\DependencyInjection\ContainerBuilder;
14
+ use Symfony\Component\HttpKernel\Bundle\Bundle;
15
+
16
+ class EndroidQrCodeBundle extends Bundle
17
+ {
18
+ /**
19
+ * {@inheritdoc}
20
+ */
21
+ public function build(ContainerBuilder $container)
22
+ {
23
+ parent::build($container);
24
+
25
+ $container->addCompilerPass(new WriterRegistryCompilerPass());
26
+ }
27
+ }
src/lib/vendor/endroid/qr-code/src/Bundle/QrCodeBundle/Resources/config/routing.yml ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ endroid_qrcode_generate:
2
+ path: /{text}.{extension}
3
+ requirements:
4
+ text: "[\\w\\W]+"
5
+ defaults:
6
+ _controller: EndroidQrCodeBundle:QrCode:generate
7
+
8
+ endroid_qrcode_twig_functions:
9
+ path: /twig
10
+ defaults:
11
+ _controller: EndroidQrCodeBundle:QrCode:twigFunctions
src/lib/vendor/endroid/qr-code/src/Bundle/QrCodeBundle/Resources/config/services.yml ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ services:
2
+ endroid.qrcode.factory:
3
+ class: Endroid\QrCode\Factory\QrCodeFactory
4
+ arguments: [ null, '@endroid.qrcode.writer_registry' ]
5
+ endroid.qrcode.twig.extension:
6
+ class: Endroid\QrCode\Twig\Extension\QrCodeExtension
7
+ arguments: [ '@endroid.qrcode.factory', '@router']
8
+ tags:
9
+ - { name: twig.extension }
10
+ endroid.qrcode.writer_registry:
11
+ class: Endroid\QrCode\WriterRegistry
12
+ endroid.qrcode.writer.binary_writer:
13
+ class: Endroid\QrCode\Writer\BinaryWriter
14
+ tags:
15
+ - { name: endroid.qrcode.writer }
16
+ endroid.qrcode.writer.debug_writer:
17
+ class: Endroid\QrCode\Writer\DebugWriter
18
+ tags:
19
+ - { name: endroid.qrcode.writer }
20
+ endroid.qrcode.writer.eps_writer:
21
+ class: Endroid\QrCode\Writer\EpsWriter
22
+ tags:
23
+ - { name: endroid.qrcode.writer }
24
+ endroid.qrcode.writer.png_writer:
25
+ class: Endroid\QrCode\Writer\PngWriter
26
+ tags:
27
+ - { name: endroid.qrcode.writer, set_as_default: true }
28
+ endroid.qrcode.writer.svg_writer:
29
+ class: Endroid\QrCode\Writer\SvgWriter
30
+ tags:
31
+ - { name: endroid.qrcode.writer }
src/lib/vendor/endroid/qr-code/src/Bundle/QrCodeBundle/Resources/views/QrCode/twigFunctions.html.twig ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ <img src="{{ qrcode_path(message) }}" />
2
+ <img src="{{ qrcode_url(message, { writer: 'svg' }) }}" />
3
+ <img src="{{ qrcode_data_uri(message, { writer: 'svg', size: 150 }) }}" />
src/lib/vendor/endroid/qr-code/src/ErrorCorrectionLevel.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * (c) Jeroen van den Enden <info@endroid.nl>
5
+ *
6
+ * This source file is subject to the MIT license that is bundled
7
+ * with this source code in the file LICENSE.
8
+ */
9
+
10
+ namespace Endroid\QrCode;
11
+
12
+ use MyCLabs\Enum\Enum;
13
+
14
+ class ErrorCorrectionLevel extends Enum
15
+ {
16
+ const LOW = 'low';
17
+ const MEDIUM = 'medium';
18
+ const QUARTILE = 'quartile';
19
+ const HIGH = 'high';
20
+ }
src/lib/vendor/endroid/qr-code/src/Exception/InvalidPathException.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * (c) Jeroen van den Enden <info@endroid.nl>
5
+ *
6
+ * This source file is subject to the MIT license that is bundled
7
+ * with this source code in the file LICENSE.
8
+ */
9
+
10
+ namespace Endroid\QrCode\Exception;
11
+
12
+ class InvalidPathException extends QrCodeException
13
+ {
14
+ }
src/lib/vendor/endroid/qr-code/src/Exception/InvalidWriterException.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * (c) Jeroen van den Enden <info@endroid.nl>
5
+ *
6
+ * This source file is subject to the MIT license that is bundled
7
+ * with this source code in the file LICENSE.
8
+ */
9
+
10
+ namespace Endroid\QrCode\Exception;
11
+
12
+ class InvalidWriterException extends QrCodeException
13
+ {
14
+ }
src/lib/vendor/endroid/qr-code/src/Exception/MissingFunctionException.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * (c) Jeroen van den Enden <info@endroid.nl>
5
+ *
6
+ * This source file is subject to the MIT license that is bundled
7
+ * with this source code in the file LICENSE.
8
+ */
9
+
10
+ namespace Endroid\QrCode\Exception;
11
+
12
+ class MissingFunctionException extends QrCodeException
13
+ {
14
+ }
src/lib/vendor/endroid/qr-code/src/Exception/QrCodeException.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * (c) Jeroen van den Enden <info@endroid.nl>
5
+ *
6
+ * This source file is subject to the MIT license that is bundled
7
+ * with this source code in the file LICENSE.
8
+ */
9
+
10
+ namespace Endroid\QrCode\Exception;
11
+
12
+ use Exception;
13
+
14
+ abstract class QrCodeException extends Exception
15
+ {
16
+ }
src/lib/vendor/endroid/qr-code/src/Exception/UnsupportedExtensionException.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * (c) Jeroen van den Enden <info@endroid.nl>
5
+ *
6
+ * This source file is subject to the MIT license that is bundled
7
+ * with this source code in the file LICENSE.
8
+ */
9
+
10
+ namespace Endroid\QrCode\Exception;
11
+
12
+ class UnsupportedExtensionException extends QrCodeException
13
+ {
14
+ }
src/lib/vendor/endroid/qr-code/src/Exception/ValidationException.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * (c) Jeroen van den Enden <info@endroid.nl>
5
+ *
6
+ * This source file is subject to the MIT license that is bundled
7
+ * with this source code in the file LICENSE.
8
+ */
9
+
10
+ namespace Endroid\QrCode\Exception;
11
+
12
+ class ValidationException extends QrCodeException
13
+ {
14
+ }
src/lib/vendor/endroid/qr-code/src/Factory/QrCodeFactory.php ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * (c) Jeroen van den Enden <info@endroid.nl>
5
+ *
6
+ * This source file is subject to the MIT license that is bundled
7
+ * with this source code in the file LICENSE.
8
+ */
9
+
10
+ namespace Endroid\QrCode\Factory;
11
+
12
+ use Endroid\QrCode\QrCode;
13
+ use Endroid\QrCode\WriterRegistryInterface;
14
+ use Symfony\Component\OptionsResolver\OptionsResolver;
15
+ use Symfony\Component\PropertyAccess\PropertyAccess;
16
+
17
+ class QrCodeFactory
18
+ {
19
+ /**
20
+ * @var array
21
+ */
22
+ protected $definedOptions = [
23
+ 'writer',
24
+ 'size',
25
+ 'margin',
26
+ 'foreground_color',
27
+ 'background_color',
28
+ 'encoding',
29
+ 'error_correction_level',
30
+ 'logo_path',
31
+ 'logo_width',
32
+ 'label',
33
+ 'label_font_size',
34
+ 'label_font_path',
35
+ 'label_alignment',
36
+ 'label_margin',
37
+ 'validate_result',
38
+ ];
39
+
40
+ /**
41
+ * @var array
42
+ */
43
+ protected $defaultOptions;
44
+
45
+ /**
46
+ * @var WriterRegistryInterface
47
+ */
48
+ protected $writerRegistry;
49
+
50
+ /**
51
+ * @var OptionsResolver
52
+ */
53
+ protected $optionsResolver;
54
+
55
+ /**
56
+ * @param array $defaultOptions
57
+ * @param WriterRegistryInterface $writerRegistry
58
+ */
59
+ public function __construct(array $defaultOptions = [], WriterRegistryInterface $writerRegistry = null)
60
+ {
61
+ $this->defaultOptions = $defaultOptions;
62
+ $this->writerRegistry = $writerRegistry;
63
+ }
64
+
65
+ /**
66
+ * @param string $text
67
+ * @param array $options
68
+ *
69
+ * @return QrCode
70
+ */
71
+ public function create($text = '', array $options = [])
72
+ {
73
+ $options = $this->getOptionsResolver()->resolve($options);
74
+ $accessor = PropertyAccess::createPropertyAccessor();
75
+
76
+ $qrCode = new QrCode($text);
77
+
78
+ if ($this->writerRegistry instanceof WriterRegistryInterface) {
79
+ $qrCode->setWriterRegistry($this->writerRegistry);
80
+ }
81
+
82
+ foreach ($this->definedOptions as $option) {
83
+ if (isset($options[$option])) {
84
+ if ('writer' === $option) {
85
+ $options['writer_by_name'] = $options[$option];
86
+ $option = 'writer_by_name';
87
+ }
88
+ $accessor->setValue($qrCode, $option, $options[$option]);
89
+ }
90
+ }
91
+
92
+ return $qrCode;
93
+ }
94
+
95
+ /**
96
+ * @return OptionsResolver
97
+ */
98
+ protected function getOptionsResolver()
99
+ {
100
+ if (!$this->optionsResolver instanceof OptionsResolver) {
101
+ $this->optionsResolver = $this->createOptionsResolver();
102
+ }
103
+
104
+ return $this->optionsResolver;
105
+ }
106
+
107
+ /**
108
+ * @return OptionsResolver
109
+ */
110
+ protected function createOptionsResolver()
111
+ {
112
+ $optionsResolver = new OptionsResolver();
113
+ $optionsResolver
114
+ ->setDefaults($this->defaultOptions)
115
+ ->setDefined($this->definedOptions)
116
+ ;
117
+
118
+ return $optionsResolver;
119
+ }
120
+ }
src/lib/vendor/endroid/qr-code/src/LabelAlignment.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * (c) Jeroen van den Enden <info@endroid.nl>
5
+ *
6
+ * This source file is subject to the MIT license that is bundled
7
+ * with this source code in the file LICENSE.
8
+ */
9
+
10
+ namespace Endroid\QrCode;
11
+
12
+ use MyCLabs\Enum\Enum;
13
+
14
+ class LabelAlignment extends Enum
15
+ {
16
+ const LEFT = 'left';
17
+ const CENTER = 'center';
18
+ const RIGHT = 'right';
19
+ }
src/lib/vendor/endroid/qr-code/src/QrCode.php ADDED
@@ -0,0 +1,591 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * (c) Jeroen van den Enden <info@endroid.nl>
5
+ *
6
+ * This source file is subject to the MIT license that is bundled
7
+ * with this source code in the file LICENSE.
8
+ */
9
+
10
+ namespace Endroid\QrCode;
11
+
12
+ use Endroid\QrCode\Exception\InvalidPathException;
13
+ use Endroid\QrCode\Exception\InvalidWriterException;
14
+ use Endroid\QrCode\Exception\UnsupportedExtensionException;
15
+ use Endroid\QrCode\Writer\WriterInterface;
16
+
17
+ class QrCode implements QrCodeInterface
18
+ {
19
+ const LABEL_FONT_PATH_DEFAULT = __DIR__.'/../assets/noto_sans.otf';
20
+
21
+ /**
22
+ * @var string
23
+ */
24
+ protected $text;
25
+
26
+ /**
27
+ * @var int
28
+ */
29
+ protected $size = 300;
30
+
31
+ /**
32
+ * @var int
33
+ */
34
+ protected $margin = 10;
35
+
36
+ /**
37
+ * @var array
38
+ */
39
+ protected $foregroundColor = [
40
+ 'r' => 0,
41
+ 'g' => 0,
42
+ 'b' => 0,
43
+ ];
44
+
45
+ /**
46
+ * @var array
47
+ */
48
+ protected $backgroundColor = [
49
+ 'r' => 255,
50
+ 'g' => 255,
51
+ 'b' => 255,
52
+ ];
53
+
54
+ /**
55
+ * @var string
56
+ */
57
+ protected $encoding = 'UTF-8';
58
+
59
+ /**
60
+ * @var ErrorCorrectionLevel
61
+ */
62
+ protected $errorCorrectionLevel;
63
+
64
+ /**
65
+ * @var string
66
+ */
67
+ protected $logoPath;
68
+
69
+ /**
70
+ * @var int
71
+ */
72
+ protected $logoWidth;
73
+
74
+ /**
75
+ * @var string
76
+ */
77
+ protected $label;
78
+
79
+ /**
80
+ * @var int
81
+ */
82
+ protected $labelFontSize = 16;
83
+
84
+ /**
85
+ * @var string
86
+ */
87
+ protected $labelFontPath = self::LABEL_FONT_PATH_DEFAULT;
88
+
89
+ /**
90
+ * @var LabelAlignment
91
+ */
92
+ protected $labelAlignment;
93
+
94
+ /**
95
+ * @var array
96
+ */
97
+ protected $labelMargin = [
98
+ 't' => 0,
99
+ 'r' => 10,
100
+ 'b' => 10,
101
+ 'l' => 10,
102
+ ];
103
+
104
+ /**
105
+ * @var WriterRegistryInterface
106
+ */
107
+ protected $writerRegistry;
108
+
109
+ /**
110
+ * @var WriterInterface
111
+ */
112
+ protected $writer;
113
+
114
+ /**
115
+ * @var bool
116
+ */
117
+ protected $validateResult = false;
118
+
119
+ /**
120
+ * @param string $text
121
+ */
122
+ public function __construct($text = '')
123
+ {
124
+ $this->text = $text;
125
+
126
+ $this->errorCorrectionLevel = new ErrorCorrectionLevel(ErrorCorrectionLevel::LOW);
127
+ $this->labelAlignment = new LabelAlignment(LabelAlignment::CENTER);
128
+
129
+ $this->writerRegistry = new StaticWriterRegistry();
130
+ }
131
+
132
+ /**
133
+ * @param string $text
134
+ *
135
+ * @return $this
136
+ */
137
+ public function setText($text)
138
+ {
139
+ $this->text = $text;
140
+
141
+ return $this;
142
+ }
143
+
144
+ /**
145
+ * {@inheritdoc}
146
+ */
147
+ public function getText()
148
+ {
149
+ return $this->text;
150
+ }
151
+
152
+ /**
153
+ * @param int $size
154
+ *
155
+ * @return $this
156
+ */
157
+ public function setSize($size)
158
+ {
159
+ $this->size = $size;
160
+
161
+ return $this;
162
+ }
163
+
164
+ /**
165
+ * {@inheritdoc}
166
+ */
167
+ public function getSize()
168
+ {
169
+ return $this->size;
170
+ }
171
+
172
+ /**
173
+ * @param int $margin
174
+ *
175
+ * @return $this
176
+ */
177
+ public function setMargin($margin)
178
+ {
179
+ $this->margin = $margin;
180
+
181
+ return $this;
182
+ }
183
+
184
+ /**
185
+ * {@inheritdoc}
186
+ */
187
+ public function getMargin()
188
+ {
189
+ return $this->margin;
190
+ }
191
+
192
+ /**
193
+ * @param array $foregroundColor
194
+ *
195
+ * @return $this
196
+ */
197
+ public function setForegroundColor($foregroundColor)
198
+ {
199
+ $this->foregroundColor = $foregroundColor;
200
+
201
+ return $this;
202
+ }
203
+
204
+ /**
205
+ * {@inheritdoc}
206
+ */
207
+ public function getForegroundColor()
208
+ {
209
+ return $this->foregroundColor;
210
+ }
211
+
212
+ /**
213
+ * @param array $backgroundColor
214
+ *
215
+ * @return $this
216
+ */
217
+ public function setBackgroundColor($backgroundColor)
218
+ {
219
+ $this->backgroundColor = $backgroundColor;
220
+
221
+ return $this;
222
+ }
223
+
224
+ /**
225
+ * {@inheritdoc}
226
+ */
227
+ public function getBackgroundColor()
228
+ {
229
+ return $this->backgroundColor;
230
+ }
231
+
232
+ /**
233
+ * @param string $encoding
234
+ *
235
+ * @return $this
236
+ */
237
+ public function setEncoding($encoding)
238
+ {
239
+ $this->encoding = $encoding;
240
+
241
+ return $this;
242
+ }
243
+
244
+ /**
245
+ * {@inheritdoc}
246
+ */
247
+ public function getEncoding()
248
+ {
249
+ return $this->encoding;
250
+ }
251
+
252
+ /**
253
+ * @param string $errorCorrectionLevel
254
+ *
255
+ * @return $this
256
+ */
257
+ public function setErrorCorrectionLevel($errorCorrectionLevel)
258
+ {
259
+ $this->errorCorrectionLevel = new ErrorCorrectionLevel($errorCorrectionLevel);
260
+
261
+ return $this;
262
+ }
263
+
264
+ /**
265
+ * {@inheritdoc}
266
+ */
267
+ public function getErrorCorrectionLevel()
268
+ {
269
+ return $this->errorCorrectionLevel->getValue();
270
+ }
271
+
272
+ /**
273
+ * @param string $logoPath
274
+ *
275
+ * @return $this
276
+ *
277
+ * @throws InvalidPathException
278
+ */
279
+ public function setLogoPath($logoPath)
280
+ {
281
+ $logoPath = realpath($logoPath);
282
+
283
+ if (!is_file($logoPath)) {
284
+ throw new InvalidPathException('Invalid logo path: '.$logoPath);
285
+ }
286
+
287
+ $this->logoPath = $logoPath;
288
+
289
+ return $this;
290
+ }
291
+
292
+ /**
293
+ * {@inheritdoc}
294
+ */
295
+ public function getLogoPath()
296
+ {
297
+ return $this->logoPath;
298
+ }
299
+
300
+ /**
301
+ * @param int $logoWidth
302
+ *
303
+ * @return $this
304
+ */
305
+ public function setLogoWidth($logoWidth)
306
+ {
307
+ $this->logoWidth = $logoWidth;
308
+
309
+ return $this;
310
+ }
311
+
312
+ /**
313
+ * {@inheritdoc}
314
+ */
315
+ public function getLogoWidth()
316
+ {
317
+ return $this->logoWidth;
318
+ }
319
+
320
+ /**
321
+ * @param string $label
322
+ * @param int $labelFontSize
323
+ * @param string $labelFontPath
324
+ * @param string $labelAlignment
325
+ * @param array $labelMargin
326
+ *
327
+ * @return $this
328
+ */
329
+ public function setLabel($label, $labelFontSize = null, $labelFontPath = null, $labelAlignment = null, $labelMargin = null)
330
+ {
331
+ $this->label = $label;
332
+
333
+ if (null !== $labelFontSize) {
334
+ $this->setLabelFontSize($labelFontSize);
335
+ }
336
+
337
+ if (null !== $labelFontPath) {
338
+ $this->setLabelFontPath($labelFontPath);
339
+ }
340
+
341
+ if (null !== $labelAlignment) {
342
+ $this->setLabelAlignment($labelAlignment);
343
+ }
344
+
345
+ if (null !== $labelMargin) {
346
+ $this->setLabelMargin($labelMargin);
347
+ }
348
+
349
+ return $this;
350
+ }
351
+
352
+ /**
353
+ * {@inheritdoc}
354
+ */
355
+ public function getLabel()
356
+ {
357
+ return $this->label;
358
+ }
359
+
360
+ /**
361
+ * @param int $labelFontSize
362
+ *
363
+ * @return $this
364
+ */
365
+ public function setLabelFontSize($labelFontSize)
366
+ {
367
+ $this->labelFontSize = $labelFontSize;
368
+
369
+ return $this;
370
+ }
371
+
372
+ /**
373
+ * {@inheritdoc}
374
+ */
375
+ public function getLabelFontSize()
376
+ {
377
+ return $this->labelFontSize;
378
+ }
379
+
380
+ /**
381
+ * @param string $labelFontPath
382
+ *
383
+ * @return $this
384
+ *
385
+ * @throws InvalidPathException
386
+ */
387
+ public function setLabelFontPath($labelFontPath)
388
+ {
389
+ $labelFontPath = realpath($labelFontPath);
390
+
391
+ if (!is_file($labelFontPath)) {
392
+ throw new InvalidPathException('Invalid label font path: '.$labelFontPath);
393
+ }
394
+
395
+ $this->labelFontPath = $labelFontPath;
396
+
397
+ return $this;
398
+ }
399
+
400
+ /**
401
+ * {@inheritdoc}
402
+ */
403
+ public function getLabelFontPath()
404
+ {
405
+ return $this->labelFontPath;
406
+ }
407
+
408
+ /**
409
+ * @param string $labelAlignment
410
+ *
411
+ * @return $this
412
+ */
413
+ public function setLabelAlignment($labelAlignment)
414
+ {
415
+ $this->labelAlignment = new LabelAlignment($labelAlignment);
416
+
417
+ return $this;
418
+ }
419
+
420
+ /**
421
+ * {@inheritdoc}
422
+ */
423
+ public function getLabelAlignment()
424
+ {
425
+ return $this->labelAlignment->getValue();
426
+ }
427
+
428
+ /**
429
+ * @param int[] $labelMargin
430
+ *
431
+ * @return $this
432
+ */
433
+ public function setLabelMargin(array $labelMargin)
434
+ {
435
+ $this->labelMargin = array_merge($this->labelMargin, $labelMargin);
436
+
437
+ return $this;
438
+ }
439
+
440
+ /**
441
+ * {@inheritdoc}
442
+ */
443
+ public function getLabelMargin()
444
+ {
445
+ return $this->labelMargin;
446
+ }
447
+
448
+ /**
449
+ * @param WriterRegistryInterface $writerRegistry
450
+ *
451
+ * @return $this
452
+ */
453
+ public function setWriterRegistry(WriterRegistryInterface $writerRegistry)
454
+ {
455
+ $this->writerRegistry = $writerRegistry;
456
+
457
+ return $this;
458
+ }
459
+
460
+ /**
461
+ * @param WriterInterface $writer
462
+ *
463
+ * @return $this
464
+ */
465
+ public function setWriter(WriterInterface $writer)
466
+ {
467
+ $this->writer = $writer;
468
+
469
+ return $this;
470
+ }
471
+
472
+ /**
473
+ * @param WriterInterface $name
474
+ *
475
+ * @return WriterInterface
476
+ */
477
+ public function getWriter($name = null)
478
+ {
479
+ if (!is_null($name)) {
480
+ return $this->writerRegistry->getWriter($name);
481
+ }
482
+
483
+ if ($this->writer instanceof WriterInterface) {
484
+ return $this->writer;
485
+ }
486
+
487
+ return $this->writerRegistry->getDefaultWriter();
488
+ }
489
+
490
+ /**
491
+ * @param string $name
492
+ *
493
+ * @return $this
494
+ *
495
+ * @throws InvalidWriterException
496
+ */
497
+ public function setWriterByName($name)
498
+ {
499
+ $this->writer = $this->writerRegistry->getWriter($name);
500
+
501
+ return $this;
502
+ }
503
+
504
+ /**
505
+ * @param string $path
506
+ *
507
+ * @return $this
508
+ */
509
+ public function setWriterByPath($path)
510
+ {
511
+ $extension = pathinfo($path, PATHINFO_EXTENSION);
512
+
513
+ $this->setWriterByExtension($extension);
514
+
515
+ return $this;
516
+ }
517
+
518
+ /**
519
+ * @param string $extension
520
+ *
521
+ * @return $this
522
+ *
523
+ * @throws UnsupportedExtensionException
524
+ */
525
+ public function setWriterByExtension($extension)
526
+ {
527
+ foreach ($this->writerRegistry->getWriters() as $writer) {
528
+ if ($writer->supportsExtension($extension)) {
529
+ $this->writer = $writer;
530
+
531
+ return $this;
532
+ }
533
+ }
534
+
535
+ throw new UnsupportedExtensionException('Missing writer for extension "'.$extension.'"');
536
+ }
537
+
538
+ /**
539
+ * @param bool $validateResult
540
+ *
541
+ * @return $this
542
+ */
543
+ public function setValidateResult($validateResult)
544
+ {
545
+ $this->validateResult = $validateResult;
546
+
547
+ return $this;
548
+ }
549
+
550
+ /**
551
+ * {@inheritdoc}
552
+ */
553
+ public function getValidateResult()
554
+ {
555
+ return $this->validateResult;
556
+ }
557
+
558
+ /**
559
+ * @return string
560
+ */
561
+ public function writeString()
562
+ {
563
+ return $this->getWriter()->writeString($this);
564
+ }
565
+
566
+ /**
567
+ * @return string
568
+ */
569
+ public function writeDataUri()
570
+ {
571
+ return $this->getWriter()->writeDataUri($this);
572
+ }
573
+
574
+ /**
575
+ * @param string $path
576
+ */
577
+ public function writeFile($path)
578
+ {
579
+ return $this->getWriter()->writeFile($this, $path);
580
+ }
581
+
582
+ /**
583
+ * @return string
584
+ *
585
+ * @throws InvalidWriterException
586
+ */
587
+ public function getContentType()
588
+ {
589
+ return $this->getWriter()->getContentType();
590
+ }
591
+ }
src/lib/vendor/endroid/qr-code/src/QrCodeInterface.php ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * (c) Jeroen van den Enden <info@endroid.nl>
5
+ *
6
+ * This source file is subject to the MIT license that is bundled
7
+ * with this source code in the file LICENSE.
8
+ */
9
+
10
+ namespace Endroid\QrCode;
11
+
12
+ interface QrCodeInterface
13
+ {
14
+ /**
15
+ * @return string
16
+ */
17
+ public function getText();
18
+
19
+ /**
20
+ * @return int
21
+ */
22
+ public function getSize();
23
+
24
+ /**
25
+ * @return int
26
+ */
27
+ public function getMargin();
28
+
29
+ /**
30
+ * @return int[]
31
+ */
32
+ public function getForegroundColor();
33
+
34
+ /**
35
+ * @return int[]
36
+ */
37
+ public function getBackgroundColor();
38
+
39
+ /**
40
+ * @return string
41
+ */
42
+ public function getEncoding();
43
+
44
+ /**
45
+ * @return string
46
+ */
47
+ public function getErrorCorrectionLevel();
48
+
49
+ /**
50
+ * @return string
51
+ */
52
+ public function getLogoPath();
53
+
54
+ /**
55
+ * @return int
56
+ */
57
+ public function getLogoWidth();
58
+
59
+ /**
60
+ * @return string
61
+ */
62
+ public function getLabel();
63
+
64
+ /**
65
+ * @return string
66
+ */
67
+ public function getLabelFontPath();
68
+
69
+ /**
70
+ * @return int
71
+ */
72
+ public function getLabelFontSize();
73
+
74
+ /**
75
+ * @return string
76
+ */
77
+ public function getLabelAlignment();
78
+
79
+ /**
80
+ * @return int[]
81
+ */
82
+ public function getLabelMargin();
83
+
84
+ /**
85
+ * @return bool
86
+ */
87
+ public function getValidateResult();
88
+
89
+ /**
90
+ * @param WriterRegistryInterface $writerRegistry
91
+ *
92
+ * @return mixed
93
+ */
94
+ public function setWriterRegistry(WriterRegistryInterface $writerRegistry);
95
+ }
src/lib/vendor/endroid/qr-code/src/StaticWriterRegistry.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * (c) Jeroen van den Enden <info@endroid.nl>
5
+ *
6
+ * This source file is subject to the MIT license that is bundled
7
+ * with this source code in the file LICENSE.
8
+ */
9
+
10
+ namespace Endroid\QrCode;
11
+
12
+ use Endroid\QrCode\Writer\BinaryWriter;
13
+ use Endroid\QrCode\Writer\DebugWriter;
14
+ use Endroid\QrCode\Writer\EpsWriter;
15
+ use Endroid\QrCode\Writer\PngWriter;
16
+ use Endroid\QrCode\Writer\SvgWriter;
17
+
18
+ class StaticWriterRegistry extends WriterRegistry
19
+ {
20
+ /**
21
+ * {@inheritdoc}
22
+ */
23
+ public function __construct()
24
+ {
25
+ parent::__construct();
26
+
27
+ $this->loadWriters();
28
+ }
29
+
30
+ protected function loadWriters()
31
+ {
32
+ if (count($this->writers) > 0) {
33
+ return;
34
+ }
35
+
36
+ $this->addWriter(new BinaryWriter());
37
+ $this->addWriter(new DebugWriter());
38
+ $this->addWriter(new EpsWriter());
39
+ $this->addWriter(new PngWriter(), true);
40
+ $this->addWriter(new SvgWriter());
41
+ }
42
+ }
src/lib/vendor/endroid/qr-code/src/Twig/Extension/QrCodeExtension.php ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * (c) Jeroen van den Enden <info@endroid.nl>
5
+ *
6
+ * This source file is subject to the MIT license that is bundled
7
+ * with this source code in the file LICENSE.
8
+ */
9
+
10
+ namespace Endroid\QrCode\Twig\Extension;
11
+
12
+ use Endroid\QrCode\Exception\UnsupportedExtensionException;
13
+ use Endroid\QrCode\Factory\QrCodeFactory;
14
+ use Endroid\QrCode\WriterRegistryInterface;
15
+ use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
16
+ use Symfony\Component\Routing\RouterInterface;
17
+ use Twig_Extension;
18
+ use Twig_SimpleFunction;
19
+
20
+ class QrCodeExtension extends Twig_Extension
21
+ {
22
+ /**
23
+ * @var QrCodeFactory
24
+ */
25
+ protected $qrCodeFactory;
26
+
27
+ /**
28
+ * @var RouterInterface
29
+ */
30
+ protected $router;
31
+
32
+ /**
33
+ * @param QrCodeFactory $qrCodeFactory
34
+ * @param RouterInterface $router
35
+ * @param WriterRegistryInterface $writerRegistry
36
+ */
37
+ public function __construct(QrCodeFactory $qrCodeFactory, RouterInterface $router)
38
+ {
39
+ $this->qrCodeFactory = $qrCodeFactory;
40
+ $this->router = $router;
41
+ }
42
+
43
+ /**
44
+ * {@inheritdoc}
45
+ */
46
+ public function getFunctions()
47
+ {
48
+ return [
49
+ new Twig_SimpleFunction('qrcode_path', [$this, 'qrCodePathFunction']),
50
+ new Twig_SimpleFunction('qrcode_url', [$this, 'qrCodeUrlFunction']),
51
+ new Twig_SimpleFunction('qrcode_data_uri', [$this, 'qrCodeDataUriFunction']),
52
+ ];
53
+ }
54
+
55
+ /**
56
+ * @param string $text
57
+ * @param array $options
58
+ *
59
+ * @return string
60
+ */
61
+ public function qrcodeUrlFunction($text, array $options = [])
62
+ {
63
+ return $this->getQrCodeReference($text, $options, UrlGeneratorInterface::ABSOLUTE_URL);
64
+ }
65
+
66
+ /**
67
+ * @param string $text
68
+ * @param array $options
69
+ *
70
+ * @return string
71
+ */
72
+ public function qrCodePathFunction($text, array $options = [])
73
+ {
74
+ return $this->getQrCodeReference($text, $options, UrlGeneratorInterface::ABSOLUTE_PATH);
75
+ }
76
+
77
+ /**
78
+ * @param string $text
79
+ * @param array $options
80
+ * @param int $referenceType
81
+ *
82
+ * @return string
83
+ */
84
+ public function getQrCodeReference($text, array $options = [], $referenceType)
85
+ {
86
+ $qrCode = $this->qrCodeFactory->create($text, $options);
87
+ $supportedExtensions = $qrCode->getWriter()->getSupportedExtensions();
88
+
89
+ $options['text'] = $text;
90
+ $options['extension'] = current($supportedExtensions);
91
+
92
+ return $this->router->generate('endroid_qrcode_generate', $options, $referenceType);
93
+ }
94
+
95
+ /**
96
+ * @param string $text
97
+ * @param array $options
98
+ *
99
+ * @return string
100
+ *
101
+ * @throws UnsupportedExtensionException
102
+ */
103
+ public function qrcodeDataUriFunction($text, array $options = [])
104
+ {
105
+ $qrCode = $this->qrCodeFactory->create($text, $options);
106
+
107
+ return $qrCode->writeDataUri();
108
+ }
109
+
110
+ /**
111
+ * @return string
112
+ */
113
+ public function getName()
114
+ {
115
+ return 'qrcode';
116
+ }
117
+ }
src/lib/vendor/endroid/qr-code/src/Writer/AbstractBaconWriter.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * (c) Jeroen van den Enden <info@endroid.nl>
5
+ *
6
+ * This source file is subject to the MIT license that is bundled
7
+ * with this source code in the file LICENSE.
8
+ */
9
+
10
+ namespace Endroid\QrCode\Writer;
11
+
12
+ use BaconQrCode\Renderer\Color\Rgb;
13
+
14
+ abstract class AbstractBaconWriter extends AbstractWriter
15
+ {
16
+ /**
17
+ * @param array $color
18
+ *
19
+ * @return Rgb
20
+ */
21
+ protected function convertColor(array $color)
22
+ {
23
+ $color = new Rgb($color['r'], $color['g'], $color['b']);
24
+
25
+ return $color;
26
+ }
27
+
28
+ /**
29
+ * @param string $errorCorrectionLevel
30
+ *
31
+ * @return string
32
+ */
33
+ protected function convertErrorCorrectionLevel($errorCorrectionLevel)
34
+ {
35
+ $name = strtoupper(substr($errorCorrectionLevel, 0, 1));
36
+ $errorCorrectionLevel = constant('BaconQrCode\Common\ErrorCorrectionLevel::'.$name);
37
+
38
+ return $errorCorrectionLevel;
39
+ }
40
+ }
src/lib/vendor/endroid/qr-code/src/Writer/AbstractWriter.php ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * (c) Jeroen van den Enden <info@endroid.nl>
5
+ *
6
+ * This source file is subject to the MIT license that is bundled
7
+ * with this source code in the file LICENSE.
8
+ */
9
+
10
+ namespace Endroid\QrCode\Writer;
11
+
12
+ use Endroid\QrCode\QrCodeInterface;
13
+ use ReflectionClass;
14
+
15
+ abstract class AbstractWriter implements WriterInterface
16
+ {
17
+ /**
18
+ * {@inheritdoc}
19
+ */
20
+ public function writeDataUri(QrCodeInterface $qrCode)
21
+ {
22
+ $dataUri = 'data:'.$this->getContentType().';base64,'.base64_encode($this->writeString($qrCode));
23
+
24
+ return $dataUri;
25
+ }
26
+
27
+ /**
28
+ * {@inheritdoc}
29
+ */
30
+ public function writeFile(QrCodeInterface $qrCode, $path)
31
+ {
32
+ $string = $this->writeString($qrCode);
33
+ file_put_contents($path, $string);
34
+ }
35
+
36
+ /**
37
+ * {@inheritdoc}
38
+ */
39
+ public static function supportsExtension($extension)
40
+ {
41
+ return in_array($extension, static::getSupportedExtensions());
42
+ }
43
+
44
+ /**
45
+ * {@inheritdoc}
46
+ */
47
+ public static function getSupportedExtensions()
48
+ {
49
+ return [];
50
+ }
51
+
52
+ /**
53
+ * {@inheritdoc}
54
+ */
55
+ public function getName()
56
+ {
57
+ $reflectionClass = new ReflectionClass($this);
58
+ $className = $reflectionClass->getShortName();
59
+ $name = strtolower(preg_replace('/(?<!^)[A-Z]/', '_$0', str_replace('Writer', '', $className)));
60
+
61
+ return $name;
62
+ }
63
+ }
src/lib/vendor/endroid/qr-code/src/Writer/BinaryWriter.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * (c) Jeroen van den Enden <info@endroid.nl>
5
+ *
6
+ * This source file is subject to the MIT license that is bundled
7
+ * with this source code in the file LICENSE.
8
+ */
9
+
10
+ namespace Endroid\QrCode\Writer;
11
+
12
+ use Endroid\QrCode\QrCodeInterface;
13
+
14
+ class BinaryWriter extends AbstractWriter
15
+ {
16
+ /**
17
+ * {@inheritdoc}
18
+ */
19
+ public function writeString(QrCodeInterface $qrCode)
20
+ {
21
+ $string = '
22
+ 0001010101
23
+ 0001010101
24
+ 1000101010
25
+ 0001010101
26
+ 0101010101
27
+ 0001010101
28
+ 0001010101
29
+ 0001010101
30
+ 0001010101
31
+ 1000101010
32
+ ';
33
+
34
+ return $string;
35
+ }
36
+
37
+ /**
38
+ * {@inheritdoc}
39
+ */
40
+ public static function getContentType()
41
+ {
42
+ return 'text/plain';
43
+ }
44
+
45
+ /**
46
+ * {@inheritdoc}
47
+ */
48
+ public static function getSupportedExtensions()
49
+ {
50
+ return ['bin', 'txt'];
51
+ }
52
+ }
src/lib/vendor/endroid/qr-code/src/Writer/DebugWriter.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * (c) Jeroen van den Enden <info@endroid.nl>
5
+ *
6
+ * This source file is subject to the MIT license that is bundled
7
+ * with this source code in the file LICENSE.
8
+ */
9
+
10
+ namespace Endroid\QrCode\Writer;
11
+
12
+ use Endroid\QrCode\QrCodeInterface;
13
+ use ReflectionClass;
14
+ use Exception;
15
+
16
+ class DebugWriter extends AbstractWriter
17
+ {
18
+ /**
19
+ * {@inheritdoc}
20
+ */
21
+ public function writeString(QrCodeInterface $qrCode)
22
+ {
23
+ $data = [];
24
+
25
+ $reflectionClass = new ReflectionClass($qrCode);
26
+ foreach ($reflectionClass->getMethods() as $method) {
27
+ $methodName = $method->getShortName();
28
+ if (0 === strpos($methodName, 'get') && 0 == $method->getNumberOfParameters()) {
29
+ $value = $qrCode->{$methodName}();
30
+ if (is_array($value) && !is_object(current($value))) {
31
+ $value = '['.implode(', ', $value).']';
32
+ } elseif (is_bool($value)) {
33
+ $value = $value ? 'true' : 'false';
34
+ } elseif (is_string($value)) {
35
+ $value = '"'.$value.'"';
36
+ } elseif (is_null($value)) {
37
+ $value = 'null';
38
+ }
39
+ try {
40
+ $data[] = $methodName.': '.$value;
41
+ } catch (Exception $exception) {
42
+ }
43
+ }
44
+ }
45
+
46
+ $string = implode(" \n", $data);
47
+
48
+ return $string;
49
+ }
50
+
51
+ /**
52
+ * {@inheritdoc}
53
+ */
54
+ public static function getContentType()
55
+ {
56
+ return 'text/plain';
57
+ }
58
+ }
src/lib/vendor/endroid/qr-code/src/Writer/EpsWriter.php ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * (c) Jeroen van den Enden <info@endroid.nl>
5
+ *
6
+ * This source file is subject to the MIT license that is bundled
7
+ * with this source code in the file LICENSE.
8
+ */
9
+
10
+ namespace Endroid\QrCode\Writer;
11
+
12
+ use BaconQrCode\Renderer\Image\Eps;
13
+ use BaconQrCode\Writer;
14
+ use Endroid\QrCode\QrCodeInterface;
15
+
16
+ class EpsWriter extends AbstractBaconWriter
17
+ {
18
+ /**
19
+