Version Description
Download this release
Release Info
Developer | paultgoodchild |
Plugin | Shield Security for WordPress |
Version | 11.0.0 |
Comparing to | |
See all releases |
Code changes from version 10.2.6 to 11.0.0
- cl.json +92 -0
- icwp-wpsf.php +1 -1
- init.php +1 -11
- plugin-spec.php +95 -35
- readme.txt +17 -11
- resources/css/bootstrap-select.min.css +0 -6
- resources/css/chartist.min.css +0 -1
- resources/css/introjs.min.css +0 -1
- resources/css/plugin.css +12 -21
- resources/css/shield/charts.css +27 -0
- resources/images/bootstrap/graph-up.svg +3 -0
- resources/js/base64.min.js +0 -1
- resources/js/bootstrap-select.min.js +0 -9
- resources/js/chartist.min.js +0 -10
- resources/js/charts.js +0 -131
- resources/js/introjs.min.js +0 -1
- resources/js/plugin.js +8 -11
- resources/js/shield-comments.js +0 -137
- resources/js/shield/antibot.js +62 -0
- resources/js/shield/charts.js +138 -0
- resources/js/shield/comments.js +137 -0
- resources/js/shield/ipanalyse.js +9 -6
- resources/js/{shield-antibot.js → shield/loginbot.js} +31 -23
- resources/js/{shield-card-shuffle.js → shield/shuffle.js} +0 -0
- resources/js/shield/tours.js +43 -0
- resources/js/shuffle.js +0 -2190
- resources/js/shuffle.min.js +0 -2
- resources/js/whitelabel.js +0 -8
- resources/js/wizard.js +0 -0
- src/config/feature-audit_trail.php +17 -5
- src/config/feature-comments_filter.php +44 -29
- src/config/feature-events.php +7 -0
- src/config/feature-firewall.php +2 -0
- src/config/feature-hack_protect.php +53 -25
- src/config/feature-integrations.php +82 -0
- src/config/feature-ips.php +143 -10
- src/config/feature-license.php +24 -8
- src/config/feature-login_protect.php +15 -1
- src/config/feature-plugin.php +38 -20
- src/config/feature-reporting.php +28 -12
- src/config/feature-sessions.php +23 -1
- src/config/feature-traffic.php +19 -7
- src/lib/functions/functions.php +39 -0
- src/lib/src/Controller/Admin/MainAdminMenu.php +7 -7
- src/lib/src/Controller/Ajax/Init.php +13 -4
- src/lib/src/Controller/Assets/Enqueue.php +22 -6
- src/lib/src/Controller/Assets/Paths.php +38 -0
- src/lib/src/Controller/Assets/Urls.php +33 -21
- src/lib/src/Controller/Config/ConfigVO.php +13 -8
- src/lib/src/Controller/Controller.php +129 -159
- src/lib/src/Controller/Utilities/CaptureMyUpgrade.php +37 -0
- src/lib/src/Controller/Utilities/DebugMode.php +3 -3
- src/lib/src/Crons/DailyCron.php +7 -7
- src/lib/src/Databases/AdminNotes/Handler.php +1 -10
- src/lib/src/Databases/AdminNotes/Insert.php +7 -11
- src/lib/src/Databases/AuditTrail/EntryVO.php +2 -3
- src/lib/src/Databases/AuditTrail/Insert.php +8 -8
- src/lib/src/Databases/AuditTrail/Select.php +14 -12
- src/lib/src/Databases/AuditTrail/Update.php +7 -11
- src/lib/src/Databases/Base/BaseQuery.php +19 -22
- src/lib/src/Databases/Base/Delete.php +6 -6
- src/lib/src/Databases/Base/EntryVO.php +34 -46
- src/lib/src/Databases/Base/Handler.php +126 -60
- src/lib/src/Databases/Base/Insert.php +11 -24
- src/lib/src/Databases/Base/Iterator.php +111 -0
- src/lib/src/Databases/Base/Traits/Select_IPTable.php +24 -0
- src/lib/src/Databases/Base/Update.php +34 -26
- src/lib/src/Databases/BotSignals/Common.php +34 -0
- src/lib/src/Databases/BotSignals/Delete.php +10 -0
- src/lib/src/Databases/BotSignals/EntryVO.php +67 -0
- src/lib/src/Databases/BotSignals/Handler.php +10 -0
- src/lib/src/Databases/BotSignals/Insert.php +9 -0
- src/lib/src/Databases/BotSignals/Select.php +21 -0
- src/lib/src/Databases/BotSignals/Update.php +7 -0
- src/lib/src/Databases/ChangeTracking/EntryVO.php +9 -12
- src/lib/src/Databases/Common/TableSchema.php +74 -11
- src/lib/src/Databases/Events/Select.php +3 -3
- src/lib/src/Databases/Events/Update.php +2 -4
- src/lib/src/Databases/FileLocker/EntryVO.php +11 -20
- src/lib/src/Databases/FileLocker/Insert.php +2 -4
- src/lib/src/Databases/FileLocker/Update.php +15 -16
- src/lib/src/Databases/GeoIp/EntryVO.php +11 -14
- src/lib/src/Databases/GeoIp/Handler.php +2 -12
- src/lib/src/Databases/GeoIp/Select.php +1 -12
- src/lib/src/Databases/IPs/EntryVO.php +1 -1
- src/lib/src/Databases/IPs/Handler.php +15 -3
- src/lib/src/Databases/IPs/Insert.php +6 -6
- src/lib/src/Databases/IPs/Update.php +17 -20
- src/lib/src/Databases/Reports/Handler.php +2 -14
- src/lib/src/Databases/ScanQueue/EntryVO.php +18 -21
- src/lib/src/Databases/ScanQueue/Handler.php +1 -14
- src/lib/src/Databases/ScanQueue/Update.php +10 -10
- src/lib/src/Databases/Scanner/Handler.php +1 -14
- src/lib/src/Databases/Scanner/Update.php +12 -12
- src/lib/src/Databases/Session/Insert.php +15 -18
- src/lib/src/Databases/Session/Select.php +1 -6
- src/lib/src/Databases/Session/Update.php +3 -3
- src/lib/src/Databases/Tally/Delete.php +0 -9
- src/lib/src/Databases/Tally/EntryVO.php +0 -16
- src/lib/src/Databases/Tally/Handler.php +0 -32
- src/lib/src/Databases/Tally/Insert.php +0 -45
- src/lib/src/Databases/Tally/Select.php +0 -39
- src/lib/src/Databases/Tally/Update.php +0 -17
- src/lib/src/Databases/Traffic/EntryVO.php +12 -13
- src/lib/src/Databases/Traffic/Insert.php +3 -3
- src/lib/src/Databases/Traffic/Select.php +1 -12
- src/lib/src/Modules/AuditTrail/AjaxHandler.php +13 -27
- src/lib/src/Modules/AuditTrail/Lib/AuditMessageBuilder.php +25 -0
- src/lib/src/Modules/AuditTrail/Lib/Ops/Commit.php +20 -23
- src/lib/src/Modules/AuditTrail/Lib/Utility/AutoWhitelistParamFromAuditEntry.php +55 -0
- src/lib/src/Modules/AuditTrail/ModCon.php +17 -5
- src/lib/src/Modules/Base/AjaxHandler.php +7 -3
- src/lib/src/Modules/Base/BaseProcessor.php +0 -183
- src/lib/src/Modules/Base/ModCon.php +104 -98
- src/lib/src/Modules/Base/Options.php +5 -6
- src/lib/src/Modules/Base/Processor.php +2 -2
- src/lib/src/Modules/Base/UI.php +14 -15
- src/lib/src/Modules/Base/Upgrade.php +2 -1
- src/lib/src/Modules/Base/WpCli.php +4 -3
- src/lib/src/Modules/Base/WpCli/BaseWpCliCmd.php +31 -56
- src/lib/src/Modules/Base/WpCli/ModuleStandard.php +17 -17
- src/lib/src/Modules/BaseShield/ModCon.php +40 -44
- src/lib/src/Modules/BaseShield/ShieldProcessor.php +0 -14
- src/lib/src/Modules/BaseShield/UI.php +6 -5
- src/lib/src/Modules/CommentsFilter/AjaxHandler.php +9 -14
- src/lib/src/Modules/CommentsFilter/Forms/Gasp.php +56 -58
- src/lib/src/Modules/CommentsFilter/Forms/GoogleRecaptcha.php +3 -3
- src/lib/src/Modules/CommentsFilter/Insights/OverviewCards.php +3 -2
- src/lib/src/Modules/CommentsFilter/ModCon.php +5 -0
- src/lib/src/Modules/CommentsFilter/Options.php +7 -2
- src/lib/src/Modules/CommentsFilter/Processor.php +8 -4
- src/lib/src/Modules/CommentsFilter/Scan/AntiBot.php +25 -0
- src/lib/src/Modules/CommentsFilter/Scan/Bot.php +26 -26
- src/lib/src/Modules/CommentsFilter/Scan/CommentAdditiveCleaner.php +26 -0
- src/lib/src/Modules/CommentsFilter/Scan/Human.php +21 -61
- src/lib/src/Modules/CommentsFilter/Scan/Scanner.php +63 -46
- src/lib/src/Modules/CommentsFilter/Strings.php +74 -50
- src/lib/src/Modules/CommentsFilter/Upgrade.php +6 -6
- src/lib/src/Modules/Events/AjaxHandler.php +0 -66
- src/lib/src/Modules/Events/Charts/BuildData.php +0 -131
- src/lib/src/Modules/Events/Charts/ChartRequestVO.php +0 -20
- src/lib/src/Modules/Events/Lib/Reports/KeyStats.php +1 -0
- src/lib/src/Modules/Events/Lib/StatsWriter.php +3 -3
- src/lib/src/Modules/Events/Processor.php +17 -19
- src/lib/src/Modules/Events/Strings.php +14 -11
- src/lib/src/Modules/GeoIp/Lookup.php +4 -5
- src/lib/src/Modules/HackGuard/AjaxHandler.php +20 -20
- src/lib/src/Modules/HackGuard/Debug.php +0 -7
- src/lib/src/Modules/HackGuard/Lib/FileLocker/File.php +10 -13
- src/lib/src/Modules/HackGuard/Lib/FileLocker/FileLockerController.php +107 -84
- src/lib/src/Modules/HackGuard/Lib/FileLocker/Ops/Accept.php +10 -10
- src/lib/src/Modules/HackGuard/Lib/FileLocker/Ops/AssessLocks.php +18 -18
- src/lib/src/Modules/HackGuard/Lib/FileLocker/Ops/BaseOps.php +4 -4
- src/lib/src/Modules/HackGuard/Lib/FileLocker/Ops/CreateFileLocks.php +20 -18
- src/lib/src/Modules/HackGuard/Lib/FileLocker/Ops/Diff.php +17 -13
- src/lib/src/Modules/HackGuard/Lib/FileLocker/Ops/LoadFileLocks.php +10 -10
- src/lib/src/Modules/HackGuard/Lib/FileLocker/Ops/PerformAction.php +13 -13
- src/lib/src/Modules/HackGuard/Lib/FileLocker/Ops/ReadOriginalFileContent.php +16 -16
- src/lib/src/Modules/HackGuard/Lib/Utility/FileDownloadHandler.php +11 -11
- src/lib/src/Modules/HackGuard/ModCon.php +12 -14
- src/lib/src/Modules/HackGuard/Scan/Controller/Base.php +1 -5
- src/lib/src/Modules/HackGuard/Scan/Queue/CompleteQueue.php +13 -13
- src/lib/src/Modules/HackGuard/Scan/Queue/ConvertBetweenTypes.php +1 -1
- src/lib/src/Modules/HackGuard/Scan/Queue/QueueProcessor.php +19 -20
- src/lib/src/Modules/HackGuard/Scan/Results/ResultsUpdate.php +1 -1
- src/lib/src/Modules/HackGuard/Scan/ScansController.php +35 -21
- src/lib/src/Modules/HackGuard/Scan/Utilities/WpvAddPluginRows.php +3 -3
- src/lib/src/Modules/HackGuard/Strings.php +35 -33
- src/lib/src/Modules/HackGuard/UI.php +3 -3
- src/lib/src/Modules/Headers/ModCon.php +8 -65
- src/lib/src/Modules/Headers/Strings.php +0 -40
- src/lib/src/Modules/IPs/AjaxHandler.php +77 -35
- src/lib/src/Modules/IPs/BotTrack/Base.php +10 -8
- src/lib/src/Modules/IPs/BotTrack/Track404.php +1 -1
- src/lib/src/Modules/IPs/BotTrack/TrackCommentSpam.php +40 -0
- src/lib/src/Modules/IPs/BotTrack/TrackFakeWebCrawler.php +23 -18
- src/lib/src/Modules/IPs/BotTrack/TrackInvalidScriptLoad.php +58 -0
- src/lib/src/Modules/IPs/BotTrack/TrackLinkCheese.php +45 -44
- src/lib/src/Modules/IPs/Components/ImportIpsFromFile.php +1 -1
- src/lib/src/Modules/IPs/Components/QueryIpBlock.php +1 -1
- src/lib/src/Modules/IPs/Components/UnblockIpByFlag.php +2 -2
- src/lib/src/Modules/IPs/Lib/AutoUnblock.php +28 -8
- src/lib/src/Modules/IPs/Lib/BlacklistHandler.php +41 -31
- src/lib/src/Modules/IPs/Lib/BlockRequest.php +8 -6
- src/lib/src/Modules/IPs/Lib/Bots/BotSignalsController.php +69 -0
- src/lib/src/Modules/IPs/Lib/Bots/BotSignalsRecord.php +105 -0
- src/lib/src/Modules/IPs/Lib/Bots/Calculator/BuildScores.php +297 -0
- src/lib/src/Modules/IPs/Lib/Bots/Calculator/CalculateVisitorBotScores.php +60 -0
- src/lib/src/Modules/IPs/Lib/Bots/EventListener.php +80 -0
- src/lib/src/Modules/IPs/Lib/Bots/NotBot/InsertNotBotJs.php +46 -0
- src/lib/src/Modules/IPs/Lib/Bots/NotBot/NotBotHandler.php +96 -0
- src/lib/src/Modules/IPs/Lib/IpAnalyse/BuildDisplay.php +137 -44
- src/lib/src/Modules/IPs/Lib/IpAnalyse/FindAllPluginIps.php +7 -0
- src/lib/src/Modules/IPs/Lib/Ops/AddIp.php +53 -53
- src/lib/src/Modules/IPs/Lib/Ops/DeleteIp.php +8 -9
- src/lib/src/Modules/IPs/Lib/Ops/LookupIpOnList.php +21 -3
- src/lib/src/Modules/IPs/Lib/ProcessOffenses.php +7 -1
- src/lib/src/Modules/IPs/ModCon.php +30 -1
- src/lib/src/Modules/IPs/Options.php +13 -37
- src/lib/src/Modules/IPs/Processor.php +1 -0
- src/lib/src/Modules/IPs/Strings.php +120 -56
- src/lib/src/Modules/IPs/UI.php +5 -0
- src/lib/src/Modules/IPs/Upgrade.php +1 -1
- src/lib/src/Modules/IPs/WpCli/BaseAddRemove.php +3 -1
- src/lib/src/Modules/IPs/WpCli/Remove.php +1 -1
- src/lib/src/Modules/Insights/ModCon.php +15 -23
- src/lib/src/Modules/Insights/Strings.php +4 -3
- src/lib/src/Modules/Insights/UI.php +17 -13
- src/lib/src/Modules/Integrations/Lib/MainWP/Common/MWPExtensionVO.php +8 -12
- src/lib/src/Modules/Integrations/Lib/MainWP/Common/MWPSiteVO.php +9 -13
- src/lib/src/Modules/Integrations/Lib/MainWP/Common/MainWPVO.php +9 -13
- src/lib/src/Modules/Integrations/Lib/MainWP/Common/SyncMetaVO.php +2 -2
- src/lib/src/Modules/Integrations/Lib/MainWP/Common/SyncVO.php +6 -10
- src/lib/src/Modules/Integrations/Lib/MainWP/Controller.php +2 -2
- src/lib/src/Modules/Integrations/Lib/MainWP/Server/Data/ClientPluginStatus.php +1 -1
- src/lib/src/Modules/Integrations/Lib/MainWP/Server/Data/LoadShieldSyncData.php +1 -1
- src/lib/src/Modules/Integrations/Lib/MainWP/Server/Data/SyncHandler.php +2 -2
- src/lib/src/Modules/Integrations/Lib/MainWP/Server/UI/ExtensionSettingsPage.php +3 -3
- src/lib/src/Modules/Integrations/Lib/MainWP/Server/UI/ManageSites/SitesListTableHandler.php +2 -2
- src/lib/src/Modules/Integrations/Lib/MainWP/Server/UI/PageRender/SitesList.php +1 -1
- src/lib/src/Modules/Integrations/Lib/Spam/Handlers/Base.php +65 -0
- src/lib/src/Modules/Integrations/Lib/Spam/Handlers/ContactForm7.php +20 -0
- src/lib/src/Modules/Integrations/Lib/Spam/Handlers/ElementorPro.php +26 -0
- src/lib/src/Modules/Integrations/Lib/Spam/Handlers/FluentForms.php +28 -0
- src/lib/src/Modules/Integrations/Lib/Spam/Handlers/FormidableForms.php +29 -0
- src/lib/src/Modules/Integrations/Lib/Spam/Handlers/Forminator.php +20 -0
- src/lib/src/Modules/Integrations/Lib/Spam/Handlers/GravityForms.php +21 -0
- src/lib/src/Modules/Integrations/Lib/Spam/Handlers/Helpers/NinjaForms_ShieldSpamAction.php +47 -0
- src/lib/src/Modules/Integrations/Lib/Spam/Handlers/KaliForms.php +27 -0
- src/lib/src/Modules/Integrations/Lib/Spam/Handlers/NinjaForms.php +48 -0
- src/lib/src/Modules/Integrations/Lib/Spam/Handlers/WPForms.php +37 -0
- src/lib/src/Modules/Integrations/Lib/Spam/Handlers/WpForo.php +40 -0
- src/lib/src/Modules/Integrations/Lib/Spam/SpamController.php +46 -0
- src/lib/src/Modules/Integrations/Processor.php +7 -4
- src/lib/src/Modules/Integrations/Strings.php +14 -0
- src/lib/src/Modules/License/Lib/LicenseHandler.php +24 -61
- src/lib/src/Modules/License/Lib/PluginNameSuffix.php +3 -3
- src/lib/src/Modules/License/Lib/Verify.php +4 -4
- src/lib/src/Modules/License/Lib/WpHashes/ApiTokenManager.php +4 -4
- src/lib/src/Modules/License/WpCli/License.php +2 -3
- src/lib/src/Modules/Lockdown/Lib/CleanRubbish.php +12 -16
- src/lib/src/Modules/Lockdown/Processor.php +6 -6
- src/lib/src/Modules/LoginGuard/Insights/OverviewCards.php +10 -10
- src/lib/src/Modules/LoginGuard/Lib/AntiBot/AntibotSetup.php +25 -22
- src/lib/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/BaseFormProvider.php +5 -10
- src/lib/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/BuddyPress.php +1 -1
- src/lib/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/EasyDigitalDownloads.php +2 -2
- src/lib/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/LearnPress.php +3 -3
- src/lib/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/MemberPress.php +4 -4
- src/lib/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/PaidMemberSubscriptions.php +1 -1
- src/lib/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/ProfileBuilder.php +1 -1
- src/lib/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/UltimateMember.php +3 -3
- src/lib/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/UserRegistration.php +3 -3
- src/lib/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/WooCommerce.php +4 -4
- src/lib/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/WordPress.php +13 -15
- src/lib/src/Modules/LoginGuard/Lib/AntiBot/ProtectionProviders/AntiBot.php +29 -0
- src/lib/src/Modules/LoginGuard/Lib/AntiBot/ProtectionProviders/BaseProtectionProvider.php +29 -10
- src/lib/src/Modules/LoginGuard/Lib/AntiBot/ProtectionProviders/GaspJs.php +67 -57
- src/lib/src/Modules/LoginGuard/Lib/CooldownFlagFile.php +8 -12
- src/lib/src/Modules/LoginGuard/Lib/Rename/RenameLogin.php +7 -7
- src/lib/src/Modules/LoginGuard/Lib/TwoFactor/LoginIntentPage.php +4 -4
- src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Profiles/CustomForms.php +2 -2
- src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Yubikey.php +0 -1
- src/lib/src/Modules/LoginGuard/ModCon.php +13 -7
- src/lib/src/Modules/LoginGuard/Options.php +12 -16
- src/lib/src/Modules/LoginGuard/Processor.php +11 -1
- src/lib/src/Modules/LoginGuard/Strings.php +12 -0
- src/lib/src/Modules/Plugin/AjaxHandler.php +20 -20
- src/lib/src/Modules/Plugin/Components/PluginBadge.php +1 -1
- src/lib/src/Modules/Plugin/Debug.php +0 -8
- src/lib/src/Modules/Plugin/Insights/DashboardCards.php +59 -28
- src/lib/src/Modules/Plugin/Insights/OverviewCards.php +3 -3
- src/lib/src/Modules/Plugin/Lib/Captcha/CaptchaConfigVO.php +9 -12
- src/lib/src/Modules/Plugin/Lib/Debug/Collate.php +21 -11
- src/lib/src/Modules/Plugin/Lib/ImportExport/Export.php +1 -2
- src/lib/src/Modules/Plugin/Lib/ImportExport/ImportExportController.php +1 -11
- src/lib/src/Modules/Plugin/Lib/PluginTelemetry.php +6 -4
- src/lib/src/Modules/Plugin/Lib/TestCacheDirWrite.php +34 -38
- src/lib/src/Modules/Plugin/Lib/TourManager.php +29 -27
- src/lib/src/Modules/Plugin/ModCon.php +39 -28
- src/lib/src/Modules/Plugin/Processor.php +5 -5
- src/lib/src/Modules/Plugin/Strings.php +12 -6
- src/lib/src/Modules/Plugin/WpCli/Reset.php +2 -2
- src/lib/src/Modules/Plugin/WpCli/ToggleDebug.php +2 -2
- src/lib/src/Modules/Reporting/AjaxHandler.php +62 -0
- src/lib/src/Modules/Reporting/Charts/BaseBuildChartData.php +162 -0
- src/lib/src/Modules/Reporting/Charts/ChartRequestConsumer.php +27 -0
- src/lib/src/Modules/Reporting/Charts/ChartRequestVO.php +35 -0
- src/lib/src/Modules/Reporting/Charts/CustomChartData.php +43 -0
- src/lib/src/Modules/Reporting/Charts/CustomChartRequestVO.php +12 -0
- src/lib/src/Modules/Reporting/Lib/ReportingController.php +3 -6
- src/lib/src/Modules/Reporting/Lib/Reports/ReportVO.php +2 -2
- src/lib/src/Modules/Reporting/UI.php +76 -47
- src/lib/src/Modules/SecurityAdmin/AjaxHandler.php +22 -35
- src/lib/src/Modules/SecurityAdmin/Lib/WhiteLabel/ApplyLabels.php +3 -3
- src/lib/src/Modules/SecurityAdmin/ModCon.php +18 -8
- src/lib/src/Modules/SecurityAdmin/Strings.php +103 -95
- src/lib/src/Modules/Sessions/ModCon.php +2 -1
- src/lib/src/Modules/Sessions/Processor.php +1 -0
- src/lib/src/Modules/Traffic/AjaxHandler.php +3 -3
- src/lib/src/Modules/Traffic/Lib/Logger.php +5 -18
- src/lib/src/Modules/Traffic/ModCon.php +11 -0
- src/lib/src/Modules/Traffic/Processor.php +0 -5
- src/lib/src/Modules/Traffic/Strings.php +60 -54
- src/lib/src/Modules/Traffic/UI.php +10 -14
- src/lib/src/Modules/UserManagement/Lib/Password/UserPasswordHandler.php +3 -3
- src/lib/src/Modules/UserManagement/Lib/Registration/EmailValidate.php +18 -18
- src/lib/src/Modules/UserManagement/Lib/Session/UserSessionHandler.php +3 -3
- src/lib/src/Modules/UserManagement/Lib/Suspend/UserSuspendController.php +3 -3
- src/lib/src/Scans/Apc/ResultItem.php +5 -7
- src/lib/src/Scans/Apc/Scan.php +1 -1
- src/lib/src/Scans/Apc/ScanActionVO.php +2 -4
- src/lib/src/Scans/Base/BaseMergeItems.php +1 -1
- src/lib/src/Scans/Base/BaseResultItem.php +7 -13
- src/lib/src/Scans/Base/BaseScanActionVO.php +12 -15
- src/lib/src/Scans/Base/Files/BaseFileMapScan.php +1 -1
- src/lib/src/Scans/Base/Table/BaseEntryFormatter.php +1 -1
- src/lib/src/Scans/Base/Utilities/ItemActionHandler.php +3 -3
- src/lib/src/Scans/Mal/ResultItem.php +5 -13
- src/lib/src/Scans/Mal/ScanActionVO.php +1 -3
- src/lib/src/Scans/Ptg/ResultItem.php +3 -8
- src/lib/src/Scans/Ptg/ScanActionVO.php +2 -4
- src/lib/src/Scans/Ufc/ResultItem.php +5 -10
- src/lib/src/Scans/Ufc/ScanActionVO.php +2 -4
- src/lib/src/Scans/Wcf/ResultItem.php +9 -17
- src/lib/src/Scans/Wcf/ScanActionVO.php +2 -4
- src/lib/src/Scans/Wpv/ResultItem.php +8 -15
- src/lib/src/Scans/Wpv/Scan.php +3 -3
- src/lib/src/Scans/Wpv/ScanActionVO.php +2 -4
- src/lib/src/Scans/Wpv/WpVulnDb/WpVulnVO.php +2 -2
- src/lib/src/ShieldNetApi/Common/BaseApi.php +15 -18
- src/lib/src/ShieldNetApi/Common/BaseShieldNetApi.php +10 -10
- src/lib/src/ShieldNetApi/FileLocker/DecryptFile.php +5 -6
- src/lib/src/ShieldNetApi/FileLocker/GetPublicKey.php +6 -6
- src/lib/src/ShieldNetApi/Handshake/Verify.php +4 -7
- src/lib/src/ShieldNetApi/HandshakingNonce.php +24 -31
- src/lib/src/ShieldNetApi/ShieldNetApiController.php +26 -29
- src/lib/src/ShieldNetApi/ShieldNetApiDataVO.php +10 -14
- src/lib/src/Tables/Build/AdminNotes.php +7 -7
- src/lib/src/Tables/Build/AuditTrail.php +64 -72
- src/lib/src/Tables/Build/Ip.php +21 -21
- src/lib/src/Tables/Build/ScanApc.php +7 -7
- src/lib/src/Tables/Build/ScanPtg.php +4 -4
- src/lib/src/Tables/Build/ScanWpv.php +7 -7
- src/lib/src/Tables/Build/Sessions.php +8 -8
- src/lib/src/Tables/Build/Traffic.php +9 -8
- src/lib/src/Tables/Render/WpListTable/AuditTrail.php +6 -6
- src/lib/src/Utilities/AdminNotices/Controller.php +9 -9
- src/lib/src/Utilities/AdminNotices/NoticeVO.php +3 -3
- src/lib/src/Utilities/HCaptcha/TestRequest.php +8 -8
- src/lib/src/Utilities/HumanSpam/TestContent.php +75 -0
- src/lib/src/Utilities/Options/CleanStorage.php +4 -4
- src/lib/src/Utilities/ReCaptcha/Enqueue.php +4 -4
- src/lib/src/Utilities/ReCaptcha/TestRequest.php +5 -6
- src/lib/src/Utilities/Resources/Dynamic.php +56 -0
- src/lib/src/Utilities/Time/WorldTimeApi.php +2 -2
- src/lib/src/Utilities/Tool/DbTableExport.php +50 -0
- src/lib/src/Utilities/Tool/IpListSort.php +9 -9
- src/lib/vendor/composer/autoload_classmap.php +48 -11
- src/lib/vendor/composer/autoload_files.php +1 -0
- src/lib/vendor/composer/autoload_static.php +49 -11
cl.json
CHANGED
@@ -1,4 +1,96 @@
|
|
1 |
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
"10.2": {
|
3 |
"version": "10.2",
|
4 |
"released_at": 1613037000,
|
1 |
{
|
2 |
+
"11.0": {
|
3 |
+
"version": "11.0",
|
4 |
+
"released_at": 1616666000,
|
5 |
+
"hrefs": {
|
6 |
+
"release": "https://shsec.io/shieldrelease1100",
|
7 |
+
"upgrade": "https://shsec.io/shieldupgradeguide1100"
|
8 |
+
},
|
9 |
+
"href": "https://shsec.io/",
|
10 |
+
"title": "All-New Shield AntiBot Detection Engine",
|
11 |
+
"description": [
|
12 |
+
"WordPress security nearly always starts with bots - detecting bad bots and blocking them.",
|
13 |
+
"This release delivers your new and exclusive AntiBot Detection Engine allowing Shield to more quickly identify bad bots and block their requests."
|
14 |
+
],
|
15 |
+
"items": [
|
16 |
+
{
|
17 |
+
"type": "new",
|
18 |
+
"pro_only": false,
|
19 |
+
"title": "AntiBot Detection Engine",
|
20 |
+
"description": [
|
21 |
+
"Detecting bad bots on you WordPress site is a huge challenge, but it's notoriously difficult to do this.",
|
22 |
+
"We have developed an exclusive system for the detection of bad bots and the option to block requests from them."
|
23 |
+
],
|
24 |
+
"href": "https://shsec.io/jb"
|
25 |
+
},
|
26 |
+
{
|
27 |
+
"type": "new",
|
28 |
+
"title": "Contact Form SPAM Protection",
|
29 |
+
"description": [
|
30 |
+
"With the arrival of our AntiBot Detection Engine, we can now more easily integrate with 3rd party plugins.",
|
31 |
+
"You can add Shield's SPAM protection to Elementor PRO Gravity Forms, Contact Form 7, Ninja Forms, and many more."
|
32 |
+
]
|
33 |
+
},
|
34 |
+
{
|
35 |
+
"type": "new",
|
36 |
+
"title": "Charts and Stats.",
|
37 |
+
"description": [
|
38 |
+
"We've added a page in Shield to allow you to chart some of your favourite Shield Stats."
|
39 |
+
]
|
40 |
+
},
|
41 |
+
{
|
42 |
+
"type": "new",
|
43 |
+
"title": "Download Audit Trail, Traffic Log and IP DB as CSV.",
|
44 |
+
"description": [
|
45 |
+
"A long-requested feature is the ability to download the raw database data - you can now do this with a single click."
|
46 |
+
]
|
47 |
+
},
|
48 |
+
{
|
49 |
+
"type": "new",
|
50 |
+
"title": "Added some new filters and hooks to allow customisation.",
|
51 |
+
"description": [
|
52 |
+
"For example, you can override the hour at which the Shield crons run, including the scans."
|
53 |
+
],
|
54 |
+
"href": "https://shsec.io/jv"
|
55 |
+
},
|
56 |
+
{
|
57 |
+
"type": "new",
|
58 |
+
"title": "Allow webmaster to specify certain web crawlers and search engines that aren't automatically whitelisted.",
|
59 |
+
"description": [],
|
60 |
+
"href": "https://shsec.io/jt"
|
61 |
+
},
|
62 |
+
{
|
63 |
+
"type": "improved",
|
64 |
+
"title": "Big improvements in the reliability of Shield's Database handling.",
|
65 |
+
"description": []
|
66 |
+
},
|
67 |
+
{
|
68 |
+
"type": "improved",
|
69 |
+
"title": "Use CDNJS to supply important plugin Javascript/CSS assets.",
|
70 |
+
"description": [
|
71 |
+
"Using a CDN to deliver assets reduces the plugin footprint on your site, while also speeding up admin page loading."
|
72 |
+
]
|
73 |
+
},
|
74 |
+
{
|
75 |
+
"type": "improved",
|
76 |
+
"title": "New and improved guided tour upon plugin activation.",
|
77 |
+
"description": []
|
78 |
+
},
|
79 |
+
{
|
80 |
+
"type": "improved",
|
81 |
+
"title": "Link Cheese Robots additions use enhanced Robots API in WordPress 5.7.",
|
82 |
+
"description": []
|
83 |
+
},
|
84 |
+
{
|
85 |
+
"type": "fixed",
|
86 |
+
"title": "Various bug fixes and enhancements.",
|
87 |
+
"description": [
|
88 |
+
"WP-Config FileLocker system is more reliable with requests in the case of database problems",
|
89 |
+
"Lots of code cleanup"
|
90 |
+
]
|
91 |
+
}
|
92 |
+
]
|
93 |
+
},
|
94 |
"10.2": {
|
95 |
"version": "10.2",
|
96 |
"released_at": 1613037000,
|
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:
|
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.0.0
|
7 |
* Text Domain: wp-simple-firewall
|
8 |
* Domain Path: /languages
|
9 |
* Author: Shield Security
|
init.php
CHANGED
@@ -56,14 +56,4 @@ catch ( \Exception $e ) {
|
|
56 |
error_log( 'Perhaps due to a failed upgrade, the Shield plugin failed to load certain component(s) - you should remove the plugin and reinstall.' );
|
57 |
error_log( $e->getMessage() );
|
58 |
}
|
59 |
-
}
|
60 |
-
|
61 |
-
if ( !function_exists( 'shield_security_get_plugin' ) ) {
|
62 |
-
/**
|
63 |
-
* @return ICWP_WPSF_Shield_Security|null
|
64 |
-
*/
|
65 |
-
function shield_security_get_plugin() {
|
66 |
-
global $oICWP_Wpsf;
|
67 |
-
return ( $oICWP_Wpsf instanceof \ICWP_WPSF_Shield_Security ) ? $oICWP_Wpsf : null;
|
68 |
-
}
|
69 |
-
}
|
56 |
error_log( 'Perhaps due to a failed upgrade, the Shield plugin failed to load certain component(s) - you should remove the plugin and reinstall.' );
|
57 |
error_log( $e->getMessage() );
|
58 |
}
|
59 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
plugin-spec.php
CHANGED
@@ -1,8 +1,8 @@
|
|
1 |
{
|
2 |
"properties": {
|
3 |
-
"version": "
|
4 |
-
"release_timestamp":
|
5 |
-
"build": "
|
6 |
"slug_parent": "icwp",
|
7 |
"slug_plugin": "wpsf",
|
8 |
"human_name": "Shield Security",
|
@@ -49,17 +49,17 @@
|
|
49 |
},
|
50 |
"plugin_admin": {
|
51 |
"css": [
|
52 |
-
"
|
53 |
"plugin",
|
54 |
-
"featherlight"
|
|
|
55 |
],
|
56 |
"js": [
|
57 |
-
"
|
58 |
"plugin",
|
59 |
-
"base64.min",
|
60 |
-
"lz-string.min",
|
61 |
"featherlight",
|
62 |
-
"jquery.fileDownload"
|
|
|
63 |
]
|
64 |
},
|
65 |
"frontend": {
|
@@ -68,58 +68,69 @@
|
|
68 |
},
|
69 |
"register": {
|
70 |
"css": {
|
71 |
-
"
|
72 |
"url": "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.0/css/bootstrap.min.css"
|
73 |
},
|
74 |
-
"
|
|
|
75 |
"deps": [
|
76 |
-
"
|
77 |
]
|
78 |
},
|
79 |
"bootstrap-datepicker": {
|
80 |
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.8.0/css/bootstrap-datepicker.min.css",
|
81 |
"deps": [
|
82 |
-
"
|
83 |
]
|
84 |
},
|
85 |
"global-plugin": {},
|
86 |
"plugin": {
|
87 |
"deps": [
|
88 |
-
"
|
89 |
"global-plugin"
|
90 |
]
|
91 |
},
|
92 |
"wizard": {
|
93 |
"deps": [
|
94 |
-
"
|
95 |
"global-plugin"
|
96 |
]
|
97 |
},
|
98 |
"featherlight": {},
|
99 |
-
"chartist
|
|
|
|
|
100 |
"chartist-plugin-legend": {
|
101 |
"deps": [
|
102 |
-
"chartist
|
103 |
]
|
104 |
},
|
105 |
-
"introjs
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
106 |
},
|
107 |
"js": {
|
108 |
-
"
|
109 |
"url": "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.0/js/bootstrap.bundle.min.js",
|
110 |
"deps": [
|
111 |
"wp-jquery"
|
112 |
]
|
113 |
},
|
114 |
-
"
|
|
|
115 |
"deps": [
|
116 |
-
"
|
117 |
]
|
118 |
},
|
119 |
"bootstrap-datepicker": {
|
120 |
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.8.0/js/bootstrap-datepicker.min.js",
|
121 |
"deps": [
|
122 |
-
"
|
123 |
]
|
124 |
},
|
125 |
"global-plugin": {
|
@@ -129,42 +140,77 @@
|
|
129 |
},
|
130 |
"plugin": {
|
131 |
"deps": [
|
132 |
-
"
|
133 |
-
"global-plugin"
|
|
|
|
|
134 |
]
|
135 |
},
|
136 |
-
"base64.min": {
|
|
|
|
|
137 |
"lz-string.min": {},
|
138 |
-
"jquery.fileDownload": {
|
139 |
-
|
|
|
|
|
|
|
140 |
"featherlight": {
|
141 |
"deps": [
|
142 |
"wp-jquery"
|
143 |
]
|
144 |
},
|
145 |
-
"chartist
|
|
|
|
|
146 |
"chartist-plugin-legend": {
|
147 |
"deps": [
|
148 |
-
"chartist
|
149 |
]
|
150 |
},
|
151 |
-
"
|
|
|
|
|
|
|
152 |
"deps": [
|
153 |
-
"chartist
|
|
|
|
|
154 |
]
|
155 |
},
|
156 |
-
"shuffle": {
|
157 |
-
|
|
|
|
|
158 |
"deps": [
|
159 |
"shuffle"
|
160 |
]
|
161 |
},
|
162 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
163 |
"shield/tables": {
|
164 |
"deps": [
|
165 |
"plugin"
|
166 |
]
|
167 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
168 |
"shield/scans": {
|
169 |
"deps": [
|
170 |
"shield/tables"
|
@@ -182,7 +228,7 @@
|
|
182 |
},
|
183 |
"shield/mainwp-extension": {
|
184 |
"deps": [
|
185 |
-
"jquery"
|
186 |
]
|
187 |
},
|
188 |
"shield/userprofile": {
|
@@ -196,6 +242,20 @@
|
|
196 |
"u2f-bundle",
|
197 |
"wp-jquery"
|
198 |
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
199 |
}
|
200 |
}
|
201 |
}
|
1 |
{
|
2 |
"properties": {
|
3 |
+
"version": "11.0.0",
|
4 |
+
"release_timestamp": 1616666000,
|
5 |
+
"build": "202103.2501",
|
6 |
"slug_parent": "icwp",
|
7 |
"slug_plugin": "wpsf",
|
8 |
"human_name": "Shield Security",
|
49 |
},
|
50 |
"plugin_admin": {
|
51 |
"css": [
|
52 |
+
"select2",
|
53 |
"plugin",
|
54 |
+
"featherlight",
|
55 |
+
"introjs"
|
56 |
],
|
57 |
"js": [
|
58 |
+
"select2",
|
59 |
"plugin",
|
|
|
|
|
60 |
"featherlight",
|
61 |
+
"jquery.fileDownload",
|
62 |
+
"shield/tours"
|
63 |
]
|
64 |
},
|
65 |
"frontend": {
|
68 |
},
|
69 |
"register": {
|
70 |
"css": {
|
71 |
+
"bootstrap": {
|
72 |
"url": "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.0/css/bootstrap.min.css"
|
73 |
},
|
74 |
+
"select2": {
|
75 |
+
"url": "https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/css/select2.min.css",
|
76 |
"deps": [
|
77 |
+
"plugin"
|
78 |
]
|
79 |
},
|
80 |
"bootstrap-datepicker": {
|
81 |
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.8.0/css/bootstrap-datepicker.min.css",
|
82 |
"deps": [
|
83 |
+
"bootstrap"
|
84 |
]
|
85 |
},
|
86 |
"global-plugin": {},
|
87 |
"plugin": {
|
88 |
"deps": [
|
89 |
+
"bootstrap",
|
90 |
"global-plugin"
|
91 |
]
|
92 |
},
|
93 |
"wizard": {
|
94 |
"deps": [
|
95 |
+
"bootstrap",
|
96 |
"global-plugin"
|
97 |
]
|
98 |
},
|
99 |
"featherlight": {},
|
100 |
+
"chartist": {
|
101 |
+
"url": "https://cdnjs.cloudflare.com/ajax/libs/chartist/0.11.4/chartist.min.css"
|
102 |
+
},
|
103 |
"chartist-plugin-legend": {
|
104 |
"deps": [
|
105 |
+
"chartist"
|
106 |
]
|
107 |
},
|
108 |
+
"introjs": {
|
109 |
+
"url": "https://cdnjs.cloudflare.com/ajax/libs/intro.js/3.3.1/introjs.min.css"
|
110 |
+
},
|
111 |
+
"shield/charts": {
|
112 |
+
"deps": [
|
113 |
+
"plugin"
|
114 |
+
]
|
115 |
+
}
|
116 |
},
|
117 |
"js": {
|
118 |
+
"bootstrap": {
|
119 |
"url": "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.0/js/bootstrap.bundle.min.js",
|
120 |
"deps": [
|
121 |
"wp-jquery"
|
122 |
]
|
123 |
},
|
124 |
+
"select2": {
|
125 |
+
"url": "https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/js/select2.min.js",
|
126 |
"deps": [
|
127 |
+
"plugin"
|
128 |
]
|
129 |
},
|
130 |
"bootstrap-datepicker": {
|
131 |
"url": "https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.8.0/js/bootstrap-datepicker.min.js",
|
132 |
"deps": [
|
133 |
+
"bootstrap"
|
134 |
]
|
135 |
},
|
136 |
"global-plugin": {
|
140 |
},
|
141 |
"plugin": {
|
142 |
"deps": [
|
143 |
+
"bootstrap",
|
144 |
+
"global-plugin",
|
145 |
+
"base64.min",
|
146 |
+
"lz-string.min"
|
147 |
]
|
148 |
},
|
149 |
+
"base64.min": {
|
150 |
+
"url": "https://cdn.jsdelivr.net/npm/js-base64@2.6.4/base64.min.js"
|
151 |
+
},
|
152 |
"lz-string.min": {},
|
153 |
+
"jquery.fileDownload": {
|
154 |
+
"deps": [
|
155 |
+
"wp-jquery"
|
156 |
+
]
|
157 |
+
},
|
158 |
"featherlight": {
|
159 |
"deps": [
|
160 |
"wp-jquery"
|
161 |
]
|
162 |
},
|
163 |
+
"chartist": {
|
164 |
+
"url": "https://cdnjs.cloudflare.com/ajax/libs/chartist/0.11.4/chartist.min.js"
|
165 |
+
},
|
166 |
"chartist-plugin-legend": {
|
167 |
"deps": [
|
168 |
+
"chartist"
|
169 |
]
|
170 |
},
|
171 |
+
"introjs": {
|
172 |
+
"url": "https://cdnjs.cloudflare.com/ajax/libs/intro.js/3.3.1/intro.min.js"
|
173 |
+
},
|
174 |
+
"shield/charts": {
|
175 |
"deps": [
|
176 |
+
"chartist",
|
177 |
+
"chartist-plugin-legend",
|
178 |
+
"plugin"
|
179 |
]
|
180 |
},
|
181 |
+
"shuffle": {
|
182 |
+
"url": "https://cdnjs.cloudflare.com/ajax/libs/Shuffle/5.3.0/shuffle.min.js"
|
183 |
+
},
|
184 |
+
"shield/shuffle": {
|
185 |
"deps": [
|
186 |
"shuffle"
|
187 |
]
|
188 |
},
|
189 |
+
"shield/comments": {
|
190 |
+
"deps": [
|
191 |
+
"wp-jquery"
|
192 |
+
],
|
193 |
+
"footer": true
|
194 |
+
},
|
195 |
+
"shield/loginbot": {
|
196 |
+
"deps": [
|
197 |
+
"wp-jquery"
|
198 |
+
]
|
199 |
+
},
|
200 |
"shield/tables": {
|
201 |
"deps": [
|
202 |
"plugin"
|
203 |
]
|
204 |
},
|
205 |
+
"shield/tours": {
|
206 |
+
"deps": [
|
207 |
+
"plugin",
|
208 |
+
"introjs"
|
209 |
+
]
|
210 |
+
},
|
211 |
+
"shield/antibot": {
|
212 |
+
"footer": true
|
213 |
+
},
|
214 |
"shield/scans": {
|
215 |
"deps": [
|
216 |
"shield/tables"
|
228 |
},
|
229 |
"shield/mainwp-extension": {
|
230 |
"deps": [
|
231 |
+
"wp-jquery"
|
232 |
]
|
233 |
},
|
234 |
"shield/userprofile": {
|
242 |
"u2f-bundle",
|
243 |
"wp-jquery"
|
244 |
]
|
245 |
+
},
|
246 |
+
"tp/grecaptcha": {
|
247 |
+
"url": "https://www.google.com/recaptcha/api.js",
|
248 |
+
"attributes": {
|
249 |
+
"async": "async",
|
250 |
+
"defer": "defer"
|
251 |
+
}
|
252 |
+
},
|
253 |
+
"tp/hcaptcha": {
|
254 |
+
"url": "https://hcaptcha.com/1/api.js",
|
255 |
+
"attributes": {
|
256 |
+
"async": "async",
|
257 |
+
"defer": "defer"
|
258 |
+
}
|
259 |
}
|
260 |
}
|
261 |
}
|
readme.txt
CHANGED
@@ -3,24 +3,23 @@ Contributors: paultgoodchild, getshieldsecurity
|
|
3 |
Donate link: https://shsec.io/bw
|
4 |
License: GPLv3
|
5 |
License URI: http://www.gnu.org/licenses/gpl.html
|
6 |
-
Tags: scan, malware, firewall, two factor authentication, login protection
|
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:
|
12 |
-
|
13 |
Security against hackers and brute force bots with firewall, login security hiding and hardening, Antispam, Audit Trail, Live Traffic, and much more...
|
14 |
|
15 |
== Description ==
|
16 |
|
17 |
-
|
18 |
|
19 |
#### Get the highest rated 5* Security Plugin for WordPress
|
20 |
|
21 |
Per download, Shield Security [has the highest 5* rating](https://shsec.io/jl) in the WordPress plugin repository.
|
22 |
|
23 |
-
## Your Security
|
24 |
|
25 |
To be free from hackers, your WordPress Security need to be smarter, adaptive and uncomplicated.
|
26 |
|
@@ -35,9 +34,13 @@ Shield Security uses 2 simple key strategies to protect your WordPress sites:
|
|
35 |
|
36 |
#### Key Security Strategy #1: Hacking Prevention
|
37 |
|
38 |
-
|
|
|
|
|
|
|
|
|
39 |
|
40 |
-
|
41 |
|
42 |
These signals include:
|
43 |
|
@@ -46,9 +49,11 @@ These signals include:
|
|
46 |
* logins with invalid usernames
|
47 |
* xml-rpc access
|
48 |
* fake search engine web crawlers
|
|
|
|
|
49 |
* and many more signals our security team have identified...
|
50 |
|
51 |
-
Early identification and blocking of malicious bots reduces your WordPress site's
|
52 |
|
53 |
#### Key Strategy #2: Hacking Cure
|
54 |
|
@@ -85,14 +90,15 @@ Shield Security handles many problems for you, making intelligent security decis
|
|
85 |
|
86 |
#### WordPress Security Features You'll Absolutely Love
|
87 |
|
88 |
-
* [
|
|
|
89 |
* Add Security To Important Forms To Block Bots:
|
90 |
* Login
|
91 |
* Registration
|
92 |
* Password Reset
|
93 |
* [ShieldPRO] WooCommerce & Easy Digital Downloads
|
94 |
* [ShieldPRO] Memberpress, LearnPress, BuddyPress, WP Members, ProfileBuilder
|
95 |
-
* [Limit Login Attempts + Login Cooldown System](https://shsec.io/iw)
|
96 |
* Powerful Firewall Security Rules
|
97 |
* Restricted Security Admin Access
|
98 |
* [Prevents Unauthorized Changes To Site Even By Admins](https://shsec.io/ix).
|
@@ -111,7 +117,7 @@ Shield Security handles many problems for you, making intelligent security decis
|
|
111 |
* Block or Bypass individual IPs
|
112 |
* Block or Bypass IP Subnets
|
113 |
* Full IP Analysis in 1 place to see their activity on your sites
|
114 |
-
*
|
115 |
* Detect File Changes - [Scan & Repair WordPress Core Files](https://shsec.io/j1)
|
116 |
* [Detect Unknown/Suspicious PHP Files](https://shsec.io/j2)
|
117 |
* Detect Abandoned Plugins.
|
3 |
Donate link: https://shsec.io/bw
|
4 |
License: GPLv3
|
5 |
License URI: http://www.gnu.org/licenses/gpl.html
|
6 |
+
Tags: scan, malware, firewall, two factor authentication, login protection
|
7 |
Requires at least: 3.5.2
|
8 |
Requires PHP: 7.0
|
9 |
Recommended PHP: 7.4
|
10 |
Tested up to: 5.7
|
11 |
+
Stable tag: 11.0.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 ==
|
15 |
|
16 |
+
Add expert security to all your WordPress sites with Shield Security, without being a security expert.
|
17 |
|
18 |
#### Get the highest rated 5* Security Plugin for WordPress
|
19 |
|
20 |
Per download, Shield Security [has the highest 5* rating](https://shsec.io/jl) in the WordPress plugin repository.
|
21 |
|
22 |
+
## Your Goal: Security Is Peace Of Mind and Freedom From Hackers
|
23 |
|
24 |
To be free from hackers, your WordPress Security need to be smarter, adaptive and uncomplicated.
|
25 |
|
34 |
|
35 |
#### Key Security Strategy #1: Hacking Prevention
|
36 |
|
37 |
+
Bots cause nearly all our security troubles - they're relentless, automatic and powerful.
|
38 |
+
|
39 |
+
Shield Security is the only plugin dedicated to their detection and erradication from your WordPress site.
|
40 |
+
|
41 |
+
Blocking malicious bots before they can do damage is the key strategy to protect and enhance security on a WordPress site.
|
42 |
|
43 |
+
Shield uses its features to detect these malicious visitors, then block access to your site altogether. This involves analysing different bot-signals and combining them to confidently identify a visitor as malicious.
|
44 |
|
45 |
These signals include:
|
46 |
|
49 |
* logins with invalid usernames
|
50 |
* xml-rpc access
|
51 |
* fake search engine web crawlers
|
52 |
+
* invalid user agents
|
53 |
+
* excessive website requests and resource abuse
|
54 |
* and many more signals our security team have identified...
|
55 |
|
56 |
+
Early identification and blocking of malicious bots reduces your WordPress site's vulnerability to attack.
|
57 |
|
58 |
#### Key Strategy #2: Hacking Cure
|
59 |
|
90 |
|
91 |
#### WordPress Security Features You'll Absolutely Love
|
92 |
|
93 |
+
* Exclusive [AntiBot Detection Engine](https://shsec.io/ju) - The most powerful Bot Detection system on any WordPress plugin.
|
94 |
+
* [Automatic Bot & IP Blocking](https://shsec.io/j0) - points-based security system to block bad bots.
|
95 |
* Add Security To Important Forms To Block Bots:
|
96 |
* Login
|
97 |
* Registration
|
98 |
* Password Reset
|
99 |
* [ShieldPRO] WooCommerce & Easy Digital Downloads
|
100 |
* [ShieldPRO] Memberpress, LearnPress, BuddyPress, WP Members, ProfileBuilder
|
101 |
+
* [Brute Force Protection, Limit Login Attempts + Login Cooldown System](https://shsec.io/iw)
|
102 |
* Powerful Firewall Security Rules
|
103 |
* Restricted Security Admin Access
|
104 |
* [Prevents Unauthorized Changes To Site Even By Admins](https://shsec.io/ix).
|
117 |
* Block or Bypass individual IPs
|
118 |
* Block or Bypass IP Subnets
|
119 |
* Full IP Analysis in 1 place to see their activity on your sites
|
120 |
+
* Comprehensive WordPress File Scanner for Intrusions and Hacks
|
121 |
* Detect File Changes - [Scan & Repair WordPress Core Files](https://shsec.io/j1)
|
122 |
* [Detect Unknown/Suspicious PHP Files](https://shsec.io/j2)
|
123 |
* Detect Abandoned Plugins.
|
resources/css/bootstrap-select.min.css
DELETED
@@ -1,6 +0,0 @@
|
|
1 |
-
/*!
|
2 |
-
* Bootstrap-select v1.13.18 (https://developer.snapappointments.com/bootstrap-select)
|
3 |
-
*
|
4 |
-
* Copyright 2012-2020 SnapAppointments, LLC
|
5 |
-
* Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE)
|
6 |
-
*/@-webkit-keyframes bs-notify-fadeOut{0%{opacity:.9}100%{opacity:0}}@-o-keyframes bs-notify-fadeOut{0%{opacity:.9}100%{opacity:0}}@keyframes bs-notify-fadeOut{0%{opacity:.9}100%{opacity:0}}.bootstrap-select>select.bs-select-hidden,select.bs-select-hidden,select.selectpicker{display:none!important}.bootstrap-select{width:220px\0;vertical-align:middle}.bootstrap-select>.dropdown-toggle{position:relative;width:100%;text-align:right;white-space:nowrap;display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between}.bootstrap-select>.dropdown-toggle:after{margin-top:-1px}.bootstrap-select>.dropdown-toggle.bs-placeholder,.bootstrap-select>.dropdown-toggle.bs-placeholder:active,.bootstrap-select>.dropdown-toggle.bs-placeholder:focus,.bootstrap-select>.dropdown-toggle.bs-placeholder:hover{color:#999}.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-danger,.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-danger:active,.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-danger:focus,.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-danger:hover,.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-dark,.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-dark:active,.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-dark:focus,.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-dark:hover,.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-info,.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-info:active,.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-info:focus,.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-info:hover,.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-primary,.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-primary:active,.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-primary:focus,.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-primary:hover,.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-secondary,.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-secondary:active,.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-secondary:focus,.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-secondary:hover,.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-success,.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-success:active,.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-success:focus,.bootstrap-select>.dropdown-toggle.bs-placeholder.btn-success:hover{color:rgba(255,255,255,.5)}.bootstrap-select>select{position:absolute!important;bottom:0;left:50%;display:block!important;width:.5px!important;height:100%!important;padding:0!important;opacity:0!important;border:none;z-index:0!important}.bootstrap-select>select.mobile-device{top:0;left:0;display:block!important;width:100%!important;z-index:2!important}.bootstrap-select.is-invalid .dropdown-toggle,.error .bootstrap-select .dropdown-toggle,.has-error .bootstrap-select .dropdown-toggle,.was-validated .bootstrap-select select:invalid+.dropdown-toggle{border-color:#b94a48}.bootstrap-select.is-valid .dropdown-toggle,.was-validated .bootstrap-select select:valid+.dropdown-toggle{border-color:#28a745}.bootstrap-select.fit-width{width:auto!important}.bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn){width:220px}.bootstrap-select .dropdown-toggle:focus,.bootstrap-select>select.mobile-device:focus+.dropdown-toggle{outline:thin dotted #333!important;outline:5px auto -webkit-focus-ring-color!important;outline-offset:-2px}.bootstrap-select.form-control{margin-bottom:0;padding:0;border:none;height:auto}:not(.input-group)>.bootstrap-select.form-control:not([class*=col-]){width:100%}.bootstrap-select.form-control.input-group-btn{float:none;z-index:auto}.form-inline .bootstrap-select,.form-inline .bootstrap-select.form-control:not([class*=col-]){width:auto}.bootstrap-select:not(.input-group-btn),.bootstrap-select[class*=col-]{float:none;display:inline-block;margin-left:0}.bootstrap-select.dropdown-menu-right,.bootstrap-select[class*=col-].dropdown-menu-right,.row .bootstrap-select[class*=col-].dropdown-menu-right{float:right}.form-group .bootstrap-select,.form-horizontal .bootstrap-select,.form-inline .bootstrap-select{margin-bottom:0}.form-group-lg .bootstrap-select.form-control,.form-group-sm .bootstrap-select.form-control{padding:0}.form-group-lg .bootstrap-select.form-control .dropdown-toggle,.form-group-sm .bootstrap-select.form-control .dropdown-toggle{height:100%;font-size:inherit;line-height:inherit;border-radius:inherit}.bootstrap-select.form-control-lg .dropdown-toggle,.bootstrap-select.form-control-sm .dropdown-toggle{font-size:inherit;line-height:inherit;border-radius:inherit}.bootstrap-select.form-control-sm .dropdown-toggle{padding:.25rem .5rem}.bootstrap-select.form-control-lg .dropdown-toggle{padding:.5rem 1rem}.form-inline .bootstrap-select .form-control{width:100%}.bootstrap-select.disabled,.bootstrap-select>.disabled{cursor:not-allowed}.bootstrap-select.disabled:focus,.bootstrap-select>.disabled:focus{outline:0!important}.bootstrap-select.bs-container{position:absolute;top:0;left:0;height:0!important;padding:0!important}.bootstrap-select.bs-container .dropdown-menu{z-index:1060}.bootstrap-select .dropdown-toggle .filter-option{position:static;top:0;left:0;float:left;height:100%;width:100%;text-align:left;overflow:hidden;-webkit-box-flex:0;-webkit-flex:0 1 auto;-ms-flex:0 1 auto;flex:0 1 auto}.bs3.bootstrap-select .dropdown-toggle .filter-option{padding-right:inherit}.input-group .bs3-has-addon.bootstrap-select .dropdown-toggle .filter-option{position:absolute;padding-top:inherit;padding-bottom:inherit;padding-left:inherit;float:none}.input-group .bs3-has-addon.bootstrap-select .dropdown-toggle .filter-option .filter-option-inner{padding-right:inherit}.bootstrap-select .dropdown-toggle .filter-option-inner-inner{overflow:hidden}.bootstrap-select .dropdown-toggle .filter-expand{width:0!important;float:left;opacity:0!important;overflow:hidden}.bootstrap-select .dropdown-toggle .caret{position:absolute;top:50%;right:12px;margin-top:-2px;vertical-align:middle}.input-group .bootstrap-select.form-control .dropdown-toggle{border-radius:inherit}.bootstrap-select[class*=col-] .dropdown-toggle{width:100%}.bootstrap-select .dropdown-menu{min-width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.bootstrap-select .dropdown-menu>.inner:focus{outline:0!important}.bootstrap-select .dropdown-menu.inner{position:static;float:none;border:0;padding:0;margin:0;border-radius:0;-webkit-box-shadow:none;box-shadow:none}.bootstrap-select .dropdown-menu li{position:relative}.bootstrap-select .dropdown-menu li.active small{color:rgba(255,255,255,.5)!important}.bootstrap-select .dropdown-menu li.disabled a{cursor:not-allowed}.bootstrap-select .dropdown-menu li a{cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.bootstrap-select .dropdown-menu li a.opt{position:relative;padding-left:2.25em}.bootstrap-select .dropdown-menu li a span.check-mark{display:none}.bootstrap-select .dropdown-menu li a span.text{display:inline-block}.bootstrap-select .dropdown-menu li small{padding-left:.5em}.bootstrap-select .dropdown-menu .notify{position:absolute;bottom:5px;width:96%;margin:0 2%;min-height:26px;padding:3px 5px;background:#f5f5f5;border:1px solid #e3e3e3;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05);pointer-events:none;opacity:.9;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.bootstrap-select .dropdown-menu .notify.fadeOut{-webkit-animation:.3s linear 750ms forwards bs-notify-fadeOut;-o-animation:.3s linear 750ms forwards bs-notify-fadeOut;animation:.3s linear 750ms forwards bs-notify-fadeOut}.bootstrap-select .no-results{padding:3px;background:#f5f5f5;margin:0 5px;white-space:nowrap}.bootstrap-select.fit-width .dropdown-toggle .filter-option{position:static;display:inline;padding:0}.bootstrap-select.fit-width .dropdown-toggle .filter-option-inner,.bootstrap-select.fit-width .dropdown-toggle .filter-option-inner-inner{display:inline}.bootstrap-select.fit-width .dropdown-toggle .bs-caret:before{content:'\00a0'}.bootstrap-select.fit-width .dropdown-toggle .caret{position:static;top:auto;margin-top:-1px}.bootstrap-select.show-tick .dropdown-menu .selected span.check-mark{position:absolute;display:inline-block;right:15px;top:5px}.bootstrap-select.show-tick .dropdown-menu li a span.text{margin-right:34px}.bootstrap-select .bs-ok-default:after{content:'';display:block;width:.5em;height:1em;border-style:solid;border-width:0 .26em .26em 0;-webkit-transform-style:preserve-3d;transform-style:preserve-3d;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg)}.bootstrap-select.show-menu-arrow.open>.dropdown-toggle,.bootstrap-select.show-menu-arrow.show>.dropdown-toggle{z-index:1061}.bootstrap-select.show-menu-arrow .dropdown-toggle .filter-option:before{content:'';border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid rgba(204,204,204,.2);position:absolute;bottom:-4px;left:9px;display:none}.bootstrap-select.show-menu-arrow .dropdown-toggle .filter-option:after{content:'';border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff;position:absolute;bottom:-4px;left:10px;display:none}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle .filter-option:before{bottom:auto;top:-4px;border-top:7px solid rgba(204,204,204,.2);border-bottom:0}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle .filter-option:after{bottom:auto;top:-4px;border-top:6px solid #fff;border-bottom:0}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle .filter-option:before{right:12px;left:auto}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle .filter-option:after{right:13px;left:auto}.bootstrap-select.show-menu-arrow.open>.dropdown-toggle .filter-option:after,.bootstrap-select.show-menu-arrow.open>.dropdown-toggle .filter-option:before,.bootstrap-select.show-menu-arrow.show>.dropdown-toggle .filter-option:after,.bootstrap-select.show-menu-arrow.show>.dropdown-toggle .filter-option:before{display:block}.bs-actionsbox,.bs-donebutton,.bs-searchbox{padding:4px 8px}.bs-actionsbox{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.bs-actionsbox .btn-group button{width:50%}.bs-donebutton{float:left;width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.bs-donebutton .btn-group button{width:100%}.bs-searchbox+.bs-actionsbox{padding:0 8px 4px}.bs-searchbox .form-control{margin-bottom:0;width:100%;float:none}
|
|
|
|
|
|
|
|
|
|
|
|
resources/css/chartist.min.css
DELETED
@@ -1 +0,0 @@
|
|
1 |
-
.ct-double-octave:after,.ct-golden-section:after,.ct-major-eleventh:after,.ct-major-second:after,.ct-major-seventh:after,.ct-major-sixth:after,.ct-major-tenth:after,.ct-major-third:after,.ct-major-twelfth:after,.ct-minor-second:after,.ct-minor-seventh:after,.ct-minor-sixth:after,.ct-minor-third:after,.ct-octave:after,.ct-perfect-fifth:after,.ct-perfect-fourth:after,.ct-square:after{content:"";clear:both}.ct-label{fill:rgba(0,0,0,.4);color:rgba(0,0,0,.4);font-size:.75rem;line-height:1}.ct-chart-bar .ct-label,.ct-chart-line .ct-label{display:block;display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex}.ct-chart-donut .ct-label,.ct-chart-pie .ct-label{dominant-baseline:central}.ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-label.ct-vertical.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-end;-webkit-justify-content:flex-end;-ms-flex-pack:flex-end;justify-content:flex-end;text-align:right;text-anchor:end}.ct-label.ct-vertical.ct-end{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar .ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;text-align:center;text-anchor:start}.ct-chart-bar .ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;text-align:center;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-start{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:flex-end;-webkit-justify-content:flex-end;-ms-flex-pack:flex-end;justify-content:flex-end;text-align:right;text-anchor:end}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-end{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:end}.ct-grid{stroke:rgba(0,0,0,.2);stroke-width:1px;stroke-dasharray:2px}.ct-grid-background{fill:none}.ct-point{stroke-width:10px;stroke-linecap:round}.ct-line{fill:none;stroke-width:4px}.ct-area{stroke:none;fill-opacity:.1}.ct-bar{fill:none;stroke-width:10px}.ct-slice-donut{fill:none;stroke-width:60px}.ct-series-a .ct-bar,.ct-series-a .ct-line,.ct-series-a .ct-point,.ct-series-a .ct-slice-donut{stroke:#d70206}.ct-series-a .ct-area,.ct-series-a .ct-slice-donut-solid,.ct-series-a .ct-slice-pie{fill:#d70206}.ct-series-b .ct-bar,.ct-series-b .ct-line,.ct-series-b .ct-point,.ct-series-b .ct-slice-donut{stroke:#f05b4f}.ct-series-b .ct-area,.ct-series-b .ct-slice-donut-solid,.ct-series-b .ct-slice-pie{fill:#f05b4f}.ct-series-c .ct-bar,.ct-series-c .ct-line,.ct-series-c .ct-point,.ct-series-c .ct-slice-donut{stroke:#f4c63d}.ct-series-c .ct-area,.ct-series-c .ct-slice-donut-solid,.ct-series-c .ct-slice-pie{fill:#f4c63d}.ct-series-d .ct-bar,.ct-series-d .ct-line,.ct-series-d .ct-point,.ct-series-d .ct-slice-donut{stroke:#d17905}.ct-series-d .ct-area,.ct-series-d .ct-slice-donut-solid,.ct-series-d .ct-slice-pie{fill:#d17905}.ct-series-e .ct-bar,.ct-series-e .ct-line,.ct-series-e .ct-point,.ct-series-e .ct-slice-donut{stroke:#453d3f}.ct-series-e .ct-area,.ct-series-e .ct-slice-donut-solid,.ct-series-e .ct-slice-pie{fill:#453d3f}.ct-series-f .ct-bar,.ct-series-f .ct-line,.ct-series-f .ct-point,.ct-series-f .ct-slice-donut{stroke:#59922b}.ct-series-f .ct-area,.ct-series-f .ct-slice-donut-solid,.ct-series-f .ct-slice-pie{fill:#59922b}.ct-series-g .ct-bar,.ct-series-g .ct-line,.ct-series-g .ct-point,.ct-series-g .ct-slice-donut{stroke:#0544d3}.ct-series-g .ct-area,.ct-series-g .ct-slice-donut-solid,.ct-series-g .ct-slice-pie{fill:#0544d3}.ct-series-h .ct-bar,.ct-series-h .ct-line,.ct-series-h .ct-point,.ct-series-h .ct-slice-donut{stroke:#6b0392}.ct-series-h .ct-area,.ct-series-h .ct-slice-donut-solid,.ct-series-h .ct-slice-pie{fill:#6b0392}.ct-series-i .ct-bar,.ct-series-i .ct-line,.ct-series-i .ct-point,.ct-series-i .ct-slice-donut{stroke:#f05b4f}.ct-series-i .ct-area,.ct-series-i .ct-slice-donut-solid,.ct-series-i .ct-slice-pie{fill:#f05b4f}.ct-series-j .ct-bar,.ct-series-j .ct-line,.ct-series-j .ct-point,.ct-series-j .ct-slice-donut{stroke:#dda458}.ct-series-j .ct-area,.ct-series-j .ct-slice-donut-solid,.ct-series-j .ct-slice-pie{fill:#dda458}.ct-series-k .ct-bar,.ct-series-k .ct-line,.ct-series-k .ct-point,.ct-series-k .ct-slice-donut{stroke:#eacf7d}.ct-series-k .ct-area,.ct-series-k .ct-slice-donut-solid,.ct-series-k .ct-slice-pie{fill:#eacf7d}.ct-series-l .ct-bar,.ct-series-l .ct-line,.ct-series-l .ct-point,.ct-series-l .ct-slice-donut{stroke:#86797d}.ct-series-l .ct-area,.ct-series-l .ct-slice-donut-solid,.ct-series-l .ct-slice-pie{fill:#86797d}.ct-series-m .ct-bar,.ct-series-m .ct-line,.ct-series-m .ct-point,.ct-series-m .ct-slice-donut{stroke:#b2c326}.ct-series-m .ct-area,.ct-series-m .ct-slice-donut-solid,.ct-series-m .ct-slice-pie{fill:#b2c326}.ct-series-n .ct-bar,.ct-series-n .ct-line,.ct-series-n .ct-point,.ct-series-n .ct-slice-donut{stroke:#6188e2}.ct-series-n .ct-area,.ct-series-n .ct-slice-donut-solid,.ct-series-n .ct-slice-pie{fill:#6188e2}.ct-series-o .ct-bar,.ct-series-o .ct-line,.ct-series-o .ct-point,.ct-series-o .ct-slice-donut{stroke:#a748ca}.ct-series-o .ct-area,.ct-series-o .ct-slice-donut-solid,.ct-series-o .ct-slice-pie{fill:#a748ca}.ct-square{display:block;position:relative;width:100%}.ct-square:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:100%}.ct-square:after{display:table}.ct-square>svg{display:block;position:absolute;top:0;left:0}.ct-minor-second{display:block;position:relative;width:100%}.ct-minor-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:93.75%}.ct-minor-second:after{display:table}.ct-minor-second>svg{display:block;position:absolute;top:0;left:0}.ct-major-second{display:block;position:relative;width:100%}.ct-major-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:88.8888888889%}.ct-major-second:after{display:table}.ct-major-second>svg{display:block;position:absolute;top:0;left:0}.ct-minor-third{display:block;position:relative;width:100%}.ct-minor-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:83.3333333333%}.ct-minor-third:after{display:table}.ct-minor-third>svg{display:block;position:absolute;top:0;left:0}.ct-major-third{display:block;position:relative;width:100%}.ct-major-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:80%}.ct-major-third:after{display:table}.ct-major-third>svg{display:block;position:absolute;top:0;left:0}.ct-perfect-fourth{display:block;position:relative;width:100%}.ct-perfect-fourth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:75%}.ct-perfect-fourth:after{display:table}.ct-perfect-fourth>svg{display:block;position:absolute;top:0;left:0}.ct-perfect-fifth{display:block;position:relative;width:100%}.ct-perfect-fifth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:66.6666666667%}.ct-perfect-fifth:after{display:table}.ct-perfect-fifth>svg{display:block;position:absolute;top:0;left:0}.ct-minor-sixth{display:block;position:relative;width:100%}.ct-minor-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:62.5%}.ct-minor-sixth:after{display:table}.ct-minor-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-golden-section{display:block;position:relative;width:100%}.ct-golden-section:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:61.804697157%}.ct-golden-section:after{display:table}.ct-golden-section>svg{display:block;position:absolute;top:0;left:0}.ct-major-sixth{display:block;position:relative;width:100%}.ct-major-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:60%}.ct-major-sixth:after{display:table}.ct-major-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-minor-seventh{display:block;position:relative;width:100%}.ct-minor-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:56.25%}.ct-minor-seventh:after{display:table}.ct-minor-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-major-seventh{display:block;position:relative;width:100%}.ct-major-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:53.3333333333%}.ct-major-seventh:after{display:table}.ct-major-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-octave{display:block;position:relative;width:100%}.ct-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:50%}.ct-octave:after{display:table}.ct-octave>svg{display:block;position:absolute;top:0;left:0}.ct-major-tenth{display:block;position:relative;width:100%}.ct-major-tenth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:40%}.ct-major-tenth:after{display:table}.ct-major-tenth>svg{display:block;position:absolute;top:0;left:0}.ct-major-eleventh{display:block;position:relative;width:100%}.ct-major-eleventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:37.5%}.ct-major-eleventh:after{display:table}.ct-major-eleventh>svg{display:block;position:absolute;top:0;left:0}.ct-major-twelfth{display:block;position:relative;width:100%}.ct-major-twelfth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:33.3333333333%}.ct-major-twelfth:after{display:table}.ct-major-twelfth>svg{display:block;position:absolute;top:0;left:0}.ct-double-octave{display:block;position:relative;width:100%}.ct-double-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:25%}.ct-double-octave:after{display:table}.ct-double-octave>svg{display:block;position:absolute;top:0;left:0}
|
|
resources/css/introjs.min.css
DELETED
@@ -1 +0,0 @@
|
|
1 |
-
.introjs-overlay{position:absolute;box-sizing:content-box;z-index:999999;background-color:#000;opacity:0;background:-moz-radial-gradient(center,ellipse farthest-corner,rgba(0,0,0,.4) 0,rgba(0,0,0,.9) 100%);background:-webkit-gradient(radial,center center,0,center center,100%,color-stop(0,rgba(0,0,0,.4)),color-stop(100%,rgba(0,0,0,.9)));background:-webkit-radial-gradient(center,ellipse farthest-corner,rgba(0,0,0,.4) 0,rgba(0,0,0,.9) 100%);background:-o-radial-gradient(center,ellipse farthest-corner,rgba(0,0,0,.4) 0,rgba(0,0,0,.9) 100%);background:-ms-radial-gradient(center,ellipse farthest-corner,rgba(0,0,0,.4) 0,rgba(0,0,0,.9) 100%);background:radial-gradient(center,ellipse farthest-corner,rgba(0,0,0,.4) 0,rgba(0,0,0,.9) 100%);-webkit-transition:all .3s ease-out;-moz-transition:all .3s ease-out;-ms-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out}.introjs-fixParent{z-index:auto!important;opacity:1!important;-webkit-transform:none!important;-moz-transform:none!important;-ms-transform:none!important;-o-transform:none!important;transform:none!important}.introjs-showElement,tr.introjs-showElement>td,tr.introjs-showElement>th{z-index:9999999!important}.introjs-disableInteraction{z-index:99999999!important;position:absolute;background-color:#fff;opacity:0}.introjs-relativePosition,tr.introjs-showElement>td,tr.introjs-showElement>th{position:relative}.introjs-helperLayer{box-sizing:content-box;position:absolute;z-index:9999998;background-color:#fff;background-color:rgba(255,255,255,.9);border:1px solid #777;border:1px solid rgba(0,0,0,.5);border-radius:4px;box-shadow:0 2px 15px rgba(0,0,0,.4);-webkit-transition:all .3s ease-out;-moz-transition:all .3s ease-out;-ms-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out}.introjs-tooltipReferenceLayer{box-sizing:content-box;position:absolute;visibility:hidden;z-index:100000000;background-color:transparent;-webkit-transition:all .3s ease-out;-moz-transition:all .3s ease-out;-ms-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out}.introjs-helperLayer *,.introjs-helperLayer :after,.introjs-helperLayer :before{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;-ms-box-sizing:content-box;-o-box-sizing:content-box;box-sizing:content-box}.introjs-helperNumberLayer{box-sizing:content-box;position:absolute;visibility:visible;top:-16px;left:-16px;z-index:9999999999!important;padding:2px;font-family:Arial,verdana,tahoma;font-size:13px;font-weight:700;color:#fff;text-align:center;text-shadow:1px 1px 1px rgba(0,0,0,.3);background:#ff3019;background:-webkit-linear-gradient(top,#ff3019 0,#cf0404 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#ff3019),color-stop(100%,#cf0404));background:-moz-linear-gradient(top,#ff3019 0,#cf0404 100%);background:-ms-linear-gradient(top,#ff3019 0,#cf0404 100%);background:-o-linear-gradient(top,#ff3019 0,#cf0404 100%);background:linear-gradient(to bottom,#ff3019 0,#cf0404 100%);width:20px;height:20px;line-height:20px;border:3px solid #fff;border-radius:50%;box-shadow:0 2px 5px rgba(0,0,0,.4)}.introjs-arrow{border:5px solid transparent;content:'';position:absolute}.introjs-arrow.top{top:-10px;border-bottom-color:#fff}.introjs-arrow.top-right{top:-10px;right:10px;border-bottom-color:#fff}.introjs-arrow.top-middle{top:-10px;left:50%;margin-left:-5px;border-bottom-color:#fff}.introjs-arrow.right{right:-10px;top:10px;border-left-color:#fff}.introjs-arrow.right-bottom{bottom:10px;right:-10px;border-left-color:#fff}.introjs-arrow.bottom{bottom:-10px;border-top-color:#fff}.introjs-arrow.bottom-right{bottom:-10px;right:10px;border-top-color:#fff}.introjs-arrow.bottom-middle{bottom:-10px;left:50%;margin-left:-5px;border-top-color:#fff}.introjs-arrow.left{left:-10px;top:10px;border-right-color:#fff}.introjs-arrow.left-bottom{left:-10px;bottom:10px;border-right-color:#fff}.introjs-tooltip{box-sizing:content-box;position:absolute;visibility:visible;padding:10px;background-color:#fff;min-width:200px;max-width:300px;border-radius:3px;box-shadow:0 1px 10px rgba(0,0,0,.4);-webkit-transition:opacity .1s ease-out;-moz-transition:opacity .1s ease-out;-ms-transition:opacity .1s ease-out;-o-transition:opacity .1s ease-out;transition:opacity .1s ease-out}.introjs-tooltipbuttons{text-align:right;white-space:nowrap}.introjs-button{box-sizing:content-box;position:relative;overflow:visible;display:inline-block;padding:.3em .8em;border:1px solid #d4d4d4;margin:0;text-decoration:none;text-shadow:1px 1px 0 #fff;font:11px/normal sans-serif;color:#333;white-space:nowrap;cursor:pointer;outline:0;background-color:#ececec;background-image:-webkit-gradient(linear,0 0,0 100%,from(#f4f4f4),to(#ececec));background-image:-moz-linear-gradient(#f4f4f4,#ececec);background-image:-o-linear-gradient(#f4f4f4,#ececec);background-image:linear-gradient(#f4f4f4,#ececec);-webkit-background-clip:padding;-moz-background-clip:padding;-o-background-clip:padding-box;-webkit-border-radius:.2em;-moz-border-radius:.2em;border-radius:.2em;zoom:1;margin-top:10px}.introjs-button:hover{border-color:#bcbcbc;text-decoration:none;box-shadow:0 1px 1px #e3e3e3}.introjs-button:active,.introjs-button:focus{background-image:-webkit-gradient(linear,0 0,0 100%,from(#ececec),to(#f4f4f4));background-image:-moz-linear-gradient(#ececec,#f4f4f4);background-image:-o-linear-gradient(#ececec,#f4f4f4);background-image:linear-gradient(#ececec,#f4f4f4)}.introjs-button::-moz-focus-inner{padding:0;border:0}.introjs-skipbutton{box-sizing:content-box;margin-right:5px;color:#7a7a7a}.introjs-prevbutton{-webkit-border-radius:.2em 0 0 .2em;-moz-border-radius:.2em 0 0 .2em;border-radius:.2em 0 0 .2em;border-right:none}.introjs-prevbutton.introjs-fullbutton{border:1px solid #d4d4d4;-webkit-border-radius:.2em;-moz-border-radius:.2em;border-radius:.2em}.introjs-nextbutton{-webkit-border-radius:0 .2em .2em 0;-moz-border-radius:0 .2em .2em 0;border-radius:0 .2em .2em 0}.introjs-nextbutton.introjs-fullbutton{-webkit-border-radius:.2em;-moz-border-radius:.2em;border-radius:.2em}.introjs-disabled,.introjs-disabled:focus,.introjs-disabled:hover{color:#9a9a9a;border-color:#d4d4d4;box-shadow:none;cursor:default;background-color:#f4f4f4;background-image:none;text-decoration:none}.introjs-hidden{display:none}.introjs-bullets{text-align:center}.introjs-bullets ul{box-sizing:content-box;clear:both;margin:15px auto 0;padding:0;display:inline-block}.introjs-bullets ul li{box-sizing:content-box;list-style:none;float:left;margin:0 2px}.introjs-bullets ul li a{box-sizing:content-box;display:block;width:6px;height:6px;background:#ccc;border-radius:10px;-moz-border-radius:10px;-webkit-border-radius:10px;text-decoration:none;cursor:pointer}.introjs-bullets ul li a:hover{background:#999}.introjs-bullets ul li a.active{background:#999}.introjs-progress{box-sizing:content-box;overflow:hidden;height:10px;margin:10px 0 5px 0;border-radius:4px;background-color:#ecf0f1}.introjs-progressbar{box-sizing:content-box;float:left;width:0%;height:100%;font-size:10px;line-height:10px;text-align:center;background-color:#08c}.introjsFloatingElement{position:absolute;height:0;width:0;left:50%;top:50%}.introjs-fixedTooltip{position:fixed}.introjs-hint{box-sizing:content-box;position:absolute;background:0 0;width:20px;height:15px;cursor:pointer}.introjs-hint:focus{border:0;outline:0}.introjs-hidehint{display:none}.introjs-fixedhint{position:fixed}.introjs-hint:hover>.introjs-hint-pulse{border:5px solid rgba(60,60,60,.57)}.introjs-hint-pulse{box-sizing:content-box;width:10px;height:10px;border:5px solid rgba(60,60,60,.27);-webkit-border-radius:30px;-moz-border-radius:30px;border-radius:30px;background-color:rgba(136,136,136,.24);z-index:10;position:absolute;-webkit-transition:all .2s ease-out;-moz-transition:all .2s ease-out;-ms-transition:all .2s ease-out;-o-transition:all .2s ease-out;transition:all .2s ease-out}.introjs-hint-no-anim .introjs-hint-dot{-webkit-animation:none;-moz-animation:none;animation:none}.introjs-hint-dot{box-sizing:content-box;border:10px solid rgba(146,146,146,.36);background:0 0;-webkit-border-radius:60px;-moz-border-radius:60px;border-radius:60px;height:50px;width:50px;-webkit-animation:introjspulse 3s ease-out;-moz-animation:introjspulse 3s ease-out;animation:introjspulse 3s ease-out;-webkit-animation-iteration-count:infinite;-moz-animation-iteration-count:infinite;animation-iteration-count:infinite;position:absolute;top:-25px;left:-25px;z-index:1;opacity:0}@-webkit-keyframes introjspulse{0%{-webkit-transform:scale(0);opacity:0}25%{-webkit-transform:scale(0);opacity:.1}50%{-webkit-transform:scale(.1);opacity:.3}75%{-webkit-transform:scale(.5);opacity:.5}100%{-webkit-transform:scale(1);opacity:0}}@-moz-keyframes introjspulse{0%{-moz-transform:scale(0);opacity:0}25%{-moz-transform:scale(0);opacity:.1}50%{-moz-transform:scale(.1);opacity:.3}75%{-moz-transform:scale(.5);opacity:.5}100%{-moz-transform:scale(1);opacity:0}}@keyframes introjspulse{0%{transform:scale(0);opacity:0}25%{transform:scale(0);opacity:.1}50%{transform:scale(.1);opacity:.3}75%{transform:scale(.5);opacity:.5}100%{transform:scale(1);opacity:0}}
|
|
resources/css/plugin.css
CHANGED
@@ -374,11 +374,6 @@ label input[type=checkbox] {
|
|
374 |
color: #008000 !important;
|
375 |
line-height: 40px;
|
376 |
}
|
377 |
-
.bootstrap-select > button.dropdown-toggle,
|
378 |
-
.bootstrap-select.show > button.dropdown-toggle {
|
379 |
-
background-color: transparent;
|
380 |
-
color: black !important;
|
381 |
-
}
|
382 |
.dropdown-item {
|
383 |
font-size: 1.05rem;
|
384 |
}
|
@@ -1447,12 +1442,6 @@ a.card_help {
|
|
1447 |
.card .badge.badge-secondary a {
|
1448 |
color: white;
|
1449 |
}
|
1450 |
-
.bootstrap-select.form-control {
|
1451 |
-
border: 1px solid rgba(0, 0, 0, 0.4);
|
1452 |
-
}
|
1453 |
-
.bootstrap-select.form-control > button {
|
1454 |
-
background-color: white;
|
1455 |
-
}
|
1456 |
.nav-pills a.nav-link.active {
|
1457 |
background-color: #008000;
|
1458 |
}
|
@@ -1493,11 +1482,11 @@ a.card_help {
|
|
1493 |
#DashboardFeatureCards .card-title img {
|
1494 |
vertical-align: text-bottom;
|
1495 |
}
|
1496 |
-
#Dashboard_ModSettingsSelect .
|
1497 |
#Dashboard_ModSettingsSelect > select {
|
1498 |
width: 100%;
|
1499 |
}
|
1500 |
-
#ModuleSettingsJump .
|
1501 |
padding: 0;
|
1502 |
line-height: 15px;
|
1503 |
background: transparent !important;
|
@@ -1505,16 +1494,16 @@ a.card_help {
|
|
1505 |
outline: 0 none !important;
|
1506 |
box-shadow: 0 0 transparent !important;
|
1507 |
}
|
1508 |
-
#ModuleSettingsJump .
|
1509 |
content: none !important;
|
1510 |
}
|
1511 |
-
#ModuleSettingsJump .
|
1512 |
font-size: 13px;
|
1513 |
line-height: 20px;
|
1514 |
color: #008000 !important;
|
1515 |
font-weight: 500;
|
1516 |
}
|
1517 |
-
#ModuleSettingsJump .
|
1518 |
#ModuleSettingsJump select,
|
1519 |
#ModuleSettingsJump select:focus,
|
1520 |
#ModuleSettingsJump select:active {
|
@@ -1523,7 +1512,6 @@ a.card_help {
|
|
1523 |
color: #008000;
|
1524 |
vertical-align: inherit;
|
1525 |
}
|
1526 |
-
|
1527 |
#wpfooter {
|
1528 |
display: none;
|
1529 |
}
|
@@ -1538,7 +1526,6 @@ a.card_help {
|
|
1538 |
word-break: keep-all;
|
1539 |
white-space: nowrap;
|
1540 |
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.2);
|
1541 |
-
|
1542 |
position: absolute;
|
1543 |
bottom: 0;
|
1544 |
padding-left: 160px;
|
@@ -1548,20 +1535,24 @@ body.folded #FooterBannerGoPro {
|
|
1548 |
padding-left: 40px;
|
1549 |
}
|
1550 |
@media (max-width: 1200px) {
|
1551 |
-
#FooterBannerGoPro h6{
|
1552 |
font-size: 14px;
|
1553 |
letter-spacing: -1px;
|
1554 |
}
|
1555 |
-
|
|
|
1556 |
font-size: 12px;
|
1557 |
letter-spacing: -1px;
|
1558 |
}
|
1559 |
}
|
1560 |
@media (max-width: 960px) {
|
1561 |
-
#FooterBannerGoPro{
|
1562 |
padding-left: 40px;
|
1563 |
}
|
1564 |
}
|
1565 |
#odp-PageFoot {
|
1566 |
height: 100px;
|
|
|
|
|
|
|
1567 |
}
|
374 |
color: #008000 !important;
|
375 |
line-height: 40px;
|
376 |
}
|
|
|
|
|
|
|
|
|
|
|
377 |
.dropdown-item {
|
378 |
font-size: 1.05rem;
|
379 |
}
|
1442 |
.card .badge.badge-secondary a {
|
1443 |
color: white;
|
1444 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
1445 |
.nav-pills a.nav-link.active {
|
1446 |
background-color: #008000;
|
1447 |
}
|
1482 |
#DashboardFeatureCards .card-title img {
|
1483 |
vertical-align: text-bottom;
|
1484 |
}
|
1485 |
+
#Dashboard_ModSettingsSelect .select2picker,
|
1486 |
#Dashboard_ModSettingsSelect > select {
|
1487 |
width: 100%;
|
1488 |
}
|
1489 |
+
#ModuleSettingsJump .select2picker button {
|
1490 |
padding: 0;
|
1491 |
line-height: 15px;
|
1492 |
background: transparent !important;
|
1494 |
outline: 0 none !important;
|
1495 |
box-shadow: 0 0 transparent !important;
|
1496 |
}
|
1497 |
+
#ModuleSettingsJump .select2picker button::after {
|
1498 |
content: none !important;
|
1499 |
}
|
1500 |
+
#ModuleSettingsJump .select2picker button .filter-option-inner-inner {
|
1501 |
font-size: 13px;
|
1502 |
line-height: 20px;
|
1503 |
color: #008000 !important;
|
1504 |
font-weight: 500;
|
1505 |
}
|
1506 |
+
#ModuleSettingsJump .select2picker,
|
1507 |
#ModuleSettingsJump select,
|
1508 |
#ModuleSettingsJump select:focus,
|
1509 |
#ModuleSettingsJump select:active {
|
1512 |
color: #008000;
|
1513 |
vertical-align: inherit;
|
1514 |
}
|
|
|
1515 |
#wpfooter {
|
1516 |
display: none;
|
1517 |
}
|
1526 |
word-break: keep-all;
|
1527 |
white-space: nowrap;
|
1528 |
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.2);
|
|
|
1529 |
position: absolute;
|
1530 |
bottom: 0;
|
1531 |
padding-left: 160px;
|
1535 |
padding-left: 40px;
|
1536 |
}
|
1537 |
@media (max-width: 1200px) {
|
1538 |
+
#FooterBannerGoPro h6 {
|
1539 |
font-size: 14px;
|
1540 |
letter-spacing: -1px;
|
1541 |
}
|
1542 |
+
|
1543 |
+
#FooterBannerGoPro p {
|
1544 |
font-size: 12px;
|
1545 |
letter-spacing: -1px;
|
1546 |
}
|
1547 |
}
|
1548 |
@media (max-width: 960px) {
|
1549 |
+
#FooterBannerGoPro {
|
1550 |
padding-left: 40px;
|
1551 |
}
|
1552 |
}
|
1553 |
#odp-PageFoot {
|
1554 |
height: 100px;
|
1555 |
+
}
|
1556 |
+
.select2-selection {
|
1557 |
+
font-weight: normal;
|
1558 |
}
|
resources/css/shield/charts.css
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
.ct-line {
|
3 |
+
/* Control the thikness of your lines */
|
4 |
+
stroke-width: 2px !important;
|
5 |
+
}
|
6 |
+
.ct-point {
|
7 |
+
/* Size of your points */
|
8 |
+
stroke-width: 6px !important;
|
9 |
+
}
|
10 |
+
|
11 |
+
/*.ct-series-a .ct-line {*/
|
12 |
+
/* !* Set the colour of this series line *!*/
|
13 |
+
/* stroke: green;*/
|
14 |
+
/* !* Control the thikness of your lines *!*/
|
15 |
+
/* stroke-width: 2px;*/
|
16 |
+
/* !* Create a dashed line with a pattern *!*/
|
17 |
+
/* stroke-dasharray: 3px 1px;*/
|
18 |
+
/*}*/
|
19 |
+
/*!* This selector overrides the points style on line charts. Points on line charts are actually just very short strokes. This allows you to customize even the point size in CSS *!*/
|
20 |
+
/*.ct-series-a .ct-point {*/
|
21 |
+
/* !* Colour of your points *!*/
|
22 |
+
/* stroke: green;*/
|
23 |
+
/* !* Size of your points *!*/
|
24 |
+
/* stroke-width: 4px;*/
|
25 |
+
/* !* Make your points appear as squares *!*/
|
26 |
+
/* stroke-linecap: square;*/
|
27 |
+
/*}*/
|
resources/images/bootstrap/graph-up.svg
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
1 |
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-graph-up" viewBox="0 0 16 16">
|
2 |
+
<path fill-rule="evenodd" d="M0 0h1v15h15v1H0V0zm10 3.5a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 .5.5v4a.5.5 0 0 1-1 0V4.9l-3.613 4.417a.5.5 0 0 1-.74.037L7.06 6.767l-3.656 5.027a.5.5 0 0 1-.808-.588l4-5.5a.5.5 0 0 1 .758-.06l2.609 2.61L13.445 4H10.5a.5.5 0 0 1-.5-.5z"/>
|
3 |
+
</svg>
|
resources/js/base64.min.js
CHANGED
@@ -1 +0,0 @@
|
|
1 |
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):function(){const r=e.Base64,o=t();o.noConflict=()=>(e.Base64=r,o),e.Meteor&&(Base64=o),e.Base64=o}()}("undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:this,(function(){"use strict";const e="3.6.0",t="function"==typeof atob,r="function"==typeof btoa,o="function"==typeof Buffer,n="function"==typeof TextDecoder?new TextDecoder:void 0,a="function"==typeof TextEncoder?new TextEncoder:void 0,f=[..."ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="],i=(e=>{let t={};return e.forEach(((e,r)=>t[e]=r)),t})(f),c=/^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/,u=String.fromCharCode.bind(String),s="function"==typeof Uint8Array.from?Uint8Array.from.bind(Uint8Array):(e,t=(e=>e))=>new Uint8Array(Array.prototype.slice.call(e,0).map(t)),d=e=>e.replace(/[+\/]/g,(e=>"+"==e?"-":"_")).replace(/=+$/m,""),l=e=>e.replace(/[^A-Za-z0-9\+\/]/g,""),h=e=>{let t,r,o,n,a="";const i=e.length%3;for(let i=0;i<e.length;){if((r=e.charCodeAt(i++))>255||(o=e.charCodeAt(i++))>255||(n=e.charCodeAt(i++))>255)throw new TypeError("invalid character found");t=r<<16|o<<8|n,a+=f[t>>18&63]+f[t>>12&63]+f[t>>6&63]+f[63&t]}return i?a.slice(0,i-3)+"===".substring(i):a},p=r?e=>btoa(e):o?e=>Buffer.from(e,"binary").toString("base64"):h,y=o?e=>Buffer.from(e).toString("base64"):e=>{let t=[];for(let r=0,o=e.length;r<o;r+=4096)t.push(u.apply(null,e.subarray(r,r+4096)));return p(t.join(""))},A=(e,t=!1)=>t?d(y(e)):y(e),b=e=>{if(e.length<2)return(t=e.charCodeAt(0))<128?e:t<2048?u(192|t>>>6)+u(128|63&t):u(224|t>>>12&15)+u(128|t>>>6&63)+u(128|63&t);var t=65536+1024*(e.charCodeAt(0)-55296)+(e.charCodeAt(1)-56320);return u(240|t>>>18&7)+u(128|t>>>12&63)+u(128|t>>>6&63)+u(128|63&t)},g=/[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g,B=e=>e.replace(g,b),x=o?e=>Buffer.from(e,"utf8").toString("base64"):a?e=>y(a.encode(e)):e=>p(B(e)),C=(e,t=!1)=>t?d(x(e)):x(e),m=e=>C(e,!0),U=/[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3}/g,F=e=>{switch(e.length){case 4:var t=((7&e.charCodeAt(0))<<18|(63&e.charCodeAt(1))<<12|(63&e.charCodeAt(2))<<6|63&e.charCodeAt(3))-65536;return u(55296+(t>>>10))+u(56320+(1023&t));case 3:return u((15&e.charCodeAt(0))<<12|(63&e.charCodeAt(1))<<6|63&e.charCodeAt(2));default:return u((31&e.charCodeAt(0))<<6|63&e.charCodeAt(1))}},w=e=>e.replace(U,F),S=e=>{if(e=e.replace(/\s+/g,""),!c.test(e))throw new TypeError("malformed base64.");e+="==".slice(2-(3&e.length));let t,r,o,n="";for(let a=0;a<e.length;)t=i[e.charAt(a++)]<<18|i[e.charAt(a++)]<<12|(r=i[e.charAt(a++)])<<6|(o=i[e.charAt(a++)]),n+=64===r?u(t>>16&255):64===o?u(t>>16&255,t>>8&255):u(t>>16&255,t>>8&255,255&t);return n},E=t?e=>atob(l(e)):o?e=>Buffer.from(e,"base64").toString("binary"):S,v=o?e=>s(Buffer.from(e,"base64")):e=>s(E(e),(e=>e.charCodeAt(0))),D=e=>v(z(e)),R=o?e=>Buffer.from(e,"base64").toString("utf8"):n?e=>n.decode(v(e)):e=>w(E(e)),z=e=>l(e.replace(/[-_]/g,(e=>"-"==e?"+":"/"))),T=e=>R(z(e)),Z=e=>({value:e,enumerable:!1,writable:!0,configurable:!0}),j=function(){const e=(e,t)=>Object.defineProperty(String.prototype,e,Z(t));e("fromBase64",(function(){return T(this)})),e("toBase64",(function(e){return C(this,e)})),e("toBase64URI",(function(){return C(this,!0)})),e("toBase64URL",(function(){return C(this,!0)})),e("toUint8Array",(function(){return D(this)}))},I=function(){const e=(e,t)=>Object.defineProperty(Uint8Array.prototype,e,Z(t));e("toBase64",(function(e){return A(this,e)})),e("toBase64URI",(function(){return A(this,!0)})),e("toBase64URL",(function(){return A(this,!0)}))},O={version:e,VERSION:"3.6.0",atob:E,atobPolyfill:S,btoa:p,btoaPolyfill:h,fromBase64:T,toBase64:C,encode:C,encodeURI:m,encodeURL:m,utob:B,btou:w,decode:T,isValid:e=>{if("string"!=typeof e)return!1;const t=e.replace(/\s+/g,"").replace(/=+$/,"");return!/[^\s0-9a-zA-Z\+/]/.test(t)||!/[^\s0-9a-zA-Z\-_]/.test(t)},fromUint8Array:A,toUint8Array:D,extendString:j,extendUint8Array:I,extendBuiltins:()=>{j(),I()},Base64:{}};return Object.keys(O).forEach((e=>O.Base64[e]=O[e])),O}));
|
|
resources/js/bootstrap-select.min.js
DELETED
@@ -1,9 +0,0 @@
|
|
1 |
-
/*!
|
2 |
-
* Bootstrap-select v1.13.18 (https://developer.snapappointments.com/bootstrap-select)
|
3 |
-
*
|
4 |
-
* Copyright 2012-2020 SnapAppointments, LLC
|
5 |
-
* Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE)
|
6 |
-
*/
|
7 |
-
|
8 |
-
!function(e,t){void 0===e&&void 0!==window&&(e=window),"function"==typeof define&&define.amd?define(["jquery"],function(e){return t(e)}):"object"==typeof module&&module.exports?module.exports=t(require("jquery")):t(e.jQuery)}(this,function(e){!function(P){"use strict";var d=["sanitize","whiteList","sanitizeFn"],r=["background","cite","href","itemtype","longdesc","poster","src","xlink:href"],e={"*":["class","dir","id","lang","role","tabindex","style",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},l=/^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi,a=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i;function v(e,t){var i=e.nodeName.toLowerCase();if(-1!==P.inArray(i,t))return-1===P.inArray(i,r)||Boolean(e.nodeValue.match(l)||e.nodeValue.match(a));for(var s=P(t).filter(function(e,t){return t instanceof RegExp}),n=0,o=s.length;n<o;n++)if(i.match(s[n]))return!0;return!1}function W(e,t,i){if(i&&"function"==typeof i)return i(e);for(var s=Object.keys(t),n=0,o=e.length;n<o;n++)for(var r=e[n].querySelectorAll("*"),l=0,a=r.length;l<a;l++){var c=r[l],d=c.nodeName.toLowerCase();if(-1!==s.indexOf(d))for(var h=[].slice.call(c.attributes),p=[].concat(t["*"]||[],t[d]||[]),u=0,f=h.length;u<f;u++){var m=h[u];v(m,p)||c.removeAttribute(m.nodeName)}else c.parentNode.removeChild(c)}}"classList"in document.createElement("_")||function(e){if("Element"in e){var t="classList",i="prototype",s=e.Element[i],n=Object,o=function(){var i=P(this);return{add:function(e){return e=Array.prototype.slice.call(arguments).join(" "),i.addClass(e)},remove:function(e){return e=Array.prototype.slice.call(arguments).join(" "),i.removeClass(e)},toggle:function(e,t){return i.toggleClass(e,t)},contains:function(e){return i.hasClass(e)}}};if(n.defineProperty){var r={get:o,enumerable:!0,configurable:!0};try{n.defineProperty(s,t,r)}catch(e){void 0!==e.number&&-2146823252!==e.number||(r.enumerable=!1,n.defineProperty(s,t,r))}}else n[i].__defineGetter__&&s.__defineGetter__(t,o)}}(window);var t,c,i=document.createElement("_");if(i.classList.add("c1","c2"),!i.classList.contains("c2")){var s=DOMTokenList.prototype.add,n=DOMTokenList.prototype.remove;DOMTokenList.prototype.add=function(){Array.prototype.forEach.call(arguments,s.bind(this))},DOMTokenList.prototype.remove=function(){Array.prototype.forEach.call(arguments,n.bind(this))}}if(i.classList.toggle("c3",!1),i.classList.contains("c3")){var o=DOMTokenList.prototype.toggle;DOMTokenList.prototype.toggle=function(e,t){return 1 in arguments&&!this.contains(e)==!t?t:o.call(this,e)}}function h(e){if(null==this)throw new TypeError;var t=String(this);if(e&&"[object RegExp]"==c.call(e))throw new TypeError;var i=t.length,s=String(e),n=s.length,o=1<arguments.length?arguments[1]:void 0,r=o?Number(o):0;r!=r&&(r=0);var l=Math.min(Math.max(r,0),i);if(i<n+l)return!1;for(var a=-1;++a<n;)if(t.charCodeAt(l+a)!=s.charCodeAt(a))return!1;return!0}function O(e,t){var i,s=e.selectedOptions,n=[];if(t){for(var o=0,r=s.length;o<r;o++)(i=s[o]).disabled||"OPTGROUP"===i.parentNode.tagName&&i.parentNode.disabled||n.push(i);return n}return s}function z(e,t){for(var i,s=[],n=t||e.selectedOptions,o=0,r=n.length;o<r;o++)(i=n[o]).disabled||"OPTGROUP"===i.parentNode.tagName&&i.parentNode.disabled||s.push(i.value);return e.multiple?s:s.length?s[0]:null}i=null,String.prototype.startsWith||(t=function(){try{var e={},t=Object.defineProperty,i=t(e,e,e)&&t}catch(e){}return i}(),c={}.toString,t?t(String.prototype,"startsWith",{value:h,configurable:!0,writable:!0}):String.prototype.startsWith=h),Object.keys||(Object.keys=function(e,t,i){for(t in i=[],e)i.hasOwnProperty.call(e,t)&&i.push(t);return i}),HTMLSelectElement&&!HTMLSelectElement.prototype.hasOwnProperty("selectedOptions")&&Object.defineProperty(HTMLSelectElement.prototype,"selectedOptions",{get:function(){return this.querySelectorAll(":checked")}});var p={useDefault:!1,_set:P.valHooks.select.set};P.valHooks.select.set=function(e,t){return t&&!p.useDefault&&P(e).data("selected",!0),p._set.apply(this,arguments)};var T=null,u=function(){try{return new Event("change"),!0}catch(e){return!1}}();function k(e,t,i,s){for(var n=["display","subtext","tokens"],o=!1,r=0;r<n.length;r++){var l=n[r],a=e[l];if(a&&(a=a.toString(),"display"===l&&(a=a.replace(/<[^>]+>/g,"")),s&&(a=w(a)),a=a.toUpperCase(),o="contains"===i?0<=a.indexOf(t):a.startsWith(t)))break}return o}function N(e){return parseInt(e,10)||0}P.fn.triggerNative=function(e){var t,i=this[0];i.dispatchEvent?(u?t=new Event(e,{bubbles:!0}):(t=document.createEvent("Event")).initEvent(e,!0,!1),i.dispatchEvent(t)):i.fireEvent?((t=document.createEventObject()).eventType=e,i.fireEvent("on"+e,t)):this.trigger(e)};var f={"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xe0":"a","\xe1":"a","\xe2":"a","\xe3":"a","\xe4":"a","\xe5":"a","\xc7":"C","\xe7":"c","\xd0":"D","\xf0":"d","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xcc":"I","\xcd":"I","\xce":"I","\xcf":"I","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xd1":"N","\xf1":"n","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xdd":"Y","\xfd":"y","\xff":"y","\xc6":"Ae","\xe6":"ae","\xde":"Th","\xfe":"th","\xdf":"ss","\u0100":"A","\u0102":"A","\u0104":"A","\u0101":"a","\u0103":"a","\u0105":"a","\u0106":"C","\u0108":"C","\u010a":"C","\u010c":"C","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\u010e":"D","\u0110":"D","\u010f":"d","\u0111":"d","\u0112":"E","\u0114":"E","\u0116":"E","\u0118":"E","\u011a":"E","\u0113":"e","\u0115":"e","\u0117":"e","\u0119":"e","\u011b":"e","\u011c":"G","\u011e":"G","\u0120":"G","\u0122":"G","\u011d":"g","\u011f":"g","\u0121":"g","\u0123":"g","\u0124":"H","\u0126":"H","\u0125":"h","\u0127":"h","\u0128":"I","\u012a":"I","\u012c":"I","\u012e":"I","\u0130":"I","\u0129":"i","\u012b":"i","\u012d":"i","\u012f":"i","\u0131":"i","\u0134":"J","\u0135":"j","\u0136":"K","\u0137":"k","\u0138":"k","\u0139":"L","\u013b":"L","\u013d":"L","\u013f":"L","\u0141":"L","\u013a":"l","\u013c":"l","\u013e":"l","\u0140":"l","\u0142":"l","\u0143":"N","\u0145":"N","\u0147":"N","\u014a":"N","\u0144":"n","\u0146":"n","\u0148":"n","\u014b":"n","\u014c":"O","\u014e":"O","\u0150":"O","\u014d":"o","\u014f":"o","\u0151":"o","\u0154":"R","\u0156":"R","\u0158":"R","\u0155":"r","\u0157":"r","\u0159":"r","\u015a":"S","\u015c":"S","\u015e":"S","\u0160":"S","\u015b":"s","\u015d":"s","\u015f":"s","\u0161":"s","\u0162":"T","\u0164":"T","\u0166":"T","\u0163":"t","\u0165":"t","\u0167":"t","\u0168":"U","\u016a":"U","\u016c":"U","\u016e":"U","\u0170":"U","\u0172":"U","\u0169":"u","\u016b":"u","\u016d":"u","\u016f":"u","\u0171":"u","\u0173":"u","\u0174":"W","\u0175":"w","\u0176":"Y","\u0177":"y","\u0178":"Y","\u0179":"Z","\u017b":"Z","\u017d":"Z","\u017a":"z","\u017c":"z","\u017e":"z","\u0132":"IJ","\u0133":"ij","\u0152":"Oe","\u0153":"oe","\u0149":"'n","\u017f":"s"},m=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,g=RegExp("[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff\\u1ab0-\\u1aff\\u1dc0-\\u1dff]","g");function b(e){return f[e]}function w(e){return(e=e.toString())&&e.replace(m,b).replace(g,"")}var I,x,y,$,S=(I={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},x="(?:"+Object.keys(I).join("|")+")",y=RegExp(x),$=RegExp(x,"g"),function(e){return e=null==e?"":""+e,y.test(e)?e.replace($,E):e});function E(e){return I[e]}var C={32:" ",48:"0",49:"1",50:"2",51:"3",52:"4",53:"5",54:"6",55:"7",56:"8",57:"9",59:";",65:"A",66:"B",67:"C",68:"D",69:"E",70:"F",71:"G",72:"H",73:"I",74:"J",75:"K",76:"L",77:"M",78:"N",79:"O",80:"P",81:"Q",82:"R",83:"S",84:"T",85:"U",86:"V",87:"W",88:"X",89:"Y",90:"Z",96:"0",97:"1",98:"2",99:"3",100:"4",101:"5",102:"6",103:"7",104:"8",105:"9"},A=27,L=13,D=32,H=9,B=38,R=40,M={success:!1,major:"3"};try{M.full=(P.fn.dropdown.Constructor.VERSION||"").split(" ")[0].split("."),M.major=M.full[0],M.success=!0}catch(e){}var U=0,j=".bs.select",V={DISABLED:"disabled",DIVIDER:"divider",SHOW:"open",DROPUP:"dropup",MENU:"dropdown-menu",MENURIGHT:"dropdown-menu-right",MENULEFT:"dropdown-menu-left",BUTTONCLASS:"btn-default",POPOVERHEADER:"popover-title",ICONBASE:"glyphicon",TICKICON:"glyphicon-ok"},F={MENU:"."+V.MENU},_={div:document.createElement("div"),span:document.createElement("span"),i:document.createElement("i"),subtext:document.createElement("small"),a:document.createElement("a"),li:document.createElement("li"),whitespace:document.createTextNode("\xa0"),fragment:document.createDocumentFragment()};_.noResults=_.li.cloneNode(!1),_.noResults.className="no-results",_.a.setAttribute("role","option"),_.a.className="dropdown-item",_.subtext.className="text-muted",_.text=_.span.cloneNode(!1),_.text.className="text",_.checkMark=_.span.cloneNode(!1);var G=new RegExp(B+"|"+R),q=new RegExp("^"+H+"$|"+A),K={li:function(e,t,i){var s=_.li.cloneNode(!1);return e&&(1===e.nodeType||11===e.nodeType?s.appendChild(e):s.innerHTML=e),void 0!==t&&""!==t&&(s.className=t),null!=i&&s.classList.add("optgroup-"+i),s},a:function(e,t,i){var s=_.a.cloneNode(!0);return e&&(11===e.nodeType?s.appendChild(e):s.insertAdjacentHTML("beforeend",e)),void 0!==t&&""!==t&&s.classList.add.apply(s.classList,t.split(/\s+/)),i&&s.setAttribute("style",i),s},text:function(e,t){var i,s,n=_.text.cloneNode(!1);if(e.content)n.innerHTML=e.content;else{if(n.textContent=e.text,e.icon){var o=_.whitespace.cloneNode(!1);(s=(!0===t?_.i:_.span).cloneNode(!1)).className=this.options.iconBase+" "+e.icon,_.fragment.appendChild(s),_.fragment.appendChild(o)}e.subtext&&((i=_.subtext.cloneNode(!1)).textContent=e.subtext,n.appendChild(i))}if(!0===t)for(;0<n.childNodes.length;)_.fragment.appendChild(n.childNodes[0]);else _.fragment.appendChild(n);return _.fragment},label:function(e){var t,i,s=_.text.cloneNode(!1);if(s.innerHTML=e.display,e.icon){var n=_.whitespace.cloneNode(!1);(i=_.span.cloneNode(!1)).className=this.options.iconBase+" "+e.icon,_.fragment.appendChild(i),_.fragment.appendChild(n)}return e.subtext&&((t=_.subtext.cloneNode(!1)).textContent=e.subtext,s.appendChild(t)),_.fragment.appendChild(s),_.fragment}};var Y=function(e,t){var i=this;p.useDefault||(P.valHooks.select.set=p._set,p.useDefault=!0),this.$element=P(e),this.$newElement=null,this.$button=null,this.$menu=null,this.options=t,this.selectpicker={main:{},search:{},current:{},view:{},isSearching:!1,keydown:{keyHistory:"",resetKeyHistory:{start:function(){return setTimeout(function(){i.selectpicker.keydown.keyHistory=""},800)}}}},this.sizeInfo={},null===this.options.title&&(this.options.title=this.$element.attr("title"));var s=this.options.windowPadding;"number"==typeof s&&(this.options.windowPadding=[s,s,s,s]),this.val=Y.prototype.val,this.render=Y.prototype.render,this.refresh=Y.prototype.refresh,this.setStyle=Y.prototype.setStyle,this.selectAll=Y.prototype.selectAll,this.deselectAll=Y.prototype.deselectAll,this.destroy=Y.prototype.destroy,this.remove=Y.prototype.remove,this.show=Y.prototype.show,this.hide=Y.prototype.hide,this.init()};function Z(e){var l,a=arguments,c=e;if([].shift.apply(a),!M.success){try{M.full=(P.fn.dropdown.Constructor.VERSION||"").split(" ")[0].split(".")}catch(e){Y.BootstrapVersion?M.full=Y.BootstrapVersion.split(" ")[0].split("."):(M.full=[M.major,"0","0"],console.warn("There was an issue retrieving Bootstrap's version. Ensure Bootstrap is being loaded before bootstrap-select and there is no namespace collision. If loading Bootstrap asynchronously, the version may need to be manually specified via $.fn.selectpicker.Constructor.BootstrapVersion.",e))}M.major=M.full[0],M.success=!0}if("4"===M.major){var t=[];Y.DEFAULTS.style===V.BUTTONCLASS&&t.push({name:"style",className:"BUTTONCLASS"}),Y.DEFAULTS.iconBase===V.ICONBASE&&t.push({name:"iconBase",className:"ICONBASE"}),Y.DEFAULTS.tickIcon===V.TICKICON&&t.push({name:"tickIcon",className:"TICKICON"}),V.DIVIDER="dropdown-divider",V.SHOW="show",V.BUTTONCLASS="btn-light",V.POPOVERHEADER="popover-header",V.ICONBASE="",V.TICKICON="bs-ok-default";for(var i=0;i<t.length;i++){e=t[i];Y.DEFAULTS[e.name]=V[e.className]}}var s=this.each(function(){var e=P(this);if(e.is("select")){var t=e.data("selectpicker"),i="object"==typeof c&&c;if(t){if(i)for(var s in i)Object.prototype.hasOwnProperty.call(i,s)&&(t.options[s]=i[s])}else{var n=e.data();for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&-1!==P.inArray(o,d)&&delete n[o];var r=P.extend({},Y.DEFAULTS,P.fn.selectpicker.defaults||{},n,i);r.template=P.extend({},Y.DEFAULTS.template,P.fn.selectpicker.defaults?P.fn.selectpicker.defaults.template:{},n.template,i.template),e.data("selectpicker",t=new Y(this,r))}"string"==typeof c&&(l=t[c]instanceof Function?t[c].apply(t,a):t.options[c])}});return void 0!==l?l:s}Y.VERSION="1.13.18",Y.DEFAULTS={noneSelectedText:"Nothing selected",noneResultsText:"No results matched {0}",countSelectedText:function(e,t){return 1==e?"{0} item selected":"{0} items selected"},maxOptionsText:function(e,t){return[1==e?"Limit reached ({n} item max)":"Limit reached ({n} items max)",1==t?"Group limit reached ({n} item max)":"Group limit reached ({n} items max)"]},selectAllText:"Select All",deselectAllText:"Deselect All",doneButton:!1,doneButtonText:"Close",multipleSeparator:", ",styleBase:"btn",style:V.BUTTONCLASS,size:"auto",title:null,selectedTextFormat:"values",width:!1,container:!1,hideDisabled:!1,showSubtext:!1,showIcon:!0,showContent:!0,dropupAuto:!0,header:!1,liveSearch:!1,liveSearchPlaceholder:null,liveSearchNormalize:!1,liveSearchStyle:"contains",actionsBox:!1,iconBase:V.ICONBASE,tickIcon:V.TICKICON,showTick:!1,template:{caret:'<span class="caret"></span>'},maxOptions:!1,mobile:!1,selectOnTab:!1,dropdownAlignRight:!1,windowPadding:0,virtualScroll:600,display:!1,sanitize:!0,sanitizeFn:null,whiteList:e},Y.prototype={constructor:Y,init:function(){var i=this,e=this.$element.attr("id"),t=this.$element[0],s=t.form;U++,this.selectId="bs-select-"+U,t.classList.add("bs-select-hidden"),this.multiple=this.$element.prop("multiple"),this.autofocus=this.$element.prop("autofocus"),t.classList.contains("show-tick")&&(this.options.showTick=!0),this.$newElement=this.createDropdown(),this.buildData(),this.$element.after(this.$newElement).prependTo(this.$newElement),s&&null===t.form&&(s.id||(s.id="form-"+this.selectId),t.setAttribute("form",s.id)),this.$button=this.$newElement.children("button"),this.$menu=this.$newElement.children(F.MENU),this.$menuInner=this.$menu.children(".inner"),this.$searchbox=this.$menu.find("input"),t.classList.remove("bs-select-hidden"),!0===this.options.dropdownAlignRight&&this.$menu[0].classList.add(V.MENURIGHT),void 0!==e&&this.$button.attr("data-id",e),this.checkDisabled(),this.clickListener(),this.options.liveSearch?(this.liveSearchListener(),this.focusedParent=this.$searchbox[0]):this.focusedParent=this.$menuInner[0],this.setStyle(),this.render(),this.setWidth(),this.options.container?this.selectPosition():this.$element.on("hide"+j,function(){if(i.isVirtual()){var e=i.$menuInner[0],t=e.firstChild.cloneNode(!1);e.replaceChild(t,e.firstChild),e.scrollTop=0}}),this.$menu.data("this",this),this.$newElement.data("this",this),this.options.mobile&&this.mobile(),this.$newElement.on({"hide.bs.dropdown":function(e){i.$element.trigger("hide"+j,e)},"hidden.bs.dropdown":function(e){i.$element.trigger("hidden"+j,e)},"show.bs.dropdown":function(e){i.$element.trigger("show"+j,e)},"shown.bs.dropdown":function(e){i.$element.trigger("shown"+j,e)}}),t.hasAttribute("required")&&this.$element.on("invalid"+j,function(){i.$button[0].classList.add("bs-invalid"),i.$element.on("shown"+j+".invalid",function(){i.$element.val(i.$element.val()).off("shown"+j+".invalid")}).on("rendered"+j,function(){this.validity.valid&&i.$button[0].classList.remove("bs-invalid"),i.$element.off("rendered"+j)}),i.$button.on("blur"+j,function(){i.$element.trigger("focus").trigger("blur"),i.$button.off("blur"+j)})}),setTimeout(function(){i.buildList(),i.$element.trigger("loaded"+j)})},createDropdown:function(){var e=this.multiple||this.options.showTick?" show-tick":"",t=this.multiple?' aria-multiselectable="true"':"",i="",s=this.autofocus?" autofocus":"";M.major<4&&this.$element.parent().hasClass("input-group")&&(i=" input-group-btn");var n,o="",r="",l="",a="";return this.options.header&&(o='<div class="'+V.POPOVERHEADER+'"><button type="button" class="close" aria-hidden="true">×</button>'+this.options.header+"</div>"),this.options.liveSearch&&(r='<div class="bs-searchbox"><input type="search" class="form-control" autocomplete="off"'+(null===this.options.liveSearchPlaceholder?"":' placeholder="'+S(this.options.liveSearchPlaceholder)+'"')+' role="combobox" aria-label="Search" aria-controls="'+this.selectId+'" aria-autocomplete="list"></div>'),this.multiple&&this.options.actionsBox&&(l='<div class="bs-actionsbox"><div class="btn-group btn-group-sm btn-block"><button type="button" class="actions-btn bs-select-all btn '+V.BUTTONCLASS+'">'+this.options.selectAllText+'</button><button type="button" class="actions-btn bs-deselect-all btn '+V.BUTTONCLASS+'">'+this.options.deselectAllText+"</button></div></div>"),this.multiple&&this.options.doneButton&&(a='<div class="bs-donebutton"><div class="btn-group btn-block"><button type="button" class="btn btn-sm '+V.BUTTONCLASS+'">'+this.options.doneButtonText+"</button></div></div>"),n='<div class="dropdown bootstrap-select'+e+i+'"><button type="button" tabindex="-1" class="'+this.options.styleBase+' dropdown-toggle" '+("static"===this.options.display?'data-display="static"':"")+'data-toggle="dropdown"'+s+' role="combobox" aria-owns="'+this.selectId+'" aria-haspopup="listbox" aria-expanded="false"><div class="filter-option"><div class="filter-option-inner"><div class="filter-option-inner-inner"></div></div> </div>'+("4"===M.major?"":'<span class="bs-caret">'+this.options.template.caret+"</span>")+'</button><div class="'+V.MENU+" "+("4"===M.major?"":V.SHOW)+'">'+o+r+l+'<div class="inner '+V.SHOW+'" role="listbox" id="'+this.selectId+'" tabindex="-1" '+t+'><ul class="'+V.MENU+" inner "+("4"===M.major?V.SHOW:"")+'" role="presentation"></ul></div>'+a+"</div></div>",P(n)},setPositionData:function(){this.selectpicker.view.canHighlight=[],this.selectpicker.view.size=0,this.selectpicker.view.firstHighlightIndex=!1;for(var e=0;e<this.selectpicker.current.data.length;e++){var t=this.selectpicker.current.data[e],i=!0;"divider"===t.type?(i=!1,t.height=this.sizeInfo.dividerHeight):"optgroup-label"===t.type?(i=!1,t.height=this.sizeInfo.dropdownHeaderHeight):t.height=this.sizeInfo.liHeight,t.disabled&&(i=!1),this.selectpicker.view.canHighlight.push(i),i&&(this.selectpicker.view.size++,t.posinset=this.selectpicker.view.size,!1===this.selectpicker.view.firstHighlightIndex&&(this.selectpicker.view.firstHighlightIndex=e)),t.position=(0===e?0:this.selectpicker.current.data[e-1].position)+t.height}},isVirtual:function(){return!1!==this.options.virtualScroll&&this.selectpicker.main.elements.length>=this.options.virtualScroll||!0===this.options.virtualScroll},createView:function(N,e,t){var A,L,D=this,i=0,H=[];if(this.selectpicker.isSearching=N,this.selectpicker.current=N?this.selectpicker.search:this.selectpicker.main,this.setPositionData(),e)if(t)i=this.$menuInner[0].scrollTop;else if(!D.multiple){var s=D.$element[0],n=(s.options[s.selectedIndex]||{}).liIndex;if("number"==typeof n&&!1!==D.options.size){var o=D.selectpicker.main.data[n],r=o&&o.position;r&&(i=r-(D.sizeInfo.menuInnerHeight+D.sizeInfo.liHeight)/2)}}function l(e,t){var i,s,n,o,r,l,a,c,d=D.selectpicker.current.elements.length,h=[],p=!0,u=D.isVirtual();D.selectpicker.view.scrollTop=e,i=Math.ceil(D.sizeInfo.menuInnerHeight/D.sizeInfo.liHeight*1.5),s=Math.round(d/i)||1;for(var f=0;f<s;f++){var m=(f+1)*i;if(f===s-1&&(m=d),h[f]=[f*i+(f?1:0),m],!d)break;void 0===r&&e-1<=D.selectpicker.current.data[m-1].position-D.sizeInfo.menuInnerHeight&&(r=f)}if(void 0===r&&(r=0),l=[D.selectpicker.view.position0,D.selectpicker.view.position1],n=Math.max(0,r-1),o=Math.min(s-1,r+1),D.selectpicker.view.position0=!1===u?0:Math.max(0,h[n][0])||0,D.selectpicker.view.position1=!1===u?d:Math.min(d,h[o][1])||0,a=l[0]!==D.selectpicker.view.position0||l[1]!==D.selectpicker.view.position1,void 0!==D.activeIndex&&(L=D.selectpicker.main.elements[D.prevActiveIndex],H=D.selectpicker.main.elements[D.activeIndex],A=D.selectpicker.main.elements[D.selectedIndex],t&&(D.activeIndex!==D.selectedIndex&&D.defocusItem(H),D.activeIndex=void 0),D.activeIndex&&D.activeIndex!==D.selectedIndex&&D.defocusItem(A)),void 0!==D.prevActiveIndex&&D.prevActiveIndex!==D.activeIndex&&D.prevActiveIndex!==D.selectedIndex&&D.defocusItem(L),(t||a)&&(c=D.selectpicker.view.visibleElements?D.selectpicker.view.visibleElements.slice():[],D.selectpicker.view.visibleElements=!1===u?D.selectpicker.current.elements:D.selectpicker.current.elements.slice(D.selectpicker.view.position0,D.selectpicker.view.position1),D.setOptionStatus(),(N||!1===u&&t)&&(p=!function(e,i){return e.length===i.length&&e.every(function(e,t){return e===i[t]})}(c,D.selectpicker.view.visibleElements)),(t||!0===u)&&p)){var v,g,b=D.$menuInner[0],w=document.createDocumentFragment(),I=b.firstChild.cloneNode(!1),x=D.selectpicker.view.visibleElements,k=[];b.replaceChild(I,b.firstChild);f=0;for(var y=x.length;f<y;f++){var $,S,E=x[f];D.options.sanitize&&($=E.lastChild)&&(S=D.selectpicker.current.data[f+D.selectpicker.view.position0])&&S.content&&!S.sanitized&&(k.push($),S.sanitized=!0),w.appendChild(E)}if(D.options.sanitize&&k.length&&W(k,D.options.whiteList,D.options.sanitizeFn),!0===u?(v=0===D.selectpicker.view.position0?0:D.selectpicker.current.data[D.selectpicker.view.position0-1].position,g=D.selectpicker.view.position1>d-1?0:D.selectpicker.current.data[d-1].position-D.selectpicker.current.data[D.selectpicker.view.position1-1].position,b.firstChild.style.marginTop=v+"px",b.firstChild.style.marginBottom=g+"px"):(b.firstChild.style.marginTop=0,b.firstChild.style.marginBottom=0),b.firstChild.appendChild(w),!0===u&&D.sizeInfo.hasScrollBar){var C=b.firstChild.offsetWidth;if(t&&C<D.sizeInfo.menuInnerInnerWidth&&D.sizeInfo.totalMenuWidth>D.sizeInfo.selectWidth)b.firstChild.style.minWidth=D.sizeInfo.menuInnerInnerWidth+"px";else if(C>D.sizeInfo.menuInnerInnerWidth){D.$menu[0].style.minWidth=0;var O=b.firstChild.offsetWidth;O>D.sizeInfo.menuInnerInnerWidth&&(D.sizeInfo.menuInnerInnerWidth=O,b.firstChild.style.minWidth=D.sizeInfo.menuInnerInnerWidth+"px"),D.$menu[0].style.minWidth=""}}}if(D.prevActiveIndex=D.activeIndex,D.options.liveSearch){if(N&&t){var z,T=0;D.selectpicker.view.canHighlight[T]||(T=1+D.selectpicker.view.canHighlight.slice(1).indexOf(!0)),z=D.selectpicker.view.visibleElements[T],D.defocusItem(D.selectpicker.view.currentActive),D.activeIndex=(D.selectpicker.current.data[T]||{}).index,D.focusItem(z)}}else D.$menuInner.trigger("focus")}l(i,!0),this.$menuInner.off("scroll.createView").on("scroll.createView",function(e,t){D.noScroll||l(this.scrollTop,t),D.noScroll=!1}),P(window).off("resize"+j+"."+this.selectId+".createView").on("resize"+j+"."+this.selectId+".createView",function(){D.$newElement.hasClass(V.SHOW)&&l(D.$menuInner[0].scrollTop)})},focusItem:function(e,t,i){if(e){t=t||this.selectpicker.main.data[this.activeIndex];var s=e.firstChild;s&&(s.setAttribute("aria-setsize",this.selectpicker.view.size),s.setAttribute("aria-posinset",t.posinset),!0!==i&&(this.focusedParent.setAttribute("aria-activedescendant",s.id),e.classList.add("active"),s.classList.add("active")))}},defocusItem:function(e){e&&(e.classList.remove("active"),e.firstChild&&e.firstChild.classList.remove("active"))},setPlaceholder:function(){var e=this,t=!1;if(this.options.title&&!this.multiple){this.selectpicker.view.titleOption||(this.selectpicker.view.titleOption=document.createElement("option")),t=!0;var i=this.$element[0],s=!1,n=!this.selectpicker.view.titleOption.parentNode,o=i.selectedIndex,r=i.options[o],l=window.performance&&window.performance.getEntriesByType("navigation"),a=l&&l.length?"back_forward"!==l[0].type:2!==window.performance.navigation.type;n&&(this.selectpicker.view.titleOption.className="bs-title-option",this.selectpicker.view.titleOption.value="",s=!r||0===o&&!1===r.defaultSelected&&void 0===this.$element.data("selected")),!n&&0===this.selectpicker.view.titleOption.index||i.insertBefore(this.selectpicker.view.titleOption,i.firstChild),s&&a?i.selectedIndex=0:"complete"!==document.readyState&&window.addEventListener("pageshow",function(){e.selectpicker.view.displayedValue!==i.value&&e.render()})}return t},buildData:function(){var p=':not([hidden]):not([data-hidden="true"])',u=[],f=0,m=this.setPlaceholder()?1:0;this.options.hideDisabled&&(p+=":not(:disabled)");var e=this.$element[0].querySelectorAll("select > *"+p);function v(e){var t=u[u.length-1];t&&"divider"===t.type&&(t.optID||e.optID)||((e=e||{}).type="divider",u.push(e))}function g(e,t){if((t=t||{}).divider="true"===e.getAttribute("data-divider"),t.divider)v({optID:t.optID});else{var i=u.length,s=e.style.cssText,n=s?S(s):"",o=(e.className||"")+(t.optgroupClass||"");t.optID&&(o="opt "+o),t.optionClass=o.trim(),t.inlineStyle=n,t.text=e.textContent,t.content=e.getAttribute("data-content"),t.tokens=e.getAttribute("data-tokens"),t.subtext=e.getAttribute("data-subtext"),t.icon=e.getAttribute("data-icon"),e.liIndex=i,t.display=t.content||t.text,t.type="option",t.index=i,t.option=e,t.selected=!!e.selected,t.disabled=t.disabled||!!e.disabled,u.push(t)}}function t(e,t){var i=t[e],s=!(e-1<m)&&t[e-1],n=t[e+1],o=i.querySelectorAll("option"+p);if(o.length){var r,l,a={display:S(i.label),subtext:i.getAttribute("data-subtext"),icon:i.getAttribute("data-icon"),type:"optgroup-label",optgroupClass:" "+(i.className||"")};f++,s&&v({optID:f}),a.optID=f,u.push(a);for(var c=0,d=o.length;c<d;c++){var h=o[c];0===c&&(l=(r=u.length-1)+d),g(h,{headerIndex:r,lastIndex:l,optID:a.optID,optgroupClass:a.optgroupClass,disabled:i.disabled})}n&&v({optID:f})}}for(var i=e.length,s=m;s<i;s++){var n=e[s];"OPTGROUP"!==n.tagName?g(n,{}):t(s,e)}this.selectpicker.main.data=this.selectpicker.current.data=u},buildList:function(){var s=this,e=this.selectpicker.main.data,n=[],o=0;function t(e){var t,i=0;switch(e.type){case"divider":t=K.li(!1,V.DIVIDER,e.optID?e.optID+"div":void 0);break;case"option":(t=K.li(K.a(K.text.call(s,e),e.optionClass,e.inlineStyle),"",e.optID)).firstChild&&(t.firstChild.id=s.selectId+"-"+e.index);break;case"optgroup-label":t=K.li(K.label.call(s,e),"dropdown-header"+e.optgroupClass,e.optID)}e.element=t,n.push(t),e.display&&(i+=e.display.length),e.subtext&&(i+=e.subtext.length),e.icon&&(i+=1),o<i&&(o=i,s.selectpicker.view.widestOption=n[n.length-1])}!s.options.showTick&&!s.multiple||_.checkMark.parentNode||(_.checkMark.className=this.options.iconBase+" "+s.options.tickIcon+" check-mark",_.a.appendChild(_.checkMark));for(var i=e.length,r=0;r<i;r++){t(e[r])}this.selectpicker.main.elements=this.selectpicker.current.elements=n},findLis:function(){return this.$menuInner.find(".inner > li")},render:function(){var e,t=this,i=this.$element[0],s=this.setPlaceholder()&&0===i.selectedIndex,n=O(i,this.options.hideDisabled),o=n.length,r=this.$button[0],l=r.querySelector(".filter-option-inner-inner"),a=document.createTextNode(this.options.multipleSeparator),c=_.fragment.cloneNode(!1),d=!1;if(r.classList.toggle("bs-placeholder",t.multiple?!o:!z(i,n)),t.multiple||1!==n.length||(t.selectpicker.view.displayedValue=z(i,n)),"static"===this.options.selectedTextFormat)c=K.text.call(this,{text:this.options.title},!0);else if(!1===(this.multiple&&-1!==this.options.selectedTextFormat.indexOf("count")&&1<o&&(1<(e=this.options.selectedTextFormat.split(">")).length&&o>e[1]||1===e.length&&2<=o))){if(!s){for(var h=0;h<o&&h<50;h++){var p=n[h],u=this.selectpicker.main.data[p.liIndex],f={};this.multiple&&0<h&&c.appendChild(a.cloneNode(!1)),p.title?f.text=p.title:u&&(u.content&&t.options.showContent?(f.content=u.content.toString(),d=!0):(t.options.showIcon&&(f.icon=u.icon),t.options.showSubtext&&!t.multiple&&u.subtext&&(f.subtext=" "+u.subtext),f.text=p.textContent.trim())),c.appendChild(K.text.call(this,f,!0))}49<o&&c.appendChild(document.createTextNode("..."))}}else{var m=':not([hidden]):not([data-hidden="true"]):not([data-divider="true"])';this.options.hideDisabled&&(m+=":not(:disabled)");var v=this.$element[0].querySelectorAll("select > option"+m+", optgroup"+m+" option"+m).length,g="function"==typeof this.options.countSelectedText?this.options.countSelectedText(o,v):this.options.countSelectedText;c=K.text.call(this,{text:g.replace("{0}",o.toString()).replace("{1}",v.toString())},!0)}if(null==this.options.title&&(this.options.title=this.$element.attr("title")),c.childNodes.length||(c=K.text.call(this,{text:void 0!==this.options.title?this.options.title:this.options.noneSelectedText},!0)),r.title=c.textContent.replace(/<[^>]*>?/g,"").trim(),this.options.sanitize&&d&&W([c],t.options.whiteList,t.options.sanitizeFn),l.innerHTML="",l.appendChild(c),M.major<4&&this.$newElement[0].classList.contains("bs3-has-addon")){var b=r.querySelector(".filter-expand"),w=l.cloneNode(!0);w.className="filter-expand",b?r.replaceChild(w,b):r.appendChild(w)}this.$element.trigger("rendered"+j)},setStyle:function(e,t){var i,s=this.$button[0],n=this.$newElement[0],o=this.options.style.trim();this.$element.attr("class")&&this.$newElement.addClass(this.$element.attr("class").replace(/selectpicker|mobile-device|bs-select-hidden|validate\[.*\]/gi,"")),M.major<4&&(n.classList.add("bs3"),n.parentNode.classList&&n.parentNode.classList.contains("input-group")&&(n.previousElementSibling||n.nextElementSibling)&&(n.previousElementSibling||n.nextElementSibling).classList.contains("input-group-addon")&&n.classList.add("bs3-has-addon")),i=e?e.trim():o,"add"==t?i&&s.classList.add.apply(s.classList,i.split(" ")):"remove"==t?i&&s.classList.remove.apply(s.classList,i.split(" ")):(o&&s.classList.remove.apply(s.classList,o.split(" ")),i&&s.classList.add.apply(s.classList,i.split(" ")))},liHeight:function(e){if(e||!1!==this.options.size&&!Object.keys(this.sizeInfo).length){var t,i=_.div.cloneNode(!1),s=_.div.cloneNode(!1),n=_.div.cloneNode(!1),o=document.createElement("ul"),r=_.li.cloneNode(!1),l=_.li.cloneNode(!1),a=_.a.cloneNode(!1),c=_.span.cloneNode(!1),d=this.options.header&&0<this.$menu.find("."+V.POPOVERHEADER).length?this.$menu.find("."+V.POPOVERHEADER)[0].cloneNode(!0):null,h=this.options.liveSearch?_.div.cloneNode(!1):null,p=this.options.actionsBox&&this.multiple&&0<this.$menu.find(".bs-actionsbox").length?this.$menu.find(".bs-actionsbox")[0].cloneNode(!0):null,u=this.options.doneButton&&this.multiple&&0<this.$menu.find(".bs-donebutton").length?this.$menu.find(".bs-donebutton")[0].cloneNode(!0):null,f=this.$element.find("option")[0];if(this.sizeInfo.selectWidth=this.$newElement[0].offsetWidth,c.className="text",a.className="dropdown-item "+(f?f.className:""),i.className=this.$menu[0].parentNode.className+" "+V.SHOW,i.style.width=0,"auto"===this.options.width&&(s.style.minWidth=0),s.className=V.MENU+" "+V.SHOW,n.className="inner "+V.SHOW,o.className=V.MENU+" inner "+("4"===M.major?V.SHOW:""),r.className=V.DIVIDER,l.className="dropdown-header",c.appendChild(document.createTextNode("\u200b")),this.selectpicker.current.data.length)for(var m=0;m<this.selectpicker.current.data.length;m++){var v=this.selectpicker.current.data[m];if("option"===v.type){t=v.element;break}}else t=_.li.cloneNode(!1),a.appendChild(c),t.appendChild(a);if(l.appendChild(c.cloneNode(!0)),this.selectpicker.view.widestOption&&o.appendChild(this.selectpicker.view.widestOption.cloneNode(!0)),o.appendChild(t),o.appendChild(r),o.appendChild(l),d&&s.appendChild(d),h){var g=document.createElement("input");h.className="bs-searchbox",g.className="form-control",h.appendChild(g),s.appendChild(h)}p&&s.appendChild(p),n.appendChild(o),s.appendChild(n),u&&s.appendChild(u),i.appendChild(s),document.body.appendChild(i);var b,w=t.offsetHeight,I=l?l.offsetHeight:0,x=d?d.offsetHeight:0,k=h?h.offsetHeight:0,y=p?p.offsetHeight:0,$=u?u.offsetHeight:0,S=P(r).outerHeight(!0),E=!!window.getComputedStyle&&window.getComputedStyle(s),C=s.offsetWidth,O=E?null:P(s),z={vert:N(E?E.paddingTop:O.css("paddingTop"))+N(E?E.paddingBottom:O.css("paddingBottom"))+N(E?E.borderTopWidth:O.css("borderTopWidth"))+N(E?E.borderBottomWidth:O.css("borderBottomWidth")),horiz:N(E?E.paddingLeft:O.css("paddingLeft"))+N(E?E.paddingRight:O.css("paddingRight"))+N(E?E.borderLeftWidth:O.css("borderLeftWidth"))+N(E?E.borderRightWidth:O.css("borderRightWidth"))},T={vert:z.vert+N(E?E.marginTop:O.css("marginTop"))+N(E?E.marginBottom:O.css("marginBottom"))+2,horiz:z.horiz+N(E?E.marginLeft:O.css("marginLeft"))+N(E?E.marginRight:O.css("marginRight"))+2};n.style.overflowY="scroll",b=s.offsetWidth-C,document.body.removeChild(i),this.sizeInfo.liHeight=w,this.sizeInfo.dropdownHeaderHeight=I,this.sizeInfo.headerHeight=x,this.sizeInfo.searchHeight=k,this.sizeInfo.actionsHeight=y,this.sizeInfo.doneButtonHeight=$,this.sizeInfo.dividerHeight=S,this.sizeInfo.menuPadding=z,this.sizeInfo.menuExtras=T,this.sizeInfo.menuWidth=C,this.sizeInfo.menuInnerInnerWidth=C-z.horiz,this.sizeInfo.totalMenuWidth=this.sizeInfo.menuWidth,this.sizeInfo.scrollBarWidth=b,this.sizeInfo.selectHeight=this.$newElement[0].offsetHeight,this.setPositionData()}},getSelectPosition:function(){var e,t=P(window),i=this.$newElement.offset(),s=P(this.options.container);this.options.container&&s.length&&!s.is("body")?((e=s.offset()).top+=parseInt(s.css("borderTopWidth")),e.left+=parseInt(s.css("borderLeftWidth"))):e={top:0,left:0};var n=this.options.windowPadding;this.sizeInfo.selectOffsetTop=i.top-e.top-t.scrollTop(),this.sizeInfo.selectOffsetBot=t.height()-this.sizeInfo.selectOffsetTop-this.sizeInfo.selectHeight-e.top-n[2],this.sizeInfo.selectOffsetLeft=i.left-e.left-t.scrollLeft(),this.sizeInfo.selectOffsetRight=t.width()-this.sizeInfo.selectOffsetLeft-this.sizeInfo.selectWidth-e.left-n[1],this.sizeInfo.selectOffsetTop-=n[0],this.sizeInfo.selectOffsetLeft-=n[3]},setMenuSize:function(e){this.getSelectPosition();var t,i,s,n,o,r,l,a,c=this.sizeInfo.selectWidth,d=this.sizeInfo.liHeight,h=this.sizeInfo.headerHeight,p=this.sizeInfo.searchHeight,u=this.sizeInfo.actionsHeight,f=this.sizeInfo.doneButtonHeight,m=this.sizeInfo.dividerHeight,v=this.sizeInfo.menuPadding,g=0;if(this.options.dropupAuto&&(l=d*this.selectpicker.current.elements.length+v.vert,a=this.sizeInfo.selectOffsetTop-this.sizeInfo.selectOffsetBot>this.sizeInfo.menuExtras.vert&&l+this.sizeInfo.menuExtras.vert+50>this.sizeInfo.selectOffsetBot,!0===this.selectpicker.isSearching&&(a=this.selectpicker.dropup),this.$newElement.toggleClass(V.DROPUP,a),this.selectpicker.dropup=a),"auto"===this.options.size)n=3<this.selectpicker.current.elements.length?3*this.sizeInfo.liHeight+this.sizeInfo.menuExtras.vert-2:0,i=this.sizeInfo.selectOffsetBot-this.sizeInfo.menuExtras.vert,s=n+h+p+u+f,r=Math.max(n-v.vert,0),this.$newElement.hasClass(V.DROPUP)&&(i=this.sizeInfo.selectOffsetTop-this.sizeInfo.menuExtras.vert),t=(o=i)-h-p-u-f-v.vert;else if(this.options.size&&"auto"!=this.options.size&&this.selectpicker.current.elements.length>this.options.size){for(var b=0;b<this.options.size;b++)"divider"===this.selectpicker.current.data[b].type&&g++;t=(i=d*this.options.size+g*m+v.vert)-v.vert,o=i+h+p+u+f,s=r=""}this.$menu.css({"max-height":o+"px",overflow:"hidden","min-height":s+"px"}),this.$menuInner.css({"max-height":t+"px","overflow-y":"auto","min-height":r+"px"}),this.sizeInfo.menuInnerHeight=Math.max(t,1),this.selectpicker.current.data.length&&this.selectpicker.current.data[this.selectpicker.current.data.length-1].position>this.sizeInfo.menuInnerHeight&&(this.sizeInfo.hasScrollBar=!0,this.sizeInfo.totalMenuWidth=this.sizeInfo.menuWidth+this.sizeInfo.scrollBarWidth),"auto"===this.options.dropdownAlignRight&&this.$menu.toggleClass(V.MENURIGHT,this.sizeInfo.selectOffsetLeft>this.sizeInfo.selectOffsetRight&&this.sizeInfo.selectOffsetRight<this.sizeInfo.totalMenuWidth-c),this.dropdown&&this.dropdown._popper&&this.dropdown._popper.update()},setSize:function(e){if(this.liHeight(e),this.options.header&&this.$menu.css("padding-top",0),!1!==this.options.size){var t=this,i=P(window);this.setMenuSize(),this.options.liveSearch&&this.$searchbox.off("input.setMenuSize propertychange.setMenuSize").on("input.setMenuSize propertychange.setMenuSize",function(){return t.setMenuSize()}),"auto"===this.options.size?i.off("resize"+j+"."+this.selectId+".setMenuSize scroll"+j+"."+this.selectId+".setMenuSize").on("resize"+j+"."+this.selectId+".setMenuSize scroll"+j+"."+this.selectId+".setMenuSize",function(){return t.setMenuSize()}):this.options.size&&"auto"!=this.options.size&&this.selectpicker.current.elements.length>this.options.size&&i.off("resize"+j+"."+this.selectId+".setMenuSize scroll"+j+"."+this.selectId+".setMenuSize")}this.createView(!1,!0,e)},setWidth:function(){var i=this;"auto"===this.options.width?requestAnimationFrame(function(){i.$menu.css("min-width","0"),i.$element.on("loaded"+j,function(){i.liHeight(),i.setMenuSize();var e=i.$newElement.clone().appendTo("body"),t=e.css("width","auto").children("button").outerWidth();e.remove(),i.sizeInfo.selectWidth=Math.max(i.sizeInfo.totalMenuWidth,t),i.$newElement.css("width",i.sizeInfo.selectWidth+"px")})}):"fit"===this.options.width?(this.$menu.css("min-width",""),this.$newElement.css("width","").addClass("fit-width")):this.options.width?(this.$menu.css("min-width",""),this.$newElement.css("width",this.options.width)):(this.$menu.css("min-width",""),this.$newElement.css("width","")),this.$newElement.hasClass("fit-width")&&"fit"!==this.options.width&&this.$newElement[0].classList.remove("fit-width")},selectPosition:function(){this.$bsContainer=P('<div class="bs-container" />');function e(e){var t={},i=r.options.display||!!P.fn.dropdown.Constructor.Default&&P.fn.dropdown.Constructor.Default.display;r.$bsContainer.addClass(e.attr("class").replace(/form-control|fit-width/gi,"")).toggleClass(V.DROPUP,e.hasClass(V.DROPUP)),s=e.offset(),l.is("body")?n={top:0,left:0}:((n=l.offset()).top+=parseInt(l.css("borderTopWidth"))-l.scrollTop(),n.left+=parseInt(l.css("borderLeftWidth"))-l.scrollLeft()),o=e.hasClass(V.DROPUP)?0:e[0].offsetHeight,(M.major<4||"static"===i)&&(t.top=s.top-n.top+o,t.left=s.left-n.left),t.width=e[0].offsetWidth,r.$bsContainer.css(t)}var s,n,o,r=this,l=P(this.options.container);this.$button.on("click.bs.dropdown.data-api",function(){r.isDisabled()||(e(r.$newElement),r.$bsContainer.appendTo(r.options.container).toggleClass(V.SHOW,!r.$button.hasClass(V.SHOW)).append(r.$menu))}),P(window).off("resize"+j+"."+this.selectId+" scroll"+j+"."+this.selectId).on("resize"+j+"."+this.selectId+" scroll"+j+"."+this.selectId,function(){r.$newElement.hasClass(V.SHOW)&&e(r.$newElement)}),this.$element.on("hide"+j,function(){r.$menu.data("height",r.$menu.height()),r.$bsContainer.detach()})},setOptionStatus:function(e){var t=this;if(t.noScroll=!1,t.selectpicker.view.visibleElements&&t.selectpicker.view.visibleElements.length)for(var i=0;i<t.selectpicker.view.visibleElements.length;i++){var s=t.selectpicker.current.data[i+t.selectpicker.view.position0],n=s.option;n&&(!0!==e&&t.setDisabled(s.index,s.disabled),t.setSelected(s.index,n.selected))}},setSelected:function(e,t){var i,s,n=this.selectpicker.main.elements[e],o=this.selectpicker.main.data[e],r=void 0!==this.activeIndex,l=this.activeIndex===e||t&&!this.multiple&&!r;o.selected=t,s=n.firstChild,t&&(this.selectedIndex=e),n.classList.toggle("selected",t),l?(this.focusItem(n,o),this.selectpicker.view.currentActive=n,this.activeIndex=e):this.defocusItem(n),s&&(s.classList.toggle("selected",t),t?s.setAttribute("aria-selected",!0):this.multiple?s.setAttribute("aria-selected",!1):s.removeAttribute("aria-selected")),l||r||!t||void 0===this.prevActiveIndex||(i=this.selectpicker.main.elements[this.prevActiveIndex],this.defocusItem(i))},setDisabled:function(e,t){var i,s=this.selectpicker.main.elements[e];this.selectpicker.main.data[e].disabled=t,i=s.firstChild,s.classList.toggle(V.DISABLED,t),i&&("4"===M.major&&i.classList.toggle(V.DISABLED,t),t?(i.setAttribute("aria-disabled",t),i.setAttribute("tabindex",-1)):(i.removeAttribute("aria-disabled"),i.setAttribute("tabindex",0)))},isDisabled:function(){return this.$element[0].disabled},checkDisabled:function(){this.isDisabled()?(this.$newElement[0].classList.add(V.DISABLED),this.$button.addClass(V.DISABLED).attr("aria-disabled",!0)):this.$button[0].classList.contains(V.DISABLED)&&(this.$newElement[0].classList.remove(V.DISABLED),this.$button.removeClass(V.DISABLED).attr("aria-disabled",!1))},clickListener:function(){var C=this,t=P(document);function e(){C.options.liveSearch?C.$searchbox.trigger("focus"):C.$menuInner.trigger("focus")}function i(){C.dropdown&&C.dropdown._popper&&C.dropdown._popper.state.isCreated?e():requestAnimationFrame(i)}t.data("spaceSelect",!1),this.$button.on("keyup",function(e){/(32)/.test(e.keyCode.toString(10))&&t.data("spaceSelect")&&(e.preventDefault(),t.data("spaceSelect",!1))}),this.$newElement.on("show.bs.dropdown",function(){3<M.major&&!C.dropdown&&(C.dropdown=C.$button.data("bs.dropdown"),C.dropdown._menu=C.$menu[0])}),this.$button.on("click.bs.dropdown.data-api",function(){C.$newElement.hasClass(V.SHOW)||C.setSize()}),this.$element.on("shown"+j,function(){C.$menuInner[0].scrollTop!==C.selectpicker.view.scrollTop&&(C.$menuInner[0].scrollTop=C.selectpicker.view.scrollTop),3<M.major?requestAnimationFrame(i):e()}),this.$menuInner.on("mouseenter","li a",function(e){var t=this.parentElement,i=C.isVirtual()?C.selectpicker.view.position0:0,s=Array.prototype.indexOf.call(t.parentElement.children,t),n=C.selectpicker.current.data[s+i];C.focusItem(t,n,!0)}),this.$menuInner.on("click","li a",function(e,t){var i=P(this),s=C.$element[0],n=C.isVirtual()?C.selectpicker.view.position0:0,o=C.selectpicker.current.data[i.parent().index()+n],r=o.index,l=z(s),a=s.selectedIndex,c=s.options[a],d=!0;if(C.multiple&&1!==C.options.maxOptions&&e.stopPropagation(),e.preventDefault(),!C.isDisabled()&&!i.parent().hasClass(V.DISABLED)){var h=o.option,p=P(h),u=h.selected,f=p.parent("optgroup"),m=f.find("option"),v=C.options.maxOptions,g=f.data("maxOptions")||!1;if(r===C.activeIndex&&(t=!0),t||(C.prevActiveIndex=C.activeIndex,C.activeIndex=void 0),C.multiple){if(h.selected=!u,C.setSelected(r,!u),C.focusedParent.focus(),!1!==v||!1!==g){var b=v<O(s).length,w=g<f.find("option:selected").length;if(v&&b||g&&w)if(v&&1==v)s.selectedIndex=-1,h.selected=!0,C.setOptionStatus(!0);else if(g&&1==g){for(var I=0;I<m.length;I++){var x=m[I];x.selected=!1,C.setSelected(x.liIndex,!1)}h.selected=!0,C.setSelected(r,!0)}else{var k="string"==typeof C.options.maxOptionsText?[C.options.maxOptionsText,C.options.maxOptionsText]:C.options.maxOptionsText,y="function"==typeof k?k(v,g):k,$=y[0].replace("{n}",v),S=y[1].replace("{n}",g),E=P('<div class="notify"></div>');y[2]&&($=$.replace("{var}",y[2][1<v?0:1]),S=S.replace("{var}",y[2][1<g?0:1])),h.selected=!1,C.$menu.append(E),v&&b&&(E.append(P("<div>"+$+"</div>")),d=!1,C.$element.trigger("maxReached"+j)),g&&w&&(E.append(P("<div>"+S+"</div>")),d=!1,C.$element.trigger("maxReachedGrp"+j)),setTimeout(function(){C.setSelected(r,!1)},10),E[0].classList.add("fadeOut"),setTimeout(function(){E.remove()},1050)}}}else c&&(c.selected=!1),h.selected=!0,C.setSelected(r,!0);!C.multiple||C.multiple&&1===C.options.maxOptions?C.$button.trigger("focus"):C.options.liveSearch&&C.$searchbox.trigger("focus"),d&&(!C.multiple&&a===s.selectedIndex||(T=[h.index,p.prop("selected"),l],C.$element.triggerNative("change")))}}),this.$menu.on("click","li."+V.DISABLED+" a, ."+V.POPOVERHEADER+", ."+V.POPOVERHEADER+" :not(.close)",function(e){e.currentTarget==this&&(e.preventDefault(),e.stopPropagation(),C.options.liveSearch&&!P(e.target).hasClass("close")?C.$searchbox.trigger("focus"):C.$button.trigger("focus"))}),this.$menuInner.on("click",".divider, .dropdown-header",function(e){e.preventDefault(),e.stopPropagation(),C.options.liveSearch?C.$searchbox.trigger("focus"):C.$button.trigger("focus")}),this.$menu.on("click","."+V.POPOVERHEADER+" .close",function(){C.$button.trigger("click")}),this.$searchbox.on("click",function(e){e.stopPropagation()}),this.$menu.on("click",".actions-btn",function(e){C.options.liveSearch?C.$searchbox.trigger("focus"):C.$button.trigger("focus"),e.preventDefault(),e.stopPropagation(),P(this).hasClass("bs-select-all")?C.selectAll():C.deselectAll()}),this.$button.on("focus"+j,function(e){var t=C.$element[0].getAttribute("tabindex");void 0!==t&&e.originalEvent&&e.originalEvent.isTrusted&&(this.setAttribute("tabindex",t),C.$element[0].setAttribute("tabindex",-1),C.selectpicker.view.tabindex=t)}).on("blur"+j,function(e){void 0!==C.selectpicker.view.tabindex&&e.originalEvent&&e.originalEvent.isTrusted&&(C.$element[0].setAttribute("tabindex",C.selectpicker.view.tabindex),this.setAttribute("tabindex",-1),C.selectpicker.view.tabindex=void 0)}),this.$element.on("change"+j,function(){C.render(),C.$element.trigger("changed"+j,T),T=null}).on("focus"+j,function(){C.options.mobile||C.$button[0].focus()})},liveSearchListener:function(){var u=this;this.$button.on("click.bs.dropdown.data-api",function(){u.$searchbox.val()&&(u.$searchbox.val(""),u.selectpicker.search.previousValue=void 0)}),this.$searchbox.on("click.bs.dropdown.data-api focus.bs.dropdown.data-api touchend.bs.dropdown.data-api",function(e){e.stopPropagation()}),this.$searchbox.on("input propertychange",function(){var e=u.$searchbox[0].value;if(u.selectpicker.search.elements=[],u.selectpicker.search.data=[],e){var t=[],i=e.toUpperCase(),s={},n=[],o=u._searchStyle(),r=u.options.liveSearchNormalize;r&&(i=w(i));for(var l=0;l<u.selectpicker.main.data.length;l++){var a=u.selectpicker.main.data[l];s[l]||(s[l]=k(a,i,o,r)),s[l]&&void 0!==a.headerIndex&&-1===n.indexOf(a.headerIndex)&&(0<a.headerIndex&&(s[a.headerIndex-1]=!0,n.push(a.headerIndex-1)),s[a.headerIndex]=!0,n.push(a.headerIndex),s[a.lastIndex+1]=!0),s[l]&&"optgroup-label"!==a.type&&n.push(l)}l=0;for(var c=n.length;l<c;l++){var d=n[l],h=n[l-1],p=(a=u.selectpicker.main.data[d],u.selectpicker.main.data[h]);("divider"!==a.type||"divider"===a.type&&p&&"divider"!==p.type&&c-1!==l)&&(u.selectpicker.search.data.push(a),t.push(u.selectpicker.main.elements[d]))}u.activeIndex=void 0,u.noScroll=!0,u.$menuInner.scrollTop(0),u.selectpicker.search.elements=t,u.createView(!0),function(e,t){e.length||(_.noResults.innerHTML=this.options.noneResultsText.replace("{0}",'"'+S(t)+'"'),this.$menuInner[0].firstChild.appendChild(_.noResults))}.call(u,t,e)}else u.selectpicker.search.previousValue&&(u.$menuInner.scrollTop(0),u.createView(!1));u.selectpicker.search.previousValue=e})},_searchStyle:function(){return this.options.liveSearchStyle||"contains"},val:function(e){var t=this.$element[0];if(void 0===e)return this.$element.val();var i=z(t);if(T=[null,null,i],this.$element.val(e).trigger("changed"+j,T),this.$newElement.hasClass(V.SHOW))if(this.multiple)this.setOptionStatus(!0);else{var s=(t.options[t.selectedIndex]||{}).liIndex;"number"==typeof s&&(this.setSelected(this.selectedIndex,!1),this.setSelected(s,!0))}return this.render(),T=null,this.$element},changeAll:function(e){if(this.multiple){void 0===e&&(e=!0);var t=this.$element[0],i=0,s=0,n=z(t);t.classList.add("bs-select-hidden");for(var o=0,r=this.selectpicker.current.data,l=r.length;o<l;o++){var a=r[o],c=a.option;c&&!a.disabled&&"divider"!==a.type&&(a.selected&&i++,!0===(c.selected=e)&&s++)}t.classList.remove("bs-select-hidden"),i!==s&&(this.setOptionStatus(),T=[null,null,n],this.$element.triggerNative("change"))}},selectAll:function(){return this.changeAll(!0)},deselectAll:function(){return this.changeAll(!1)},toggle:function(e){(e=e||window.event)&&e.stopPropagation(),this.$button.trigger("click.bs.dropdown.data-api")},keydown:function(e){var t,i,s,n,o,r=P(this),l=r.hasClass("dropdown-toggle"),a=(l?r.closest(".dropdown"):r.closest(F.MENU)).data("this"),c=a.findLis(),d=!1,h=e.which===H&&!l&&!a.options.selectOnTab,p=G.test(e.which)||h,u=a.$menuInner[0].scrollTop,f=!0===a.isVirtual()?a.selectpicker.view.position0:0;if(!(112<=e.which&&e.which<=123))if(!(i=a.$newElement.hasClass(V.SHOW))&&(p||48<=e.which&&e.which<=57||96<=e.which&&e.which<=105||65<=e.which&&e.which<=90)&&(a.$button.trigger("click.bs.dropdown.data-api"),a.options.liveSearch))a.$searchbox.trigger("focus");else{if(e.which===A&&i&&(e.preventDefault(),a.$button.trigger("click.bs.dropdown.data-api").trigger("focus")),p){if(!c.length)return;-1!==(t=(s=a.selectpicker.main.elements[a.activeIndex])?Array.prototype.indexOf.call(s.parentElement.children,s):-1)&&a.defocusItem(s),e.which===B?(-1!==t&&t--,t+f<0&&(t+=c.length),a.selectpicker.view.canHighlight[t+f]||-1===(t=a.selectpicker.view.canHighlight.slice(0,t+f).lastIndexOf(!0)-f)&&(t=c.length-1)):e.which!==R&&!h||(++t+f>=a.selectpicker.view.canHighlight.length&&(t=a.selectpicker.view.firstHighlightIndex),a.selectpicker.view.canHighlight[t+f]||(t=t+1+a.selectpicker.view.canHighlight.slice(t+f+1).indexOf(!0))),e.preventDefault();var m=f+t;e.which===B?0===f&&t===c.length-1?(a.$menuInner[0].scrollTop=a.$menuInner[0].scrollHeight,m=a.selectpicker.current.elements.length-1):d=(o=(n=a.selectpicker.current.data[m]).position-n.height)<u:e.which!==R&&!h||(t===a.selectpicker.view.firstHighlightIndex?(a.$menuInner[0].scrollTop=0,m=a.selectpicker.view.firstHighlightIndex):d=u<(o=(n=a.selectpicker.current.data[m]).position-a.sizeInfo.menuInnerHeight)),s=a.selectpicker.current.elements[m],a.activeIndex=a.selectpicker.current.data[m].index,a.focusItem(s),a.selectpicker.view.currentActive=s,d&&(a.$menuInner[0].scrollTop=o),a.options.liveSearch?a.$searchbox.trigger("focus"):r.trigger("focus")}else if(!r.is("input")&&!q.test(e.which)||e.which===D&&a.selectpicker.keydown.keyHistory){var v,g,b=[];e.preventDefault(),a.selectpicker.keydown.keyHistory+=C[e.which],a.selectpicker.keydown.resetKeyHistory.cancel&&clearTimeout(a.selectpicker.keydown.resetKeyHistory.cancel),a.selectpicker.keydown.resetKeyHistory.cancel=a.selectpicker.keydown.resetKeyHistory.start(),g=a.selectpicker.keydown.keyHistory,/^(.)\1+$/.test(g)&&(g=g.charAt(0));for(var w=0;w<a.selectpicker.current.data.length;w++){var I=a.selectpicker.current.data[w];k(I,g,"startsWith",!0)&&a.selectpicker.view.canHighlight[w]&&b.push(I.index)}if(b.length){var x=0;c.removeClass("active").find("a").removeClass("active"),1===g.length&&(-1===(x=b.indexOf(a.activeIndex))||x===b.length-1?x=0:x++),v=b[x],d=0<u-(n=a.selectpicker.main.data[v]).position?(o=n.position-n.height,!0):(o=n.position-a.sizeInfo.menuInnerHeight,n.position>u+a.sizeInfo.menuInnerHeight),s=a.selectpicker.main.elements[v],a.activeIndex=b[x],a.focusItem(s),s&&s.firstChild.focus(),d&&(a.$menuInner[0].scrollTop=o),r.trigger("focus")}}i&&(e.which===D&&!a.selectpicker.keydown.keyHistory||e.which===L||e.which===H&&a.options.selectOnTab)&&(e.which!==D&&e.preventDefault(),a.options.liveSearch&&e.which===D||(a.$menuInner.find(".active a").trigger("click",!0),r.trigger("focus"),a.options.liveSearch||(e.preventDefault(),P(document).data("spaceSelect",!0))))}},mobile:function(){this.options.mobile=!0,this.$element[0].classList.add("mobile-device")},refresh:function(){var e=P.extend({},this.options,this.$element.data());this.options=e,this.checkDisabled(),this.buildData(),this.setStyle(),this.render(),this.buildList(),this.setWidth(),this.setSize(!0),this.$element.trigger("refreshed"+j)},hide:function(){this.$newElement.hide()},show:function(){this.$newElement.show()},remove:function(){this.$newElement.remove(),this.$element.remove()},destroy:function(){this.$newElement.before(this.$element).remove(),this.$bsContainer?this.$bsContainer.remove():this.$menu.remove(),this.selectpicker.view.titleOption&&this.selectpicker.view.titleOption.parentNode&&this.selectpicker.view.titleOption.parentNode.removeChild(this.selectpicker.view.titleOption),this.$element.off(j).removeData("selectpicker").removeClass("bs-select-hidden selectpicker"),P(window).off(j+"."+this.selectId)}};var J=P.fn.selectpicker;function Q(){if(P.fn.dropdown)return(P.fn.dropdown.Constructor._dataApiKeydownHandler||P.fn.dropdown.Constructor.prototype.keydown).apply(this,arguments)}P.fn.selectpicker=Z,P.fn.selectpicker.Constructor=Y,P.fn.selectpicker.noConflict=function(){return P.fn.selectpicker=J,this},P(document).off("keydown.bs.dropdown.data-api").on("keydown.bs.dropdown.data-api",':not(.bootstrap-select) > [data-toggle="dropdown"]',Q).on("keydown.bs.dropdown.data-api",":not(.bootstrap-select) > .dropdown-menu",Q).on("keydown"+j,'.bootstrap-select [data-toggle="dropdown"], .bootstrap-select [role="listbox"], .bootstrap-select .bs-searchbox input',Y.prototype.keydown).on("focusin.modal",'.bootstrap-select [data-toggle="dropdown"], .bootstrap-select [role="listbox"], .bootstrap-select .bs-searchbox input',function(e){e.stopPropagation()}),P(window).on("load"+j+".data-api",function(){P(".selectpicker").each(function(){var e=P(this);Z.call(e,e.data())})})}(e)});
|
9 |
-
//# sourceMappingURL=bootstrap-select.min.js.map
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resources/js/chartist.min.js
DELETED
@@ -1,10 +0,0 @@
|
|
1 |
-
/* Chartist.js 0.11.4
|
2 |
-
* Copyright © 2019 Gion Kunz
|
3 |
-
* Free to use under either the WTFPL license or the MIT license.
|
4 |
-
* https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-WTFPL
|
5 |
-
* https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-MIT
|
6 |
-
*/
|
7 |
-
|
8 |
-
!function(a,b){"function"==typeof define&&define.amd?define("Chartist",[],function(){return a.Chartist=b()}):"object"==typeof module&&module.exports?module.exports=b():a.Chartist=b()}(this,function(){var a={version:"0.11.4"};return function(a,b){"use strict";var c=a.window,d=a.document;b.namespaces={svg:"http://www.w3.org/2000/svg",xmlns:"http://www.w3.org/2000/xmlns/",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",ct:"http://gionkunz.github.com/chartist-js/ct"},b.noop=function(a){return a},b.alphaNumerate=function(a){return String.fromCharCode(97+a%26)},b.extend=function(a){var c,d,e;for(a=a||{},c=1;c<arguments.length;c++){d=arguments[c];for(var f in d)e=d[f],"object"!=typeof e||null===e||e instanceof Array?a[f]=e:a[f]=b.extend(a[f],e)}return a},b.replaceAll=function(a,b,c){return a.replace(new RegExp(b,"g"),c)},b.ensureUnit=function(a,b){return"number"==typeof a&&(a+=b),a},b.quantity=function(a){if("string"==typeof a){var b=/^(\d+)\s*(.*)$/g.exec(a);return{value:+b[1],unit:b[2]||void 0}}return{value:a}},b.querySelector=function(a){return a instanceof Node?a:d.querySelector(a)},b.times=function(a){return Array.apply(null,new Array(a))},b.sum=function(a,b){return a+(b?b:0)},b.mapMultiply=function(a){return function(b){return b*a}},b.mapAdd=function(a){return function(b){return b+a}},b.serialMap=function(a,c){var d=[],e=Math.max.apply(null,a.map(function(a){return a.length}));return b.times(e).forEach(function(b,e){var f=a.map(function(a){return a[e]});d[e]=c.apply(null,f)}),d},b.roundWithPrecision=function(a,c){var d=Math.pow(10,c||b.precision);return Math.round(a*d)/d},b.precision=8,b.escapingMap={"&":"&","<":"<",">":">",'"':""","'":"'"},b.serialize=function(a){return null===a||void 0===a?a:("number"==typeof a?a=""+a:"object"==typeof a&&(a=JSON.stringify({data:a})),Object.keys(b.escapingMap).reduce(function(a,c){return b.replaceAll(a,c,b.escapingMap[c])},a))},b.deserialize=function(a){if("string"!=typeof a)return a;a=Object.keys(b.escapingMap).reduce(function(a,c){return b.replaceAll(a,b.escapingMap[c],c)},a);try{a=JSON.parse(a),a=void 0!==a.data?a.data:a}catch(c){}return a},b.createSvg=function(a,c,d,e){var f;return c=c||"100%",d=d||"100%",Array.prototype.slice.call(a.querySelectorAll("svg")).filter(function(a){return a.getAttributeNS(b.namespaces.xmlns,"ct")}).forEach(function(b){a.removeChild(b)}),f=new b.Svg("svg").attr({width:c,height:d}).addClass(e),f._node.style.width=c,f._node.style.height=d,a.appendChild(f._node),f},b.normalizeData=function(a,c,d){var e,f={raw:a,normalized:{}};return f.normalized.series=b.getDataArray({series:a.series||[]},c,d),e=f.normalized.series.every(function(a){return a instanceof Array})?Math.max.apply(null,f.normalized.series.map(function(a){return a.length})):f.normalized.series.length,f.normalized.labels=(a.labels||[]).slice(),Array.prototype.push.apply(f.normalized.labels,b.times(Math.max(0,e-f.normalized.labels.length)).map(function(){return""})),c&&b.reverseData(f.normalized),f},b.safeHasProperty=function(a,b){return null!==a&&"object"==typeof a&&a.hasOwnProperty(b)},b.isDataHoleValue=function(a){return null===a||void 0===a||"number"==typeof a&&isNaN(a)},b.reverseData=function(a){a.labels.reverse(),a.series.reverse();for(var b=0;b<a.series.length;b++)"object"==typeof a.series[b]&&void 0!==a.series[b].data?a.series[b].data.reverse():a.series[b]instanceof Array&&a.series[b].reverse()},b.getDataArray=function(a,c,d){function e(a){if(b.safeHasProperty(a,"value"))return e(a.value);if(b.safeHasProperty(a,"data"))return e(a.data);if(a instanceof Array)return a.map(e);if(!b.isDataHoleValue(a)){if(d){var c={};return"string"==typeof d?c[d]=b.getNumberOrUndefined(a):c.y=b.getNumberOrUndefined(a),c.x=a.hasOwnProperty("x")?b.getNumberOrUndefined(a.x):c.x,c.y=a.hasOwnProperty("y")?b.getNumberOrUndefined(a.y):c.y,c}return b.getNumberOrUndefined(a)}}return a.series.map(e)},b.normalizePadding=function(a,b){return b=b||0,"number"==typeof a?{top:a,right:a,bottom:a,left:a}:{top:"number"==typeof a.top?a.top:b,right:"number"==typeof a.right?a.right:b,bottom:"number"==typeof a.bottom?a.bottom:b,left:"number"==typeof a.left?a.left:b}},b.getMetaData=function(a,b){var c=a.data?a.data[b]:a[b];return c?c.meta:void 0},b.orderOfMagnitude=function(a){return Math.floor(Math.log(Math.abs(a))/Math.LN10)},b.projectLength=function(a,b,c){return b/c.range*a},b.getAvailableHeight=function(a,c){return Math.max((b.quantity(c.height).value||a.height())-(c.chartPadding.top+c.chartPadding.bottom)-c.axisX.offset,0)},b.getHighLow=function(a,c,d){function e(a){if(void 0!==a)if(a instanceof Array)for(var b=0;b<a.length;b++)e(a[b]);else{var c=d?+a[d]:+a;g&&c>f.high&&(f.high=c),h&&c<f.low&&(f.low=c)}}c=b.extend({},c,d?c["axis"+d.toUpperCase()]:{});var f={high:void 0===c.high?-Number.MAX_VALUE:+c.high,low:void 0===c.low?Number.MAX_VALUE:+c.low},g=void 0===c.high,h=void 0===c.low;return(g||h)&&e(a),(c.referenceValue||0===c.referenceValue)&&(f.high=Math.max(c.referenceValue,f.high),f.low=Math.min(c.referenceValue,f.low)),f.high<=f.low&&(0===f.low?f.high=1:f.low<0?f.high=0:f.high>0?f.low=0:(f.high=1,f.low=0)),f},b.isNumeric=function(a){return null!==a&&isFinite(a)},b.isFalseyButZero=function(a){return!a&&0!==a},b.getNumberOrUndefined=function(a){return b.isNumeric(a)?+a:void 0},b.isMultiValue=function(a){return"object"==typeof a&&("x"in a||"y"in a)},b.getMultiValue=function(a,c){return b.isMultiValue(a)?b.getNumberOrUndefined(a[c||"y"]):b.getNumberOrUndefined(a)},b.rho=function(a){function b(a,c){return a%c===0?c:b(c,a%c)}function c(a){return a*a+1}if(1===a)return a;var d,e=2,f=2;if(a%2===0)return 2;do e=c(e)%a,f=c(c(f))%a,d=b(Math.abs(e-f),a);while(1===d);return d},b.getBounds=function(a,c,d,e){function f(a,b){return a===(a+=b)&&(a*=1+(b>0?o:-o)),a}var g,h,i,j=0,k={high:c.high,low:c.low};k.valueRange=k.high-k.low,k.oom=b.orderOfMagnitude(k.valueRange),k.step=Math.pow(10,k.oom),k.min=Math.floor(k.low/k.step)*k.step,k.max=Math.ceil(k.high/k.step)*k.step,k.range=k.max-k.min,k.numberOfSteps=Math.round(k.range/k.step);var l=b.projectLength(a,k.step,k),m=l<d,n=e?b.rho(k.range):0;if(e&&b.projectLength(a,1,k)>=d)k.step=1;else if(e&&n<k.step&&b.projectLength(a,n,k)>=d)k.step=n;else for(;;){if(m&&b.projectLength(a,k.step,k)<=d)k.step*=2;else{if(m||!(b.projectLength(a,k.step/2,k)>=d))break;if(k.step/=2,e&&k.step%1!==0){k.step*=2;break}}if(j++>1e3)throw new Error("Exceeded maximum number of iterations while optimizing scale step!")}var o=2.221e-16;for(k.step=Math.max(k.step,o),h=k.min,i=k.max;h+k.step<=k.low;)h=f(h,k.step);for(;i-k.step>=k.high;)i=f(i,-k.step);k.min=h,k.max=i,k.range=k.max-k.min;var p=[];for(g=k.min;g<=k.max;g=f(g,k.step)){var q=b.roundWithPrecision(g);q!==p[p.length-1]&&p.push(q)}return k.values=p,k},b.polarToCartesian=function(a,b,c,d){var e=(d-90)*Math.PI/180;return{x:a+c*Math.cos(e),y:b+c*Math.sin(e)}},b.createChartRect=function(a,c,d){var e=!(!c.axisX&&!c.axisY),f=e?c.axisY.offset:0,g=e?c.axisX.offset:0,h=a.width()||b.quantity(c.width).value||0,i=a.height()||b.quantity(c.height).value||0,j=b.normalizePadding(c.chartPadding,d);h=Math.max(h,f+j.left+j.right),i=Math.max(i,g+j.top+j.bottom);var k={padding:j,width:function(){return this.x2-this.x1},height:function(){return this.y1-this.y2}};return e?("start"===c.axisX.position?(k.y2=j.top+g,k.y1=Math.max(i-j.bottom,k.y2+1)):(k.y2=j.top,k.y1=Math.max(i-j.bottom-g,k.y2+1)),"start"===c.axisY.position?(k.x1=j.left+f,k.x2=Math.max(h-j.right,k.x1+1)):(k.x1=j.left,k.x2=Math.max(h-j.right-f,k.x1+1))):(k.x1=j.left,k.x2=Math.max(h-j.right,k.x1+1),k.y2=j.top,k.y1=Math.max(i-j.bottom,k.y2+1)),k},b.createGrid=function(a,c,d,e,f,g,h,i){var j={};j[d.units.pos+"1"]=a,j[d.units.pos+"2"]=a,j[d.counterUnits.pos+"1"]=e,j[d.counterUnits.pos+"2"]=e+f;var k=g.elem("line",j,h.join(" "));i.emit("draw",b.extend({type:"grid",axis:d,index:c,group:g,element:k},j))},b.createGridBackground=function(a,b,c,d){var e=a.elem("rect",{x:b.x1,y:b.y2,width:b.width(),height:b.height()},c,!0);d.emit("draw",{type:"gridBackground",group:a,element:e})},b.createLabel=function(a,c,e,f,g,h,i,j,k,l,m){var n,o={};if(o[g.units.pos]=a+i[g.units.pos],o[g.counterUnits.pos]=i[g.counterUnits.pos],o[g.units.len]=c,o[g.counterUnits.len]=Math.max(0,h-10),l){var p=d.createElement("span");p.className=k.join(" "),p.setAttribute("xmlns",b.namespaces.xhtml),p.innerText=f[e],p.style[g.units.len]=Math.round(o[g.units.len])+"px",p.style[g.counterUnits.len]=Math.round(o[g.counterUnits.len])+"px",n=j.foreignObject(p,b.extend({style:"overflow: visible;"},o))}else n=j.elem("text",o,k.join(" ")).text(f[e]);m.emit("draw",b.extend({type:"label",axis:g,index:e,group:j,element:n,text:f[e]},o))},b.getSeriesOption=function(a,b,c){if(a.name&&b.series&&b.series[a.name]){var d=b.series[a.name];return d.hasOwnProperty(c)?d[c]:b[c]}return b[c]},b.optionsProvider=function(a,d,e){function f(a){var f=h;if(h=b.extend({},j),d)for(i=0;i<d.length;i++){var g=c.matchMedia(d[i][0]);g.matches&&(h=b.extend(h,d[i][1]))}e&&a&&e.emit("optionsChanged",{previousOptions:f,currentOptions:h})}function g(){k.forEach(function(a){a.removeListener(f)})}var h,i,j=b.extend({},a),k=[];if(!c.matchMedia)throw"window.matchMedia not found! Make sure you're using a polyfill.";if(d)for(i=0;i<d.length;i++){var l=c.matchMedia(d[i][0]);l.addListener(f),k.push(l)}return f(),{removeMediaQueryListeners:g,getCurrentOptions:function(){return b.extend({},h)}}},b.splitIntoSegments=function(a,c,d){var e={increasingX:!1,fillHoles:!1};d=b.extend({},e,d);for(var f=[],g=!0,h=0;h<a.length;h+=2)void 0===b.getMultiValue(c[h/2].value)?d.fillHoles||(g=!0):(d.increasingX&&h>=2&&a[h]<=a[h-2]&&(g=!0),g&&(f.push({pathCoordinates:[],valueData:[]}),g=!1),f[f.length-1].pathCoordinates.push(a[h],a[h+1]),f[f.length-1].valueData.push(c[h/2]));return f}}(this||global,a),function(a,b){"use strict";b.Interpolation={},b.Interpolation.none=function(a){var c={fillHoles:!1};return a=b.extend({},c,a),function(c,d){for(var e=new b.Svg.Path,f=!0,g=0;g<c.length;g+=2){var h=c[g],i=c[g+1],j=d[g/2];void 0!==b.getMultiValue(j.value)?(f?e.move(h,i,!1,j):e.line(h,i,!1,j),f=!1):a.fillHoles||(f=!0)}return e}},b.Interpolation.simple=function(a){var c={divisor:2,fillHoles:!1};a=b.extend({},c,a);var d=1/Math.max(1,a.divisor);return function(c,e){for(var f,g,h,i=new b.Svg.Path,j=0;j<c.length;j+=2){var k=c[j],l=c[j+1],m=(k-f)*d,n=e[j/2];void 0!==n.value?(void 0===h?i.move(k,l,!1,n):i.curve(f+m,g,k-m,l,k,l,!1,n),f=k,g=l,h=n):a.fillHoles||(f=k=h=void 0)}return i}},b.Interpolation.cardinal=function(a){var c={tension:1,fillHoles:!1};a=b.extend({},c,a);var d=Math.min(1,Math.max(0,a.tension)),e=1-d;return function f(c,g){var h=b.splitIntoSegments(c,g,{fillHoles:a.fillHoles});if(h.length){if(h.length>1){var i=[];return h.forEach(function(a){i.push(f(a.pathCoordinates,a.valueData))}),b.Svg.Path.join(i)}if(c=h[0].pathCoordinates,g=h[0].valueData,c.length<=4)return b.Interpolation.none()(c,g);for(var j,k=(new b.Svg.Path).move(c[0],c[1],!1,g[0]),l=0,m=c.length;m-2*!j>l;l+=2){var n=[{x:+c[l-2],y:+c[l-1]},{x:+c[l],y:+c[l+1]},{x:+c[l+2],y:+c[l+3]},{x:+c[l+4],y:+c[l+5]}];j?l?m-4===l?n[3]={x:+c[0],y:+c[1]}:m-2===l&&(n[2]={x:+c[0],y:+c[1]},n[3]={x:+c[2],y:+c[3]}):n[0]={x:+c[m-2],y:+c[m-1]}:m-4===l?n[3]=n[2]:l||(n[0]={x:+c[l],y:+c[l+1]}),k.curve(d*(-n[0].x+6*n[1].x+n[2].x)/6+e*n[2].x,d*(-n[0].y+6*n[1].y+n[2].y)/6+e*n[2].y,d*(n[1].x+6*n[2].x-n[3].x)/6+e*n[2].x,d*(n[1].y+6*n[2].y-n[3].y)/6+e*n[2].y,n[2].x,n[2].y,!1,g[(l+2)/2])}return k}return b.Interpolation.none()([])}},b.Interpolation.monotoneCubic=function(a){var c={fillHoles:!1};return a=b.extend({},c,a),function d(c,e){var f=b.splitIntoSegments(c,e,{fillHoles:a.fillHoles,increasingX:!0});if(f.length){if(f.length>1){var g=[];return f.forEach(function(a){g.push(d(a.pathCoordinates,a.valueData))}),b.Svg.Path.join(g)}if(c=f[0].pathCoordinates,e=f[0].valueData,c.length<=4)return b.Interpolation.none()(c,e);var h,i,j=[],k=[],l=c.length/2,m=[],n=[],o=[],p=[];for(h=0;h<l;h++)j[h]=c[2*h],k[h]=c[2*h+1];for(h=0;h<l-1;h++)o[h]=k[h+1]-k[h],p[h]=j[h+1]-j[h],n[h]=o[h]/p[h];for(m[0]=n[0],m[l-1]=n[l-2],h=1;h<l-1;h++)0===n[h]||0===n[h-1]||n[h-1]>0!=n[h]>0?m[h]=0:(m[h]=3*(p[h-1]+p[h])/((2*p[h]+p[h-1])/n[h-1]+(p[h]+2*p[h-1])/n[h]),isFinite(m[h])||(m[h]=0));for(i=(new b.Svg.Path).move(j[0],k[0],!1,e[0]),h=0;h<l-1;h++)i.curve(j[h]+p[h]/3,k[h]+m[h]*p[h]/3,j[h+1]-p[h]/3,k[h+1]-m[h+1]*p[h]/3,j[h+1],k[h+1],!1,e[h+1]);return i}return b.Interpolation.none()([])}},b.Interpolation.step=function(a){var c={postpone:!0,fillHoles:!1};return a=b.extend({},c,a),function(c,d){for(var e,f,g,h=new b.Svg.Path,i=0;i<c.length;i+=2){var j=c[i],k=c[i+1],l=d[i/2];void 0!==l.value?(void 0===g?h.move(j,k,!1,l):(a.postpone?h.line(j,f,!1,g):h.line(e,k,!1,l),h.line(j,k,!1,l)),e=j,f=k,g=l):a.fillHoles||(e=f=g=void 0)}return h}}}(this||global,a),function(a,b){"use strict";b.EventEmitter=function(){function a(a,b){d[a]=d[a]||[],d[a].push(b)}function b(a,b){d[a]&&(b?(d[a].splice(d[a].indexOf(b),1),0===d[a].length&&delete d[a]):delete d[a])}function c(a,b){d[a]&&d[a].forEach(function(a){a(b)}),d["*"]&&d["*"].forEach(function(c){c(a,b)})}var d=[];return{addEventHandler:a,removeEventHandler:b,emit:c}}}(this||global,a),function(a,b){"use strict";function c(a){var b=[];if(a.length)for(var c=0;c<a.length;c++)b.push(a[c]);return b}function d(a,c){var d=c||this.prototype||b.Class,e=Object.create(d);b.Class.cloneDefinitions(e,a);var f=function(){var a,c=e.constructor||function(){};return a=this===b?Object.create(e):this,c.apply(a,Array.prototype.slice.call(arguments,0)),a};return f.prototype=e,f["super"]=d,f.extend=this.extend,f}function e(){var a=c(arguments),b=a[0];return a.splice(1,a.length-1).forEach(function(a){Object.getOwnPropertyNames(a).forEach(function(c){delete b[c],Object.defineProperty(b,c,Object.getOwnPropertyDescriptor(a,c))})}),b}b.Class={extend:d,cloneDefinitions:e}}(this||global,a),function(a,b){"use strict";function c(a,c,d){return a&&(this.data=a||{},this.data.labels=this.data.labels||[],this.data.series=this.data.series||[],this.eventEmitter.emit("data",{type:"update",data:this.data})),c&&(this.options=b.extend({},d?this.options:this.defaultOptions,c),this.initializeTimeoutId||(this.optionsProvider.removeMediaQueryListeners(),this.optionsProvider=b.optionsProvider(this.options,this.responsiveOptions,this.eventEmitter))),this.initializeTimeoutId||this.createChart(this.optionsProvider.getCurrentOptions()),this}function d(){return this.initializeTimeoutId?i.clearTimeout(this.initializeTimeoutId):(i.removeEventListener("resize",this.resizeListener),this.optionsProvider.removeMediaQueryListeners()),this}function e(a,b){return this.eventEmitter.addEventHandler(a,b),this}function f(a,b){return this.eventEmitter.removeEventHandler(a,b),this}function g(){i.addEventListener("resize",this.resizeListener),this.optionsProvider=b.optionsProvider(this.options,this.responsiveOptions,this.eventEmitter),this.eventEmitter.addEventHandler("optionsChanged",function(){this.update()}.bind(this)),this.options.plugins&&this.options.plugins.forEach(function(a){a instanceof Array?a[0](this,a[1]):a(this)}.bind(this)),this.eventEmitter.emit("data",{type:"initial",data:this.data}),this.createChart(this.optionsProvider.getCurrentOptions()),this.initializeTimeoutId=void 0}function h(a,c,d,e,f){this.container=b.querySelector(a),this.data=c||{},this.data.labels=this.data.labels||[],this.data.series=this.data.series||[],this.defaultOptions=d,this.options=e,this.responsiveOptions=f,this.eventEmitter=b.EventEmitter(),this.supportsForeignObject=b.Svg.isSupported("Extensibility"),this.supportsAnimations=b.Svg.isSupported("AnimationEventsAttribute"),this.resizeListener=function(){this.update()}.bind(this),this.container&&(this.container.__chartist__&&this.container.__chartist__.detach(),this.container.__chartist__=this),this.initializeTimeoutId=setTimeout(g.bind(this),0)}var i=a.window;b.Base=b.Class.extend({constructor:h,optionsProvider:void 0,container:void 0,svg:void 0,eventEmitter:void 0,createChart:function(){throw new Error("Base chart type can't be instantiated!")},update:c,detach:d,on:e,off:f,version:b.version,supportsForeignObject:!1})}(this||global,a),function(a,b){"use strict";function c(a,c,d,e,f){a instanceof Element?this._node=a:(this._node=y.createElementNS(b.namespaces.svg,a),"svg"===a&&this.attr({"xmlns:ct":b.namespaces.ct})),c&&this.attr(c),d&&this.addClass(d),e&&(f&&e._node.firstChild?e._node.insertBefore(this._node,e._node.firstChild):e._node.appendChild(this._node))}function d(a,c){return"string"==typeof a?c?this._node.getAttributeNS(c,a):this._node.getAttribute(a):(Object.keys(a).forEach(function(c){if(void 0!==a[c])if(c.indexOf(":")!==-1){var d=c.split(":");this._node.setAttributeNS(b.namespaces[d[0]],c,a[c])}else this._node.setAttribute(c,a[c])}.bind(this)),this)}function e(a,c,d,e){return new b.Svg(a,c,d,this,e)}function f(){return this._node.parentNode instanceof SVGElement?new b.Svg(this._node.parentNode):null}function g(){for(var a=this._node;"svg"!==a.nodeName;)a=a.parentNode;return new b.Svg(a)}function h(a){var c=this._node.querySelector(a);return c?new b.Svg(c):null}function i(a){var c=this._node.querySelectorAll(a);return c.length?new b.Svg.List(c):null}function j(){return this._node}function k(a,c,d,e){if("string"==typeof a){var f=y.createElement("div");f.innerHTML=a,a=f.firstChild}a.setAttribute("xmlns",b.namespaces.xmlns);var g=this.elem("foreignObject",c,d,e);return g._node.appendChild(a),g}function l(a){return this._node.appendChild(y.createTextNode(a)),this}function m(){for(;this._node.firstChild;)this._node.removeChild(this._node.firstChild);return this}function n(){return this._node.parentNode.removeChild(this._node),this.parent()}function o(a){return this._node.parentNode.replaceChild(a._node,this._node),a}function p(a,b){return b&&this._node.firstChild?this._node.insertBefore(a._node,this._node.firstChild):this._node.appendChild(a._node),this}function q(){return this._node.getAttribute("class")?this._node.getAttribute("class").trim().split(/\s+/):[]}function r(a){return this._node.setAttribute("class",this.classes(this._node).concat(a.trim().split(/\s+/)).filter(function(a,b,c){return c.indexOf(a)===b}).join(" ")),this}function s(a){var b=a.trim().split(/\s+/);return this._node.setAttribute("class",this.classes(this._node).filter(function(a){return b.indexOf(a)===-1}).join(" ")),this}function t(){return this._node.setAttribute("class",""),this}function u(){return this._node.getBoundingClientRect().height}function v(){return this._node.getBoundingClientRect().width}function w(a,c,d){return void 0===c&&(c=!0),Object.keys(a).forEach(function(e){function f(a,c){var f,g,h,i={};a.easing&&(h=a.easing instanceof Array?a.easing:b.Svg.Easing[a.easing],delete a.easing),a.begin=b.ensureUnit(a.begin,"ms"),a.dur=b.ensureUnit(a.dur,"ms"),h&&(a.calcMode="spline",a.keySplines=h.join(" "),a.keyTimes="0;1"),c&&(a.fill="freeze",i[e]=a.from,this.attr(i),g=b.quantity(a.begin||0).value,a.begin="indefinite"),f=this.elem("animate",b.extend({attributeName:e},a)),c&&setTimeout(function(){try{f._node.beginElement()}catch(b){i[e]=a.to,this.attr(i),f.remove()}}.bind(this),g),d&&f._node.addEventListener("beginEvent",function(){d.emit("animationBegin",{element:this,animate:f._node,params:a})}.bind(this)),f._node.addEventListener("endEvent",function(){d&&d.emit("animationEnd",{element:this,animate:f._node,params:a}),c&&(i[e]=a.to,this.attr(i),f.remove())}.bind(this))}a[e]instanceof Array?a[e].forEach(function(a){f.bind(this)(a,!1)}.bind(this)):f.bind(this)(a[e],c)}.bind(this)),this}function x(a){var c=this;this.svgElements=[];for(var d=0;d<a.length;d++)this.svgElements.push(new b.Svg(a[d]));Object.keys(b.Svg.prototype).filter(function(a){return["constructor","parent","querySelector","querySelectorAll","replace","append","classes","height","width"].indexOf(a)===-1}).forEach(function(a){c[a]=function(){var d=Array.prototype.slice.call(arguments,0);return c.svgElements.forEach(function(c){b.Svg.prototype[a].apply(c,d)}),c}})}var y=a.document;b.Svg=b.Class.extend({constructor:c,attr:d,elem:e,parent:f,root:g,querySelector:h,querySelectorAll:i,getNode:j,foreignObject:k,text:l,empty:m,remove:n,replace:o,append:p,classes:q,addClass:r,removeClass:s,removeAllClasses:t,height:u,width:v,animate:w}),b.Svg.isSupported=function(a){return y.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#"+a,"1.1")};var z={easeInSine:[.47,0,.745,.715],easeOutSine:[.39,.575,.565,1],easeInOutSine:[.445,.05,.55,.95],easeInQuad:[.55,.085,.68,.53],easeOutQuad:[.25,.46,.45,.94],easeInOutQuad:[.455,.03,.515,.955],easeInCubic:[.55,.055,.675,.19],easeOutCubic:[.215,.61,.355,1],easeInOutCubic:[.645,.045,.355,1],easeInQuart:[.895,.03,.685,.22],easeOutQuart:[.165,.84,.44,1],easeInOutQuart:[.77,0,.175,1],easeInQuint:[.755,.05,.855,.06],easeOutQuint:[.23,1,.32,1],easeInOutQuint:[.86,0,.07,1],easeInExpo:[.95,.05,.795,.035],easeOutExpo:[.19,1,.22,1],easeInOutExpo:[1,0,0,1],easeInCirc:[.6,.04,.98,.335],easeOutCirc:[.075,.82,.165,1],easeInOutCirc:[.785,.135,.15,.86],easeInBack:[.6,-.28,.735,.045],easeOutBack:[.175,.885,.32,1.275],easeInOutBack:[.68,-.55,.265,1.55]};b.Svg.Easing=z,b.Svg.List=b.Class.extend({constructor:x})}(this||global,a),function(a,b){"use strict";function c(a,c,d,e,f,g){var h=b.extend({command:f?a.toLowerCase():a.toUpperCase()},c,g?{data:g}:{});d.splice(e,0,h)}function d(a,b){a.forEach(function(c,d){t[c.command.toLowerCase()].forEach(function(e,f){b(c,e,d,f,a)})})}function e(a,c){this.pathElements=[],this.pos=0,this.close=a,this.options=b.extend({},u,c)}function f(a){return void 0!==a?(this.pos=Math.max(0,Math.min(this.pathElements.length,a)),this):this.pos}function g(a){return this.pathElements.splice(this.pos,a),this}function h(a,b,d,e){return c("M",{x:+a,y:+b},this.pathElements,this.pos++,d,e),this}function i(a,b,d,e){return c("L",{x:+a,y:+b},this.pathElements,this.pos++,d,e),this}function j(a,b,d,e,f,g,h,i){return c("C",{x1:+a,y1:+b,x2:+d,y2:+e,x:+f,y:+g},this.pathElements,this.pos++,h,i),this}function k(a,b,d,e,f,g,h,i,j){return c("A",{rx:+a,ry:+b,xAr:+d,lAf:+e,sf:+f,x:+g,y:+h},this.pathElements,this.pos++,i,j),this}function l(a){var c=a.replace(/([A-Za-z])([0-9])/g,"$1 $2").replace(/([0-9])([A-Za-z])/g,"$1 $2").split(/[\s,]+/).reduce(function(a,b){return b.match(/[A-Za-z]/)&&a.push([]),a[a.length-1].push(b),a},[]);"Z"===c[c.length-1][0].toUpperCase()&&c.pop();var d=c.map(function(a){var c=a.shift(),d=t[c.toLowerCase()];return b.extend({command:c},d.reduce(function(b,c,d){return b[c]=+a[d],b},{}))}),e=[this.pos,0];return Array.prototype.push.apply(e,d),Array.prototype.splice.apply(this.pathElements,e),this.pos+=d.length,this}function m(){var a=Math.pow(10,this.options.accuracy);return this.pathElements.reduce(function(b,c){var d=t[c.command.toLowerCase()].map(function(b){return this.options.accuracy?Math.round(c[b]*a)/a:c[b]}.bind(this));return b+c.command+d.join(",")}.bind(this),"")+(this.close?"Z":"")}function n(a,b){return d(this.pathElements,function(c,d){c[d]*="x"===d[0]?a:b}),this}function o(a,b){return d(this.pathElements,function(c,d){c[d]+="x"===d[0]?a:b}),this}function p(a){return d(this.pathElements,function(b,c,d,e,f){var g=a(b,c,d,e,f);(g||0===g)&&(b[c]=g)}),this}function q(a){var c=new b.Svg.Path(a||this.close);return c.pos=this.pos,c.pathElements=this.pathElements.slice().map(function(a){return b.extend({},a)}),c.options=b.extend({},this.options),c}function r(a){var c=[new b.Svg.Path];return this.pathElements.forEach(function(d){d.command===a.toUpperCase()&&0!==c[c.length-1].pathElements.length&&c.push(new b.Svg.Path),c[c.length-1].pathElements.push(d)}),c}function s(a,c,d){for(var e=new b.Svg.Path(c,d),f=0;f<a.length;f++)for(var g=a[f],h=0;h<g.pathElements.length;h++)e.pathElements.push(g.pathElements[h]);return e}var t={m:["x","y"],l:["x","y"],c:["x1","y1","x2","y2","x","y"],a:["rx","ry","xAr","lAf","sf","x","y"]},u={accuracy:3};b.Svg.Path=b.Class.extend({constructor:e,position:f,remove:g,move:h,line:i,curve:j,arc:k,scale:n,translate:o,transform:p,parse:l,stringify:m,clone:q,splitByCommand:r}),b.Svg.Path.elementDescriptions=t,b.Svg.Path.join=s}(this||global,a),function(a,b){"use strict";function c(a,b,c,d){this.units=a,this.counterUnits=a===e.x?e.y:e.x,this.chartRect=b,this.axisLength=b[a.rectEnd]-b[a.rectStart],this.gridOffset=b[a.rectOffset],this.ticks=c,this.options=d}function d(a,c,d,e,f){var g=e["axis"+this.units.pos.toUpperCase()],h=this.ticks.map(this.projectValue.bind(this)),i=this.ticks.map(g.labelInterpolationFnc);h.forEach(function(j,k){var l,m={x:0,y:0};l=h[k+1]?h[k+1]-j:Math.max(this.axisLength-j,30),b.isFalseyButZero(i[k])&&""!==i[k]||("x"===this.units.pos?(j=this.chartRect.x1+j,m.x=e.axisX.labelOffset.x,"start"===e.axisX.position?m.y=this.chartRect.padding.top+e.axisX.labelOffset.y+(d?5:20):m.y=this.chartRect.y1+e.axisX.labelOffset.y+(d?5:20)):(j=this.chartRect.y1-j,m.y=e.axisY.labelOffset.y-(d?l:0),"start"===e.axisY.position?m.x=d?this.chartRect.padding.left+e.axisY.labelOffset.x:this.chartRect.x1-10:m.x=this.chartRect.x2+e.axisY.labelOffset.x+10),g.showGrid&&b.createGrid(j,k,this,this.gridOffset,this.chartRect[this.counterUnits.len](),a,[e.classNames.grid,e.classNames[this.units.dir]],f),g.showLabel&&b.createLabel(j,l,k,i,this,g.offset,m,c,[e.classNames.label,e.classNames[this.units.dir],"start"===g.position?e.classNames[g.position]:e.classNames.end],d,f))}.bind(this))}var e=(a.window,a.document,{x:{pos:"x",len:"width",dir:"horizontal",rectStart:"x1",rectEnd:"x2",rectOffset:"y2"},y:{pos:"y",len:"height",dir:"vertical",rectStart:"y2",rectEnd:"y1",rectOffset:"x1"}});b.Axis=b.Class.extend({constructor:c,createGridAndLabels:d,projectValue:function(a,b,c){throw new Error("Base axis can't be instantiated!")}}),b.Axis.units=e}(this||global,a),function(a,b){"use strict";function c(a,c,d,e){var f=e.highLow||b.getHighLow(c,e,a.pos);this.bounds=b.getBounds(d[a.rectEnd]-d[a.rectStart],f,e.scaleMinSpace||20,e.onlyInteger),this.range={min:this.bounds.min,max:this.bounds.max},b.AutoScaleAxis["super"].constructor.call(this,a,d,this.bounds.values,e)}function d(a){return this.axisLength*(+b.getMultiValue(a,this.units.pos)-this.bounds.min)/this.bounds.range}a.window,a.document;b.AutoScaleAxis=b.Axis.extend({constructor:c,projectValue:d})}(this||global,a),function(a,b){"use strict";function c(a,c,d,e){var f=e.highLow||b.getHighLow(c,e,a.pos);this.divisor=e.divisor||1,this.ticks=e.ticks||b.times(this.divisor).map(function(a,b){return f.low+(f.high-f.low)/this.divisor*b}.bind(this)),this.ticks.sort(function(a,b){return a-b}),this.range={min:f.low,max:f.high},b.FixedScaleAxis["super"].constructor.call(this,a,d,this.ticks,e),this.stepLength=this.axisLength/this.divisor}function d(a){return this.axisLength*(+b.getMultiValue(a,this.units.pos)-this.range.min)/(this.range.max-this.range.min)}a.window,a.document;b.FixedScaleAxis=b.Axis.extend({constructor:c,projectValue:d})}(this||global,a),function(a,b){"use strict";function c(a,c,d,e){b.StepAxis["super"].constructor.call(this,a,d,e.ticks,e);var f=Math.max(1,e.ticks.length-(e.stretch?1:0));this.stepLength=this.axisLength/f}function d(a,b){return this.stepLength*b}a.window,a.document;b.StepAxis=b.Axis.extend({constructor:c,projectValue:d})}(this||global,a),function(a,b){"use strict";function c(a){var c=b.normalizeData(this.data,a.reverseData,!0);this.svg=b.createSvg(this.container,a.width,a.height,a.classNames.chart);var d,f,g=this.svg.elem("g").addClass(a.classNames.gridGroup),h=this.svg.elem("g"),i=this.svg.elem("g").addClass(a.classNames.labelGroup),j=b.createChartRect(this.svg,a,e.padding);d=void 0===a.axisX.type?new b.StepAxis(b.Axis.units.x,c.normalized.series,j,b.extend({},a.axisX,{ticks:c.normalized.labels,stretch:a.fullWidth})):a.axisX.type.call(b,b.Axis.units.x,c.normalized.series,j,a.axisX),f=void 0===a.axisY.type?new b.AutoScaleAxis(b.Axis.units.y,c.normalized.series,j,b.extend({},a.axisY,{high:b.isNumeric(a.high)?a.high:a.axisY.high,low:b.isNumeric(a.low)?a.low:a.axisY.low})):a.axisY.type.call(b,b.Axis.units.y,c.normalized.series,j,a.axisY),d.createGridAndLabels(g,i,this.supportsForeignObject,a,this.eventEmitter),f.createGridAndLabels(g,i,this.supportsForeignObject,a,this.eventEmitter),a.showGridBackground&&b.createGridBackground(g,j,a.classNames.gridBackground,this.eventEmitter),c.raw.series.forEach(function(e,g){var i=h.elem("g");i.attr({"ct:series-name":e.name,"ct:meta":b.serialize(e.meta)}),i.addClass([a.classNames.series,e.className||a.classNames.series+"-"+b.alphaNumerate(g)].join(" "));var k=[],l=[];c.normalized.series[g].forEach(function(a,h){var i={x:j.x1+d.projectValue(a,h,c.normalized.series[g]),y:j.y1-f.projectValue(a,h,c.normalized.series[g])};k.push(i.x,i.y),l.push({value:a,valueIndex:h,meta:b.getMetaData(e,h)})}.bind(this));var m={lineSmooth:b.getSeriesOption(e,a,"lineSmooth"),showPoint:b.getSeriesOption(e,a,"showPoint"),showLine:b.getSeriesOption(e,a,"showLine"),showArea:b.getSeriesOption(e,a,"showArea"),areaBase:b.getSeriesOption(e,a,"areaBase")},n="function"==typeof m.lineSmooth?m.lineSmooth:m.lineSmooth?b.Interpolation.monotoneCubic():b.Interpolation.none(),o=n(k,l);if(m.showPoint&&o.pathElements.forEach(function(c){var h=i.elem("line",{x1:c.x,y1:c.y,x2:c.x+.01,y2:c.y},a.classNames.point).attr({"ct:value":[c.data.value.x,c.data.value.y].filter(b.isNumeric).join(","),"ct:meta":b.serialize(c.data.meta)});this.eventEmitter.emit("draw",{type:"point",value:c.data.value,index:c.data.valueIndex,meta:c.data.meta,series:e,seriesIndex:g,axisX:d,axisY:f,group:i,element:h,x:c.x,y:c.y})}.bind(this)),m.showLine){var p=i.elem("path",{d:o.stringify()},a.classNames.line,!0);this.eventEmitter.emit("draw",{type:"line",values:c.normalized.series[g],path:o.clone(),chartRect:j,index:g,series:e,seriesIndex:g,seriesMeta:e.meta,axisX:d,axisY:f,group:i,element:p})}if(m.showArea&&f.range){var q=Math.max(Math.min(m.areaBase,f.range.max),f.range.min),r=j.y1-f.projectValue(q);o.splitByCommand("M").filter(function(a){return a.pathElements.length>1}).map(function(a){var b=a.pathElements[0],c=a.pathElements[a.pathElements.length-1];return a.clone(!0).position(0).remove(1).move(b.x,r).line(b.x,b.y).position(a.pathElements.length+1).line(c.x,r)}).forEach(function(b){var h=i.elem("path",{d:b.stringify()},a.classNames.area,!0);this.eventEmitter.emit("draw",{type:"area",values:c.normalized.series[g],path:b.clone(),series:e,seriesIndex:g,axisX:d,axisY:f,chartRect:j,index:g,group:i,element:h})}.bind(this))}}.bind(this)),this.eventEmitter.emit("created",{bounds:f.bounds,chartRect:j,axisX:d,axisY:f,svg:this.svg,options:a})}function d(a,c,d,f){b.Line["super"].constructor.call(this,a,c,e,b.extend({},e,d),f)}var e=(a.window,a.document,{axisX:{offset:30,position:"end",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:b.noop,type:void 0},axisY:{offset:40,position:"start",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:b.noop,type:void 0,scaleMinSpace:20,onlyInteger:!1},width:void 0,height:void 0,showLine:!0,showPoint:!0,showArea:!1,areaBase:0,lineSmooth:!0,showGridBackground:!1,low:void 0,high:void 0,chartPadding:{top:15,right:15,bottom:5,left:10},fullWidth:!1,reverseData:!1,classNames:{chart:"ct-chart-line",label:"ct-label",labelGroup:"ct-labels",series:"ct-series",line:"ct-line",point:"ct-point",area:"ct-area",grid:"ct-grid",gridGroup:"ct-grids",gridBackground:"ct-grid-background",vertical:"ct-vertical",horizontal:"ct-horizontal",start:"ct-start",end:"ct-end"}});b.Line=b.Base.extend({constructor:d,createChart:c})}(this||global,a),function(a,b){"use strict";function c(a){var c,d;a.distributeSeries?(c=b.normalizeData(this.data,a.reverseData,a.horizontalBars?"x":"y"),c.normalized.series=c.normalized.series.map(function(a){return[a]})):c=b.normalizeData(this.data,a.reverseData,a.horizontalBars?"x":"y"),this.svg=b.createSvg(this.container,a.width,a.height,a.classNames.chart+(a.horizontalBars?" "+a.classNames.horizontalBars:""));var f=this.svg.elem("g").addClass(a.classNames.gridGroup),g=this.svg.elem("g"),h=this.svg.elem("g").addClass(a.classNames.labelGroup);
|
9 |
-
if(a.stackBars&&0!==c.normalized.series.length){var i=b.serialMap(c.normalized.series,function(){return Array.prototype.slice.call(arguments).map(function(a){return a}).reduce(function(a,b){return{x:a.x+(b&&b.x)||0,y:a.y+(b&&b.y)||0}},{x:0,y:0})});d=b.getHighLow([i],a,a.horizontalBars?"x":"y")}else d=b.getHighLow(c.normalized.series,a,a.horizontalBars?"x":"y");d.high=+a.high||(0===a.high?0:d.high),d.low=+a.low||(0===a.low?0:d.low);var j,k,l,m,n,o=b.createChartRect(this.svg,a,e.padding);k=a.distributeSeries&&a.stackBars?c.normalized.labels.slice(0,1):c.normalized.labels,a.horizontalBars?(j=m=void 0===a.axisX.type?new b.AutoScaleAxis(b.Axis.units.x,c.normalized.series,o,b.extend({},a.axisX,{highLow:d,referenceValue:0})):a.axisX.type.call(b,b.Axis.units.x,c.normalized.series,o,b.extend({},a.axisX,{highLow:d,referenceValue:0})),l=n=void 0===a.axisY.type?new b.StepAxis(b.Axis.units.y,c.normalized.series,o,{ticks:k}):a.axisY.type.call(b,b.Axis.units.y,c.normalized.series,o,a.axisY)):(l=m=void 0===a.axisX.type?new b.StepAxis(b.Axis.units.x,c.normalized.series,o,{ticks:k}):a.axisX.type.call(b,b.Axis.units.x,c.normalized.series,o,a.axisX),j=n=void 0===a.axisY.type?new b.AutoScaleAxis(b.Axis.units.y,c.normalized.series,o,b.extend({},a.axisY,{highLow:d,referenceValue:0})):a.axisY.type.call(b,b.Axis.units.y,c.normalized.series,o,b.extend({},a.axisY,{highLow:d,referenceValue:0})));var p=a.horizontalBars?o.x1+j.projectValue(0):o.y1-j.projectValue(0),q=[];l.createGridAndLabels(f,h,this.supportsForeignObject,a,this.eventEmitter),j.createGridAndLabels(f,h,this.supportsForeignObject,a,this.eventEmitter),a.showGridBackground&&b.createGridBackground(f,o,a.classNames.gridBackground,this.eventEmitter),c.raw.series.forEach(function(d,e){var f,h,i=e-(c.raw.series.length-1)/2;f=a.distributeSeries&&!a.stackBars?l.axisLength/c.normalized.series.length/2:a.distributeSeries&&a.stackBars?l.axisLength/2:l.axisLength/c.normalized.series[e].length/2,h=g.elem("g"),h.attr({"ct:series-name":d.name,"ct:meta":b.serialize(d.meta)}),h.addClass([a.classNames.series,d.className||a.classNames.series+"-"+b.alphaNumerate(e)].join(" ")),c.normalized.series[e].forEach(function(g,k){var r,s,t,u;if(u=a.distributeSeries&&!a.stackBars?e:a.distributeSeries&&a.stackBars?0:k,r=a.horizontalBars?{x:o.x1+j.projectValue(g&&g.x?g.x:0,k,c.normalized.series[e]),y:o.y1-l.projectValue(g&&g.y?g.y:0,u,c.normalized.series[e])}:{x:o.x1+l.projectValue(g&&g.x?g.x:0,u,c.normalized.series[e]),y:o.y1-j.projectValue(g&&g.y?g.y:0,k,c.normalized.series[e])},l instanceof b.StepAxis&&(l.options.stretch||(r[l.units.pos]+=f*(a.horizontalBars?-1:1)),r[l.units.pos]+=a.stackBars||a.distributeSeries?0:i*a.seriesBarDistance*(a.horizontalBars?-1:1)),t=q[k]||p,q[k]=t-(p-r[l.counterUnits.pos]),void 0!==g){var v={};v[l.units.pos+"1"]=r[l.units.pos],v[l.units.pos+"2"]=r[l.units.pos],!a.stackBars||"accumulate"!==a.stackMode&&a.stackMode?(v[l.counterUnits.pos+"1"]=p,v[l.counterUnits.pos+"2"]=r[l.counterUnits.pos]):(v[l.counterUnits.pos+"1"]=t,v[l.counterUnits.pos+"2"]=q[k]),v.x1=Math.min(Math.max(v.x1,o.x1),o.x2),v.x2=Math.min(Math.max(v.x2,o.x1),o.x2),v.y1=Math.min(Math.max(v.y1,o.y2),o.y1),v.y2=Math.min(Math.max(v.y2,o.y2),o.y1);var w=b.getMetaData(d,k);s=h.elem("line",v,a.classNames.bar).attr({"ct:value":[g.x,g.y].filter(b.isNumeric).join(","),"ct:meta":b.serialize(w)}),this.eventEmitter.emit("draw",b.extend({type:"bar",value:g,index:k,meta:w,series:d,seriesIndex:e,axisX:m,axisY:n,chartRect:o,group:h,element:s},v))}}.bind(this))}.bind(this)),this.eventEmitter.emit("created",{bounds:j.bounds,chartRect:o,axisX:m,axisY:n,svg:this.svg,options:a})}function d(a,c,d,f){b.Bar["super"].constructor.call(this,a,c,e,b.extend({},e,d),f)}var e=(a.window,a.document,{axisX:{offset:30,position:"end",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:b.noop,scaleMinSpace:30,onlyInteger:!1},axisY:{offset:40,position:"start",labelOffset:{x:0,y:0},showLabel:!0,showGrid:!0,labelInterpolationFnc:b.noop,scaleMinSpace:20,onlyInteger:!1},width:void 0,height:void 0,high:void 0,low:void 0,referenceValue:0,chartPadding:{top:15,right:15,bottom:5,left:10},seriesBarDistance:15,stackBars:!1,stackMode:"accumulate",horizontalBars:!1,distributeSeries:!1,reverseData:!1,showGridBackground:!1,classNames:{chart:"ct-chart-bar",horizontalBars:"ct-horizontal-bars",label:"ct-label",labelGroup:"ct-labels",series:"ct-series",bar:"ct-bar",grid:"ct-grid",gridGroup:"ct-grids",gridBackground:"ct-grid-background",vertical:"ct-vertical",horizontal:"ct-horizontal",start:"ct-start",end:"ct-end"}});b.Bar=b.Base.extend({constructor:d,createChart:c})}(this||global,a),function(a,b){"use strict";function c(a,b,c){var d=b.x>a.x;return d&&"explode"===c||!d&&"implode"===c?"start":d&&"implode"===c||!d&&"explode"===c?"end":"middle"}function d(a){var d,e,g,h,i,j=b.normalizeData(this.data),k=[],l=a.startAngle;this.svg=b.createSvg(this.container,a.width,a.height,a.donut?a.classNames.chartDonut:a.classNames.chartPie),e=b.createChartRect(this.svg,a,f.padding),g=Math.min(e.width()/2,e.height()/2),i=a.total||j.normalized.series.reduce(function(a,b){return a+b},0);var m=b.quantity(a.donutWidth);"%"===m.unit&&(m.value*=g/100),g-=a.donut&&!a.donutSolid?m.value/2:0,h="outside"===a.labelPosition||a.donut&&!a.donutSolid?g:"center"===a.labelPosition?0:a.donutSolid?g-m.value/2:g/2,h+=a.labelOffset;var n={x:e.x1+e.width()/2,y:e.y2+e.height()/2},o=1===j.raw.series.filter(function(a){return a.hasOwnProperty("value")?0!==a.value:0!==a}).length;j.raw.series.forEach(function(a,b){k[b]=this.svg.elem("g",null,null)}.bind(this)),a.showLabel&&(d=this.svg.elem("g",null,null)),j.raw.series.forEach(function(e,f){if(0!==j.normalized.series[f]||!a.ignoreEmptyValues){k[f].attr({"ct:series-name":e.name}),k[f].addClass([a.classNames.series,e.className||a.classNames.series+"-"+b.alphaNumerate(f)].join(" "));var p=i>0?l+j.normalized.series[f]/i*360:0,q=Math.max(0,l-(0===f||o?0:.2));p-q>=359.99&&(p=q+359.99);var r,s,t,u=b.polarToCartesian(n.x,n.y,g,q),v=b.polarToCartesian(n.x,n.y,g,p),w=new b.Svg.Path(!a.donut||a.donutSolid).move(v.x,v.y).arc(g,g,0,p-l>180,0,u.x,u.y);a.donut?a.donutSolid&&(t=g-m.value,r=b.polarToCartesian(n.x,n.y,t,l-(0===f||o?0:.2)),s=b.polarToCartesian(n.x,n.y,t,p),w.line(r.x,r.y),w.arc(t,t,0,p-l>180,1,s.x,s.y)):w.line(n.x,n.y);var x=a.classNames.slicePie;a.donut&&(x=a.classNames.sliceDonut,a.donutSolid&&(x=a.classNames.sliceDonutSolid));var y=k[f].elem("path",{d:w.stringify()},x);if(y.attr({"ct:value":j.normalized.series[f],"ct:meta":b.serialize(e.meta)}),a.donut&&!a.donutSolid&&(y._node.style.strokeWidth=m.value+"px"),this.eventEmitter.emit("draw",{type:"slice",value:j.normalized.series[f],totalDataSum:i,index:f,meta:e.meta,series:e,group:k[f],element:y,path:w.clone(),center:n,radius:g,startAngle:l,endAngle:p}),a.showLabel){var z;z=1===j.raw.series.length?{x:n.x,y:n.y}:b.polarToCartesian(n.x,n.y,h,l+(p-l)/2);var A;A=j.normalized.labels&&!b.isFalseyButZero(j.normalized.labels[f])?j.normalized.labels[f]:j.normalized.series[f];var B=a.labelInterpolationFnc(A,f);if(B||0===B){var C=d.elem("text",{dx:z.x,dy:z.y,"text-anchor":c(n,z,a.labelDirection)},a.classNames.label).text(""+B);this.eventEmitter.emit("draw",{type:"label",index:f,group:d,element:C,text:""+B,x:z.x,y:z.y})}}l=p}}.bind(this)),this.eventEmitter.emit("created",{chartRect:e,svg:this.svg,options:a})}function e(a,c,d,e){b.Pie["super"].constructor.call(this,a,c,f,b.extend({},f,d),e)}var f=(a.window,a.document,{width:void 0,height:void 0,chartPadding:5,classNames:{chartPie:"ct-chart-pie",chartDonut:"ct-chart-donut",series:"ct-series",slicePie:"ct-slice-pie",sliceDonut:"ct-slice-donut",sliceDonutSolid:"ct-slice-donut-solid",label:"ct-label"},startAngle:0,total:void 0,donut:!1,donutSolid:!1,donutWidth:60,showLabel:!0,labelOffset:0,labelPosition:"inside",labelInterpolationFnc:b.noop,labelDirection:"neutral",reverseData:!1,ignoreEmptyValues:!1});b.Pie=b.Base.extend({constructor:e,createChart:d,determineAnchorPosition:c})}(this||global,a),a});
|
10 |
-
//# sourceMappingURL=chartist.min.js.map
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resources/js/charts.js
DELETED
@@ -1,131 +0,0 @@
|
|
1 |
-
jQuery.fn.icwpWpsfChartWithFilters = function ( aOptions ) {
|
2 |
-
|
3 |
-
let resetFilters = function ( evt ) {
|
4 |
-
jQuery( 'input[type=text]', $oForm ).each( function () {
|
5 |
-
jQuery( this ).val( '' );
|
6 |
-
} );
|
7 |
-
jQuery( 'select', $oForm ).each( function () {
|
8 |
-
jQuery( this ).prop( 'selectedIndex', 0 );
|
9 |
-
} );
|
10 |
-
jQuery( 'input[type=checkbox]', $oForm ).each( function () {
|
11 |
-
jQuery( this ).prop( 'checked', false );
|
12 |
-
} );
|
13 |
-
aOpts[ 'chart' ].renderChartFromForm( $oForm );
|
14 |
-
};
|
15 |
-
|
16 |
-
let submitFilters = function ( evt ) {
|
17 |
-
evt.preventDefault();
|
18 |
-
aOpts[ 'chart' ].renderChartFromForm( $oForm );
|
19 |
-
return false;
|
20 |
-
};
|
21 |
-
|
22 |
-
let initialise = function () {
|
23 |
-
jQuery( document ).ready( function () {
|
24 |
-
$oForm = jQuery( aOpts[ 'selector_filter_form' ] );
|
25 |
-
$oForm.on( 'change', submitFilters );
|
26 |
-
$oForm.on( 'click', 'a#ClearForm', resetFilters );
|
27 |
-
} );
|
28 |
-
};
|
29 |
-
|
30 |
-
let $oThis = this;
|
31 |
-
let aOpts = jQuery.extend( {}, aOptions );
|
32 |
-
let $oForm;
|
33 |
-
initialise();
|
34 |
-
|
35 |
-
return this;
|
36 |
-
};
|
37 |
-
|
38 |
-
jQuery.fn.icwpWpsfAjaxChart = function ( aOptions ) {
|
39 |
-
|
40 |
-
this.reloadChart = function () {
|
41 |
-
reqRenderChart();
|
42 |
-
};
|
43 |
-
|
44 |
-
let createChartContainer = function () {
|
45 |
-
$oChartContainer = jQuery( '<div />' ).appendTo( $oThis );
|
46 |
-
$oChartContainer.addClass( 'icwpAjaxContainerChart' )
|
47 |
-
.addClass( 'ct-chart' );
|
48 |
-
};
|
49 |
-
|
50 |
-
let refreshChart = function ( event ) {
|
51 |
-
event.preventDefault();
|
52 |
-
let aChartRequestParams = {};
|
53 |
-
reqRenderChart( aChartRequestParams );
|
54 |
-
};
|
55 |
-
|
56 |
-
this.renderChartFromForm = function ( $oForm ) {
|
57 |
-
reqRenderChart( { 'form_params': $oForm.serialize() } );
|
58 |
-
};
|
59 |
-
|
60 |
-
let reqRenderChart = function ( aRequestParams ) {
|
61 |
-
if ( bReqRunning ) {
|
62 |
-
return false;
|
63 |
-
}
|
64 |
-
bReqRunning = true;
|
65 |
-
|
66 |
-
$oChartContainer.html( 'Loading...' );
|
67 |
-
|
68 |
-
jQuery.post( ajaxurl, jQuery.extend( aOpts[ 'ajax_render' ], aOpts[ 'req_params' ], aRequestParams ),
|
69 |
-
function ( oResponse ) {
|
70 |
-
|
71 |
-
$oChartContainer.html('');
|
72 |
-
new Chartist.Line(
|
73 |
-
$oThis.selector+' .icwpAjaxContainerChart',
|
74 |
-
oResponse.data.chart.data,
|
75 |
-
{
|
76 |
-
height: '100px',
|
77 |
-
fullWidth: true,
|
78 |
-
showArea: false,
|
79 |
-
chartPadding: {
|
80 |
-
top: 10,
|
81 |
-
right: 10,
|
82 |
-
bottom: 10,
|
83 |
-
left: 10
|
84 |
-
},
|
85 |
-
axisX: {
|
86 |
-
offset: 5,
|
87 |
-
showLabel: false,
|
88 |
-
showGrid: false,
|
89 |
-
},
|
90 |
-
axisY: {
|
91 |
-
offset: 25,
|
92 |
-
onlyInteger: true,
|
93 |
-
showLabel: true,
|
94 |
-
labelInterpolationFnc: function ( value ) {
|
95 |
-
return value;
|
96 |
-
}
|
97 |
-
},
|
98 |
-
plugins: [
|
99 |
-
Chartist.plugins.legend( {
|
100 |
-
legendNames: oResponse.data.chart.legend_names
|
101 |
-
} )
|
102 |
-
]
|
103 |
-
}
|
104 |
-
);
|
105 |
-
}
|
106 |
-
).always(
|
107 |
-
function () {
|
108 |
-
bReqRunning = false;
|
109 |
-
}
|
110 |
-
);
|
111 |
-
};
|
112 |
-
|
113 |
-
let setHandlers = function () {
|
114 |
-
};
|
115 |
-
|
116 |
-
let initialise = function () {
|
117 |
-
jQuery( document ).ready( function () {
|
118 |
-
createChartContainer();
|
119 |
-
reqRenderChart();
|
120 |
-
setHandlers();
|
121 |
-
} );
|
122 |
-
};
|
123 |
-
|
124 |
-
let $oThis = this;
|
125 |
-
let $oChartContainer;
|
126 |
-
let bReqRunning = false;
|
127 |
-
let aOpts = jQuery.extend( {}, aOptions );
|
128 |
-
initialise();
|
129 |
-
|
130 |
-
return this;
|
131 |
-
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resources/js/introjs.min.js
DELETED
@@ -1 +0,0 @@
|
|
1 |
-
!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t(),module.exports.introJs=function(){return console.warn('Deprecated: please use require("intro.js") directly, instead of the introJs method of the function'),t().apply(this,arguments)};else if("function"==typeof define&&define.amd)define([],t);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).introJs=t()}}(function(){function n(t){this._targetElement=t,this._introItems=[],this._options={nextLabel:"Next →",prevLabel:"← Back",skipLabel:"Skip",doneLabel:"Done",hidePrev:!1,hideNext:!1,tooltipPosition:"bottom",tooltipClass:"",highlightClass:"",exitOnEsc:!0,exitOnOverlayClick:!0,showStepNumbers:!0,keyboardNavigation:!0,showButtons:!0,showBullets:!0,showProgress:!1,scrollToElement:!0,scrollTo:"element",scrollPadding:30,overlayOpacity:.8,positionPrecedence:["bottom","top","right","left"],disableInteraction:!1,helperElementPadding:10,hintPosition:"top-middle",hintButtonLabel:"Got it",hintAnimation:!0,buttonClass:"introjs-button"}}function e(t,i){var e=t.querySelectorAll("*[data-intro]"),n=[];if(this._options.steps)B(this._options.steps,function(t){var e=h(t);if(e.step=n.length+1,"string"==typeof e.element&&(e.element=document.querySelector(e.element)),void 0===e.element||null===e.element){var i=document.querySelector(".introjsFloatingElement");null===i&&((i=document.createElement("div")).className="introjsFloatingElement",document.body.appendChild(i)),e.element=i,e.position="floating"}e.scrollTo=e.scrollTo||this._options.scrollTo,void 0===e.disableInteraction&&(e.disableInteraction=this._options.disableInteraction),null!==e.element&&n.push(e)}.bind(this));else{var o;if(e.length<1)return!1;B(e,function(t){if((!i||t.getAttribute("data-intro-group")===i)&&"none"!==t.style.display){var e=parseInt(t.getAttribute("data-step"),10);o=void 0!==t.getAttribute("data-disable-interaction")?!!t.getAttribute("data-disable-interaction"):this._options.disableInteraction,0<e&&(n[e-1]={element:t,intro:t.getAttribute("data-intro"),step:parseInt(t.getAttribute("data-step"),10),tooltipClass:t.getAttribute("data-tooltipclass"),highlightClass:t.getAttribute("data-highlightclass"),position:t.getAttribute("data-position")||this._options.tooltipPosition,scrollTo:t.getAttribute("data-scrollto")||this._options.scrollTo,disableInteraction:o})}}.bind(this));var s=0;B(e,function(t){if((!i||t.getAttribute("data-intro-group")===i)&&null===t.getAttribute("data-step")){for(;void 0!==n[s];)s++;o=void 0!==t.getAttribute("data-disable-interaction")?!!t.getAttribute("data-disable-interaction"):this._options.disableInteraction,n[s]={element:t,intro:t.getAttribute("data-intro"),step:s+1,tooltipClass:t.getAttribute("data-tooltipclass"),highlightClass:t.getAttribute("data-highlightclass"),position:t.getAttribute("data-position")||this._options.tooltipPosition,scrollTo:t.getAttribute("data-scrollto")||this._options.scrollTo,disableInteraction:o}}}.bind(this))}for(var l=[],r=0;r<n.length;r++)n[r]&&l.push(n[r]);return(n=l).sort(function(t,e){return t.step-e.step}),this._introItems=n,function(t){var e=document.createElement("div"),i="",n=this;if(e.className="introjs-overlay",t.tagName&&"body"!==t.tagName.toLowerCase()){var o=k(t);o&&(i+="width: "+o.width+"px; height:"+o.height+"px; top:"+o.top+"px;left: "+o.left+"px;",e.style.cssText=i)}else i+="top: 0;bottom: 0; left: 0;right: 0;position: fixed;",e.style.cssText=i;return t.appendChild(e),e.onclick=function(){!0===n._options.exitOnOverlayClick&&A.call(n,t)},window.setTimeout(function(){i+="opacity: "+n._options.overlayOpacity.toString()+";",e.style.cssText=i},10),!0}.call(this,t)&&(E.call(this),this._options.keyboardNavigation&&u.on(window,"keydown",c,this,!0),u.on(window,"resize",a,this,!0)),!1}function a(){this.refresh.call(this)}function c(t){var e=null===t.code?t.which:t.code;if(null===e&&(e=null===t.charCode?t.keyCode:t.charCode),"Escape"!==e&&27!==e||!0!==this._options.exitOnEsc){if("ArrowLeft"===e||37===e)N.call(this);else if("ArrowRight"===e||39===e)E.call(this);else if("Enter"===e||13===e){var i=t.target||t.srcElement;i&&i.className.match("introjs-prevbutton")?N.call(this):i&&i.className.match("introjs-skipbutton")?(this._introItems.length-1===this._currentStep&&"function"==typeof this._introCompleteCallback&&this._introCompleteCallback.call(this),A.call(this,this._targetElement)):i&&i.getAttribute("data-stepnumber")?i.click():E.call(this),t.preventDefault?t.preventDefault():t.returnValue=!1}}else A.call(this,this._targetElement)}function h(t){if(null===t||"object"!=typeof t||void 0!==t.nodeType)return t;var e={};for(var i in t)void 0!==window.jQuery&&t[i]instanceof window.jQuery?e[i]=t[i]:e[i]=h(t[i]);return e}function E(){this._direction="forward",void 0!==this._currentStepNumber&&B(this._introItems,function(t,e){t.step===this._currentStepNumber&&(this._currentStep=e-1,this._currentStepNumber=void 0)}.bind(this)),void 0===this._currentStep?this._currentStep=0:++this._currentStep;var t=this._introItems[this._currentStep],e=!0;return void 0!==this._introBeforeChangeCallback&&(e=this._introBeforeChangeCallback.call(this,t.element)),!1===e?(--this._currentStep,!1):this._introItems.length<=this._currentStep?("function"==typeof this._introCompleteCallback&&this._introCompleteCallback.call(this),void A.call(this,this._targetElement)):void i.call(this,t)}function N(){if(this._direction="backward",0===this._currentStep)return!1;--this._currentStep;var t=this._introItems[this._currentStep],e=!0;if(void 0!==this._introBeforeChangeCallback&&(e=this._introBeforeChangeCallback.call(this,t.element)),!1===e)return++this._currentStep,!1;i.call(this,t)}function A(t,e){var i=!0;if(void 0!==this._introBeforeExitCallback&&(i=this._introBeforeExitCallback.call(this)),e||!1!==i){var n=t.querySelectorAll(".introjs-overlay");n&&n.length&&B(n,function(t){t.style.opacity=0,window.setTimeout(function(){this.parentNode&&this.parentNode.removeChild(this)}.bind(t),500)}.bind(this));var o=t.querySelector(".introjs-helperLayer");o&&o.parentNode.removeChild(o);var s=t.querySelector(".introjs-tooltipReferenceLayer");s&&s.parentNode.removeChild(s);var l=t.querySelector(".introjs-disableInteraction");l&&l.parentNode.removeChild(l);var r=document.querySelector(".introjsFloatingElement");r&&r.parentNode.removeChild(r),q(),B(document.querySelectorAll(".introjs-fixParent"),function(t){O(t,/introjs-fixParent/g)}),u.off(window,"keydown",c,this,!0),u.off(window,"resize",a,this,!0),void 0!==this._introExitCallback&&this._introExitCallback.call(this),this._currentStep=void 0}}function L(t,e,i,n,o){var s,l,r,a,c,h="";if(o=o||!1,e.style.top=null,e.style.right=null,e.style.bottom=null,e.style.left=null,e.style.marginLeft=null,e.style.marginTop=null,i.style.display="inherit",null!=n&&(n.style.top=null,n.style.left=null),this._introItems[this._currentStep])switch(h="string"==typeof(s=this._introItems[this._currentStep]).tooltipClass?s.tooltipClass:this._options.tooltipClass,e.className=("introjs-tooltip "+h).replace(/^\s+|\s+$/g,""),e.setAttribute("role","dialog"),"floating"!==(c=this._introItems[this._currentStep].position)&&(c=function(t,e,i){var n=this._options.positionPrecedence.slice(),o=b(),s=k(e).height+10,l=k(e).width+20,r=t.getBoundingClientRect(),a="floating";r.bottom+s+s>o.height&&m(n,"bottom");r.top-s<0&&m(n,"top");r.right+l>o.width&&m(n,"right");r.left-l<0&&m(n,"left");var c=(h=i||"",u=h.indexOf("-"),-1!==u?h.substr(u):"");var h,u;i&&(i=i.split("-")[0]);n.length&&(a="auto"!==i&&-1<n.indexOf(i)?i:n[0]);-1!==["top","bottom"].indexOf(a)&&(a+=function(t,e,i,n){var o=e/2,s=Math.min(i.width,window.screen.width),l=["-left-aligned","-middle-aligned","-right-aligned"],r="";s-t<e&&m(l,"-left-aligned");(t<o||s-t<o)&&m(l,"-middle-aligned");t<e&&m(l,"-right-aligned");r=l.length?-1!==l.indexOf(n)?n:l[0]:"-middle-aligned";return r}(r.left,l,o,c));return a}.call(this,t,e,c)),r=k(t),l=k(e),a=b(),H(e,"introjs-"+c),c){case"top-right-aligned":i.className="introjs-arrow bottom-right";var u=0;f(r,u,l,e),e.style.bottom=r.height+20+"px";break;case"top-middle-aligned":i.className="introjs-arrow bottom-middle";var d=r.width/2-l.width/2;o&&(d+=5),f(r,d,l,e)&&(e.style.right=null,p(r,d,l,a,e)),e.style.bottom=r.height+20+"px";break;case"top-left-aligned":case"top":i.className="introjs-arrow bottom",p(r,o?0:15,l,a,e),e.style.bottom=r.height+20+"px";break;case"right":e.style.left=r.width+20+"px",r.top+l.height>a.height?(i.className="introjs-arrow left-bottom",e.style.top="-"+(l.height-r.height-20)+"px"):i.className="introjs-arrow left";break;case"left":o||!0!==this._options.showStepNumbers||(e.style.top="15px"),r.top+l.height>a.height?(e.style.top="-"+(l.height-r.height-20)+"px",i.className="introjs-arrow right-bottom"):i.className="introjs-arrow right",e.style.right=r.width+20+"px";break;case"floating":i.style.display="none",e.style.left="50%",e.style.top="50%",e.style.marginLeft="-"+l.width/2+"px",e.style.marginTop="-"+l.height/2+"px",null!=n&&(n.style.left="-"+(l.width/2+18)+"px",n.style.top="-"+(l.height/2+18)+"px");break;case"bottom-right-aligned":i.className="introjs-arrow top-right",f(r,u=0,l,e),e.style.top=r.height+20+"px";break;case"bottom-middle-aligned":i.className="introjs-arrow top-middle",d=r.width/2-l.width/2,o&&(d+=5),f(r,d,l,e)&&(e.style.right=null,p(r,d,l,a,e)),e.style.top=r.height+20+"px";break;default:i.className="introjs-arrow top",p(r,0,l,a,e),e.style.top=r.height+20+"px"}}function p(t,e,i,n,o){return t.left+e+i.width>n.width?(o.style.left=n.width-i.width-t.left+"px",!1):(o.style.left=e+"px",!0)}function f(t,e,i,n){return t.left+t.width-e-i.width<0?(n.style.left=-t.left+"px",!1):(n.style.right=e+"px",!0)}function m(t,e){-1<t.indexOf(e)&&t.splice(t.indexOf(e),1)}function T(t){if(t){if(!this._introItems[this._currentStep])return;var e=this._introItems[this._currentStep],i=k(e.element),n=this._options.helperElementPadding;d(e.element)?H(t,"introjs-fixedTooltip"):O(t,"introjs-fixedTooltip"),"floating"===e.position&&(n=0),t.style.cssText="width: "+(i.width+n)+"px; height:"+(i.height+n)+"px; top:"+(i.top-n/2)+"px;left: "+(i.left-n/2)+"px;"}}function I(t){t.setAttribute("role","button"),t.tabIndex=0}function i(o){void 0!==this._introChangeCallback&&this._introChangeCallback.call(this,o.element);var t,e,i,n,s=this,l=document.querySelector(".introjs-helperLayer"),r=document.querySelector(".introjs-tooltipReferenceLayer"),a="introjs-helperLayer";if("string"==typeof o.highlightClass&&(a+=" "+o.highlightClass),"string"==typeof this._options.highlightClass&&(a+=" "+this._options.highlightClass),null!==l){var c=r.querySelector(".introjs-helperNumberLayer"),h=r.querySelector(".introjs-tooltiptext"),u=r.querySelector(".introjs-arrow"),d=r.querySelector(".introjs-tooltip");if(i=r.querySelector(".introjs-skipbutton"),e=r.querySelector(".introjs-prevbutton"),t=r.querySelector(".introjs-nextbutton"),l.className=a,d.style.opacity=0,d.style.display="none",null!==c){var p=this._introItems[0<=o.step-2?o.step-2:0];(null!==p&&"forward"===this._direction&&"floating"===p.position||"backward"===this._direction&&"floating"===o.position)&&(c.style.opacity=0)}(n=R(o.element))!==document.body&&V(n,o.element),T.call(s,l),T.call(s,r),B(document.querySelectorAll(".introjs-fixParent"),function(t){O(t,/introjs-fixParent/g)}),q(),s._lastShowElementTimer&&window.clearTimeout(s._lastShowElementTimer),s._lastShowElementTimer=window.setTimeout(function(){null!==c&&(c.innerHTML=o.step),h.innerHTML=o.intro,d.style.display="block",L.call(s,o.element,d,u,c),s._options.showBullets&&(r.querySelector(".introjs-bullets li > a.active").className="",r.querySelector('.introjs-bullets li > a[data-stepnumber="'+o.step+'"]').className="active"),r.querySelector(".introjs-progress .introjs-progressbar").style.cssText="width:"+z.call(s)+"%;",r.querySelector(".introjs-progress .introjs-progressbar").setAttribute("aria-valuenow",z.call(s)),d.style.opacity=1,c&&(c.style.opacity=1),null!=i&&/introjs-donebutton/gi.test(i.className)?i.focus():null!=t&&t.focus(),P.call(s,o.scrollTo,o,h)},350)}else{var f=document.createElement("div"),m=document.createElement("div"),b=document.createElement("div"),g=document.createElement("div"),y=document.createElement("div"),v=document.createElement("div"),_=document.createElement("div"),w=document.createElement("div");f.className=a,m.className="introjs-tooltipReferenceLayer",(n=R(o.element))!==document.body&&V(n,o.element),T.call(s,f),T.call(s,m),this._targetElement.appendChild(f),this._targetElement.appendChild(m),b.className="introjs-arrow",y.className="introjs-tooltiptext",y.innerHTML=o.intro,!(v.className="introjs-bullets")===this._options.showBullets&&(v.style.display="none");var C=document.createElement("ul");C.setAttribute("role","tablist");var j=function(){s.goToStep(this.getAttribute("data-stepnumber"))};B(this._introItems,function(t,e){var i=document.createElement("li"),n=document.createElement("a");i.setAttribute("role","presentation"),n.setAttribute("role","tab"),n.onclick=j,e===o.step-1&&(n.className="active"),I(n),n.innerHTML=" ",n.setAttribute("data-stepnumber",t.step),i.appendChild(n),C.appendChild(i)}),v.appendChild(C),!(_.className="introjs-progress")===this._options.showProgress&&(_.style.display="none");var k=document.createElement("div");k.className="introjs-progressbar",k.setAttribute("role","progress"),k.setAttribute("aria-valuemin",0),k.setAttribute("aria-valuemax",100),k.setAttribute("aria-valuenow",z.call(this)),k.style.cssText="width:"+z.call(this)+"%;",_.appendChild(k),!(w.className="introjs-tooltipbuttons")===this._options.showButtons&&(w.style.display="none"),g.className="introjs-tooltip",g.appendChild(y),g.appendChild(v),g.appendChild(_);var x=document.createElement("span");!0===this._options.showStepNumbers&&(x.className="introjs-helperNumberLayer",x.innerHTML=o.step,m.appendChild(x)),g.appendChild(b),m.appendChild(g),(t=document.createElement("a")).onclick=function(){s._introItems.length-1!==s._currentStep&&E.call(s)},I(t),t.innerHTML=this._options.nextLabel,(e=document.createElement("a")).onclick=function(){0!==s._currentStep&&N.call(s)},I(e),e.innerHTML=this._options.prevLabel,(i=document.createElement("a")).className=this._options.buttonClass+" introjs-skipbutton ",I(i),i.innerHTML=this._options.skipLabel,i.onclick=function(){s._introItems.length-1===s._currentStep&&"function"==typeof s._introCompleteCallback&&s._introCompleteCallback.call(s),s._introItems.length-1!==s._currentStep&&"function"==typeof s._introExitCallback&&s._introExitCallback.call(s),"function"==typeof s._introSkipCallback&&s._introSkipCallback.call(s),A.call(s,s._targetElement)},w.appendChild(i),1<this._introItems.length&&(w.appendChild(e),w.appendChild(t)),g.appendChild(w),L.call(s,o.element,g,b,x),P.call(this,o.scrollTo,o,g)}var S=s._targetElement.querySelector(".introjs-disableInteraction");S&&S.parentNode.removeChild(S),o.disableInteraction&&function(){var t=document.querySelector(".introjs-disableInteraction");null===t&&((t=document.createElement("div")).className="introjs-disableInteraction",this._targetElement.appendChild(t)),T.call(this,t)}.call(s),0===this._currentStep&&1<this._introItems.length?(null!=i&&(i.className=this._options.buttonClass+" introjs-skipbutton"),null!=t&&(t.className=this._options.buttonClass+" introjs-nextbutton"),!0===this._options.hidePrev?(null!=e&&(e.className=this._options.buttonClass+" introjs-prevbutton introjs-hidden"),null!=t&&H(t,"introjs-fullbutton")):null!=e&&(e.className=this._options.buttonClass+" introjs-prevbutton introjs-disabled"),null!=i&&(i.innerHTML=this._options.skipLabel)):this._introItems.length-1===this._currentStep||1===this._introItems.length?(null!=i&&(i.innerHTML=this._options.doneLabel,H(i,"introjs-donebutton")),null!=e&&(e.className=this._options.buttonClass+" introjs-prevbutton"),!0===this._options.hideNext?(null!=t&&(t.className=this._options.buttonClass+" introjs-nextbutton introjs-hidden"),null!=e&&H(e,"introjs-fullbutton")):null!=t&&(t.className=this._options.buttonClass+" introjs-nextbutton introjs-disabled")):(null!=i&&(i.className=this._options.buttonClass+" introjs-skipbutton"),null!=e&&(e.className=this._options.buttonClass+" introjs-prevbutton"),null!=t&&(t.className=this._options.buttonClass+" introjs-nextbutton"),null!=i&&(i.innerHTML=this._options.skipLabel)),e.setAttribute("role","button"),t.setAttribute("role","button"),i.setAttribute("role","button"),null!=t&&t.focus(),function(t){var e;if(t.element instanceof SVGElement)for(e=t.element.parentNode;null!==t.element.parentNode&&e.tagName&&"body"!==e.tagName.toLowerCase();)"svg"===e.tagName.toLowerCase()&&H(e,"introjs-showElement introjs-relativePosition"),e=e.parentNode;H(t.element,"introjs-showElement");var i=M(t.element,"position");"absolute"!==i&&"relative"!==i&&"fixed"!==i&&H(t.element,"introjs-relativePosition");e=t.element.parentNode;for(;null!==e&&e.tagName&&"body"!==e.tagName.toLowerCase();){var n=M(e,"z-index"),o=parseFloat(M(e,"opacity")),s=M(e,"transform")||M(e,"-webkit-transform")||M(e,"-moz-transform")||M(e,"-ms-transform")||M(e,"-o-transform");(/[0-9]+/.test(n)||o<1||"none"!==s&&void 0!==s)&&H(e,"introjs-fixParent"),e=e.parentNode}}(o),void 0!==this._introAfterChangeCallback&&this._introAfterChangeCallback.call(this,o.element)}function P(t,e,i){var n,o,s;if("off"!==t&&(this._options.scrollToElement&&(n="tooltip"===t?i.getBoundingClientRect():e.element.getBoundingClientRect(),o=e.element,!(0<=(s=o.getBoundingClientRect()).top&&0<=s.left&&s.bottom+80<=window.innerHeight&&s.right<=window.innerWidth)))){var l=b().height;n.bottom-(n.bottom-n.top)<0||e.element.clientHeight>l?window.scrollBy(0,n.top-(l/2-n.height/2)-this._options.scrollPadding):window.scrollBy(0,n.top-(l/2-n.height/2)+this._options.scrollPadding)}}function q(){B(document.querySelectorAll(".introjs-showElement"),function(t){O(t,/introjs-[a-zA-Z]+/g)})}function B(t,e,i){if(t)for(var n=0,o=t.length;n<o;n++)e(t[n],n);"function"==typeof i&&i()}var o,s=(o={},function(t,e){return o[e=e||"introjs-stamp"]=o[e]||0,void 0===t[e]&&(t[e]=o[e]++),t[e]}),u=new function(){var r="introjs_event";this._id=function(t,e,i,n){return e+s(i)+(n?"_"+s(n):"")},this.on=function(e,t,i,n,o){var s=this._id.apply(this,arguments),l=function(t){return i.call(n||e,t||window.event)};"addEventListener"in e?e.addEventListener(t,l,o):"attachEvent"in e&&e.attachEvent("on"+t,l),e[r]=e[r]||{},e[r][s]=l},this.off=function(t,e,i,n,o){var s=this._id.apply(this,arguments),l=t[r]&&t[r][s];l&&("removeEventListener"in t?t.removeEventListener(e,l,o):"detachEvent"in t&&t.detachEvent("on"+e,l),t[r][s]=null)}};function H(e,t){if(e instanceof SVGElement){var i=e.getAttribute("class")||"";e.setAttribute("class",i+" "+t)}else{if(void 0!==e.classList)B(t.split(" "),function(t){e.classList.add(t)});else e.className.match(t)||(e.className+=" "+t)}}function O(t,e){if(t instanceof SVGElement){var i=t.getAttribute("class")||"";t.setAttribute("class",i.replace(e,"").replace(/^\s+|\s+$/g,""))}else t.className=t.className.replace(e,"").replace(/^\s+|\s+$/g,"")}function M(t,e){var i="";return t.currentStyle?i=t.currentStyle[e]:document.defaultView&&document.defaultView.getComputedStyle&&(i=document.defaultView.getComputedStyle(t,null).getPropertyValue(e)),i&&i.toLowerCase?i.toLowerCase():i}function d(t){var e=t.parentNode;return!(!e||"HTML"===e.nodeName)&&("fixed"===M(t,"position")||d(e))}function b(){if(void 0!==window.innerWidth)return{width:window.innerWidth,height:window.innerHeight};var t=document.documentElement;return{width:t.clientWidth,height:t.clientHeight}}function g(){var t=document.querySelector(".introjs-hintReference");if(t){var e=t.getAttribute("data-step");return t.parentNode.removeChild(t),e}}function l(t){if(this._introItems=[],this._options.hints)B(this._options.hints,function(t){var e=h(t);"string"==typeof e.element&&(e.element=document.querySelector(e.element)),e.hintPosition=e.hintPosition||this._options.hintPosition,e.hintAnimation=e.hintAnimation||this._options.hintAnimation,null!==e.element&&this._introItems.push(e)}.bind(this));else{var e=t.querySelectorAll("*[data-hint]");if(!e||!e.length)return!1;B(e,function(t){var e=t.getAttribute("data-hintanimation");e=e?"true"===e:this._options.hintAnimation,this._introItems.push({element:t,hint:t.getAttribute("data-hint"),hintPosition:t.getAttribute("data-hintposition")||this._options.hintPosition,hintAnimation:e,tooltipClass:t.getAttribute("data-tooltipclass"),position:t.getAttribute("data-position")||this._options.tooltipPosition})}.bind(this))}(function(){var l=this,r=document.querySelector(".introjs-hints");null===r&&((r=document.createElement("div")).className="introjs-hints");B(this._introItems,function(t,e){if(!document.querySelector('.introjs-hint[data-step="'+e+'"]')){var i,n=document.createElement("a");I(n),n.onclick=(i=e,function(t){var e=t||window.event;e.stopPropagation&&e.stopPropagation(),null!==e.cancelBubble&&(e.cancelBubble=!0),j.call(l,i)}),n.className="introjs-hint",t.hintAnimation||H(n,"introjs-hint-no-anim"),d(t.element)&&H(n,"introjs-fixedhint");var o=document.createElement("div");o.className="introjs-hint-dot";var s=document.createElement("div");s.className="introjs-hint-pulse",n.appendChild(o),n.appendChild(s),n.setAttribute("data-step",e),t.targetElement=t.element,t.element=n,C.call(this,t.hintPosition,n,t.targetElement),r.appendChild(n)}}.bind(this)),document.body.appendChild(r),void 0!==this._hintsAddedCallback&&this._hintsAddedCallback.call(this)}).call(this),u.on(document,"click",g,this,!1),u.on(window,"resize",r,this,!0)}function r(){B(this._introItems,function(t){void 0!==t.targetElement&&C.call(this,t.hintPosition,t.element,t.targetElement)}.bind(this))}function y(t){var e=document.querySelector(".introjs-hints");return e?e.querySelectorAll(t):[]}function v(t){var e=y('.introjs-hint[data-step="'+t+'"]')[0];g.call(this),e&&H(e,"introjs-hidehint"),void 0!==this._hintCloseCallback&&this._hintCloseCallback.call(this,t)}function _(t){var e=y('.introjs-hint[data-step="'+t+'"]')[0];e&&O(e,/introjs-hidehint/g)}function w(t){var e=y('.introjs-hint[data-step="'+t+'"]')[0];e&&e.parentNode.removeChild(e)}function C(t,e,i){var n=k.call(this,i);switch(t){default:case"top-left":e.style.left=n.left+"px",e.style.top=n.top+"px";break;case"top-right":e.style.left=n.left+n.width-20+"px",e.style.top=n.top+"px";break;case"bottom-left":e.style.left=n.left+"px",e.style.top=n.top+n.height-20+"px";break;case"bottom-right":e.style.left=n.left+n.width-20+"px",e.style.top=n.top+n.height-20+"px";break;case"middle-left":e.style.left=n.left+"px",e.style.top=n.top+(n.height-20)/2+"px";break;case"middle-right":e.style.left=n.left+n.width-20+"px",e.style.top=n.top+(n.height-20)/2+"px";break;case"middle-middle":e.style.left=n.left+(n.width-20)/2+"px",e.style.top=n.top+(n.height-20)/2+"px";break;case"bottom-middle":e.style.left=n.left+(n.width-20)/2+"px",e.style.top=n.top+n.height-20+"px";break;case"top-middle":e.style.left=n.left+(n.width-20)/2+"px",e.style.top=n.top+"px"}}function j(t){var e=document.querySelector('.introjs-hint[data-step="'+t+'"]'),i=this._introItems[t];void 0!==this._hintClickCallback&&this._hintClickCallback.call(this,e,i,t);var n=g.call(this);if(parseInt(n,10)!==t){var o=document.createElement("div"),s=document.createElement("div"),l=document.createElement("div"),r=document.createElement("div");o.className="introjs-tooltip",o.onclick=function(t){t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},s.className="introjs-tooltiptext";var a=document.createElement("p");a.innerHTML=i.hint;var c=document.createElement("a");c.className=this._options.buttonClass,c.setAttribute("role","button"),c.innerHTML=this._options.hintButtonLabel,c.onclick=v.bind(this,t),s.appendChild(a),s.appendChild(c),l.className="introjs-arrow",o.appendChild(l),o.appendChild(s),this._currentStep=e.getAttribute("data-step"),r.className="introjs-tooltipReferenceLayer introjs-hintReference",r.setAttribute("data-step",e.getAttribute("data-step")),T.call(this,r),r.appendChild(o),document.body.appendChild(r),L.call(this,e,o,l,null,!0)}}function k(t){var e=document.body,i=document.documentElement,n=window.pageYOffset||i.scrollTop||e.scrollTop,o=window.pageXOffset||i.scrollLeft||e.scrollLeft,s=t.getBoundingClientRect();return{top:s.top+n,width:s.width,height:s.height,left:s.left+o}}function R(t){var e=window.getComputedStyle(t),i="absolute"===e.position,n=/(auto|scroll)/;if("fixed"===e.position)return document.body;for(var o=t;o=o.parentElement;)if(e=window.getComputedStyle(o),(!i||"static"!==e.position)&&n.test(e.overflow+e.overflowY+e.overflowX))return o;return document.body}function V(t,e){t.scrollTop=e.offsetTop-t.offsetTop}function z(){return parseInt(this._currentStep+1,10)/this._introItems.length*100}var x=function(t){var e;if("object"==typeof t)e=new n(t);else if("string"==typeof t){var i=document.querySelector(t);if(!i)throw new Error("There is no element with given selector.");e=new n(i)}else e=new n(document.body);return x.instances[s(e,"introjs-instance")]=e};return x.version="2.9.3",x.instances={},x.fn=n.prototype={clone:function(){return new n(this)},setOption:function(t,e){return this._options[t]=e,this},setOptions:function(t){return this._options=function(t,e){var i,n={};for(i in t)n[i]=t[i];for(i in e)n[i]=e[i];return n}(this._options,t),this},start:function(t){return e.call(this,this._targetElement,t),this},goToStep:function(t){return function(t){this._currentStep=t-2,void 0!==this._introItems&&E.call(this)}.call(this,t),this},addStep:function(t){return this._options.steps||(this._options.steps=[]),this._options.steps.push(t),this},addSteps:function(t){if(t.length){for(var e=0;e<t.length;e++)this.addStep(t[e]);return this}},goToStepNumber:function(t){return function(t){this._currentStepNumber=t,void 0!==this._introItems&&E.call(this)}.call(this,t),this},nextStep:function(){return E.call(this),this},previousStep:function(){return N.call(this),this},exit:function(t){return A.call(this,this._targetElement,t),this},refresh:function(){return function(){if(T.call(this,document.querySelector(".introjs-helperLayer")),T.call(this,document.querySelector(".introjs-tooltipReferenceLayer")),T.call(this,document.querySelector(".introjs-disableInteraction")),void 0!==this._currentStep&&null!==this._currentStep){var t=document.querySelector(".introjs-helperNumberLayer"),e=document.querySelector(".introjs-arrow"),i=document.querySelector(".introjs-tooltip");L.call(this,this._introItems[this._currentStep].element,i,e,t)}return r.call(this),this}.call(this),this},onbeforechange:function(t){if("function"!=typeof t)throw new Error("Provided callback for onbeforechange was not a function");return this._introBeforeChangeCallback=t,this},onchange:function(t){if("function"!=typeof t)throw new Error("Provided callback for onchange was not a function.");return this._introChangeCallback=t,this},onafterchange:function(t){if("function"!=typeof t)throw new Error("Provided callback for onafterchange was not a function");return this._introAfterChangeCallback=t,this},oncomplete:function(t){if("function"!=typeof t)throw new Error("Provided callback for oncomplete was not a function.");return this._introCompleteCallback=t,this},onhintsadded:function(t){if("function"!=typeof t)throw new Error("Provided callback for onhintsadded was not a function.");return this._hintsAddedCallback=t,this},onhintclick:function(t){if("function"!=typeof t)throw new Error("Provided callback for onhintclick was not a function.");return this._hintClickCallback=t,this},onhintclose:function(t){if("function"!=typeof t)throw new Error("Provided callback for onhintclose was not a function.");return this._hintCloseCallback=t,this},onexit:function(t){if("function"!=typeof t)throw new Error("Provided callback for onexit was not a function.");return this._introExitCallback=t,this},onskip:function(t){if("function"!=typeof t)throw new Error("Provided callback for onskip was not a function.");return this._introSkipCallback=t,this},onbeforeexit:function(t){if("function"!=typeof t)throw new Error("Provided callback for onbeforeexit was not a function.");return this._introBeforeExitCallback=t,this},addHints:function(){return l.call(this,this._targetElement),this},hideHint:function(t){return v.call(this,t),this},hideHints:function(){return function(){B(y(".introjs-hint"),function(t){v.call(this,t.getAttribute("data-step"))}.bind(this))}.call(this),this},showHint:function(t){return _.call(this,t),this},showHints:function(){return function(){var t=y(".introjs-hint");t&&t.length?B(t,function(t){_.call(this,t.getAttribute("data-step"))}.bind(this)):l.call(this,this._targetElement)}.call(this),this},removeHints:function(){return function(){B(y(".introjs-hint"),function(t){w.call(this,t.getAttribute("data-step"))}.bind(this))}.call(this),this},removeHint:function(t){return w.call(this,t),this},showHintDialog:function(t){return j.call(this,t),this}},x});
|
|
resources/js/plugin.js
CHANGED
@@ -70,15 +70,6 @@ let iCWP_WPSF_OptsPageRender = new function () {
|
|
70 |
};
|
71 |
}();
|
72 |
|
73 |
-
if ( typeof icwp_wpsf_vars_tourmanager !== 'undefined' ) {
|
74 |
-
var iCWP_WPSF_MarkTourFinished = new function () {
|
75 |
-
this.finishedTour = function ( sTourKey ) {
|
76 |
-
icwp_wpsf_vars_tourmanager.ajax[ 'tour_key' ] = sTourKey;
|
77 |
-
jQuery.post( ajaxurl, icwp_wpsf_vars_tourmanager.ajax ).always();
|
78 |
-
};
|
79 |
-
}();
|
80 |
-
}
|
81 |
-
|
82 |
var iCWP_WPSF_Toaster = new function () {
|
83 |
|
84 |
this.showMessage = function ( msg, success ) {
|
@@ -158,7 +149,6 @@ var iCWP_WPSF_OptionsFormSubmit = new function () {
|
|
158 |
},
|
159 |
}
|
160 |
).fail( function () {
|
161 |
-
alert( 'fail()' );
|
162 |
if ( useCompression ) {
|
163 |
handleResponse( raw );
|
164 |
}
|
@@ -414,4 +404,11 @@ if ( typeof icwp_wpsf_vars_plugin !== 'undefined' ) {
|
|
414 |
return false;
|
415 |
} );
|
416 |
} );
|
417 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
};
|
71 |
}();
|
72 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
73 |
var iCWP_WPSF_Toaster = new function () {
|
74 |
|
75 |
this.showMessage = function ( msg, success ) {
|
149 |
},
|
150 |
}
|
151 |
).fail( function () {
|
|
|
152 |
if ( useCompression ) {
|
153 |
handleResponse( raw );
|
154 |
}
|
404 |
return false;
|
405 |
} );
|
406 |
} );
|
407 |
+
}
|
408 |
+
|
409 |
+
jQuery( document ).ready( function () {
|
410 |
+
jQuery( document ).icwpWpsfTours();
|
411 |
+
jQuery( '.select2picker' ).select2({
|
412 |
+
width: 'resolve'
|
413 |
+
});
|
414 |
+
} );
|
resources/js/shield-comments.js
DELETED
@@ -1,137 +0,0 @@
|
|
1 |
-
/** @var shield_comments object */
|
2 |
-
if ( typeof shield_comments !== 'undefined' ) {
|
3 |
-
var iCWP_WPSF_ShieldCommentGuard = new function () {
|
4 |
-
|
5 |
-
var submitButton;
|
6 |
-
var origButtonValue;
|
7 |
-
var nTimerCounter;
|
8 |
-
var sCountdownTimer;
|
9 |
-
|
10 |
-
this.initialise = function () {
|
11 |
-
jQuery( document ).ready( function () {
|
12 |
-
insertPlaceHolder_Gasp( this );
|
13 |
-
} );
|
14 |
-
};
|
15 |
-
|
16 |
-
var reEnableButton = function () {
|
17 |
-
let nRemaining = shield_comments.vars.cooldown - nTimerCounter;
|
18 |
-
submitButton.value = shield_comments.strings.js_comment_wait.replace( "%s", nRemaining );
|
19 |
-
if ( nTimerCounter >= shield_comments.vars.cooldown ) {
|
20 |
-
submitButton.value = origButtonValue;
|
21 |
-
submitButton.disabled = false;
|
22 |
-
clearInterval( sCountdownTimer );
|
23 |
-
}
|
24 |
-
nTimerCounter++;
|
25 |
-
};
|
26 |
-
|
27 |
-
var assignElements = function ( shiep ) {
|
28 |
-
var maybecheckbox = document.getElementById( '_shieldcb_nombre' );
|
29 |
-
if ( typeof (maybecheckbox) === "undefined" || maybecheckbox === null ) {
|
30 |
-
var cbnombre = document.createElement( "input" );
|
31 |
-
cbnombre.type = "hidden";
|
32 |
-
cbnombre.id = "_shieldcb_nombre";
|
33 |
-
cbnombre.name = "cb_nombre";
|
34 |
-
cbnombre.value = shield_comments.vars.cbname;
|
35 |
-
shiep.appendChild( cbnombre );
|
36 |
-
|
37 |
-
document.body.style.cursor = 'wait';
|
38 |
-
submitButton.disabled = true;
|
39 |
-
|
40 |
-
var aAjaxVars = shield_comments.ajax.comment_token;
|
41 |
-
jQuery.post( aAjaxVars.ajaxurl, aAjaxVars,
|
42 |
-
function ( oResponse ) {
|
43 |
-
if ( typeof (oResponse) !== "undefined" && oResponse !== null ) {
|
44 |
-
if ( oResponse.success ) {
|
45 |
-
var inputBotts = document.createElement( "input" );
|
46 |
-
inputBotts.type = "hidden";
|
47 |
-
inputBotts.name = "botts";
|
48 |
-
inputBotts.value = aAjaxVars.ts;
|
49 |
-
var inputToken = document.createElement( "input" );
|
50 |
-
inputToken.type = "hidden";
|
51 |
-
inputToken.name = "comment_token";
|
52 |
-
inputToken.value = oResponse.data.token;
|
53 |
-
|
54 |
-
shiep.appendChild( inputBotts );
|
55 |
-
shiep.appendChild( inputToken );
|
56 |
-
}
|
57 |
-
}
|
58 |
-
}
|
59 |
-
).fail(
|
60 |
-
function () {
|
61 |
-
alert( 'There was a problem with the request. Please try reloading the page.' );
|
62 |
-
}
|
63 |
-
).always( function () {
|
64 |
-
submitButton.disabled = false;
|
65 |
-
document.body.style.cursor = 'default';
|
66 |
-
}
|
67 |
-
);
|
68 |
-
}
|
69 |
-
};
|
70 |
-
|
71 |
-
var reDisableButton = function () {
|
72 |
-
submitButton.value = shield_comments.strings.comment_reload;
|
73 |
-
submitButton.disabled = true;
|
74 |
-
};
|
75 |
-
|
76 |
-
var insertPlaceHolder_Gasp = function ( form ) {
|
77 |
-
var shiep = document.getElementById( shield_comments.vars.uniq );
|
78 |
-
if ( typeof (shiep) === "undefined" || shiep === null ) {
|
79 |
-
return;
|
80 |
-
}
|
81 |
-
|
82 |
-
var shieThe_cb = document.createElement( "input" );
|
83 |
-
shieThe_cb.type = "checkbox";
|
84 |
-
shieThe_cb.value = "Y";
|
85 |
-
shieThe_cb.name = shield_comments.vars.cbname;
|
86 |
-
shieThe_cb.id = '_' + shieThe_cb.name;
|
87 |
-
shieThe_cb.onchange = function () {
|
88 |
-
assignElements( shiep );
|
89 |
-
};
|
90 |
-
|
91 |
-
var shieThe_lab = document.createElement( "label" );
|
92 |
-
var shieThe_labspan = document.createElement( "span" );
|
93 |
-
shieThe_labspan.innerHTML = ' ' + shield_comments.strings.label;
|
94 |
-
|
95 |
-
shieThe_lab.appendChild( shieThe_cb );
|
96 |
-
shieThe_lab.appendChild( shieThe_labspan );
|
97 |
-
|
98 |
-
var shishoney = document.createElement( "input" );
|
99 |
-
shishoney.type = "hidden";
|
100 |
-
shishoney.name = "sugar_sweet_email";
|
101 |
-
|
102 |
-
shiep.appendChild( shishoney );
|
103 |
-
shiep.appendChild( shieThe_lab );
|
104 |
-
|
105 |
-
var comForm = shieThe_cb.form;
|
106 |
-
var subbuttonList = comForm.querySelectorAll( 'input[type="submit"]' );
|
107 |
-
|
108 |
-
if ( typeof (subbuttonList) !== "undefined" ) {
|
109 |
-
|
110 |
-
submitButton = subbuttonList[ 0 ];
|
111 |
-
|
112 |
-
if ( typeof (submitButton) !== "undefined" ) {
|
113 |
-
|
114 |
-
if ( shield_comments.vars.cooldown > 0 ) {
|
115 |
-
submitButton.disabled = true;
|
116 |
-
origButtonValue = submitButton.value;
|
117 |
-
nTimerCounter = 0;
|
118 |
-
reEnableButton();
|
119 |
-
sCountdownTimer = setInterval( reEnableButton, 1000 );
|
120 |
-
}
|
121 |
-
if ( shield_comments.vars.expires > 0 ) {
|
122 |
-
setTimeout( reDisableButton, (1000 * shield_comments.vars.expires - 1000) );
|
123 |
-
}
|
124 |
-
}
|
125 |
-
}
|
126 |
-
|
127 |
-
shieThe_cb.form.onsubmit = function () {
|
128 |
-
if ( shieThe_cb.checked !== true ) {
|
129 |
-
alert( shield_comments.strings.alert );
|
130 |
-
return false;
|
131 |
-
}
|
132 |
-
return true;
|
133 |
-
};
|
134 |
-
};
|
135 |
-
}();
|
136 |
-
iCWP_WPSF_ShieldCommentGuard.initialise();
|
137 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resources/js/shield/antibot.js
ADDED
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
if ( typeof Shield_Antibot === typeof undefined && typeof shield_vars_antibotjs !== typeof undefined ) {
|
2 |
+
|
3 |
+
var Shield_Antibot = new function () {
|
4 |
+
|
5 |
+
var request_count = 0;
|
6 |
+
|
7 |
+
var domReady = function ( fn ) {
|
8 |
+
if ( document.readyState !== 'loading' ) {
|
9 |
+
fn();
|
10 |
+
}
|
11 |
+
else if ( document.addEventListener ) {
|
12 |
+
document.addEventListener( 'DOMContentLoaded', fn );
|
13 |
+
}
|
14 |
+
else {
|
15 |
+
document.attachEvent( 'onreadystatechange', function () {
|
16 |
+
if ( document.readyState !== 'loading' )
|
17 |
+
fn();
|
18 |
+
} );
|
19 |
+
}
|
20 |
+
}
|
21 |
+
|
22 |
+
this.initialise = function () {
|
23 |
+
domReady( function () {
|
24 |
+
fire();
|
25 |
+
} );
|
26 |
+
};
|
27 |
+
|
28 |
+
var fire = function () {
|
29 |
+
var sendRequest = false;
|
30 |
+
var current = getCookie( 'icwp-wpsf-notbot' );
|
31 |
+
if ( current === undefined ) {
|
32 |
+
sendRequest = true;
|
33 |
+
}
|
34 |
+
else {
|
35 |
+
var remaining = current.split( "z" )[ 0 ] - Math.floor( Date.now() / 1000 );
|
36 |
+
if ( remaining < 60 ) {
|
37 |
+
sendRequest = true;
|
38 |
+
}
|
39 |
+
}
|
40 |
+
|
41 |
+
if ( sendRequest && request_count < 11 ) {
|
42 |
+
sendReq();
|
43 |
+
}
|
44 |
+
window.setTimeout( fire, 60000 );
|
45 |
+
};
|
46 |
+
|
47 |
+
var sendReq = function ( name ) {
|
48 |
+
var xhttp = new XMLHttpRequest();
|
49 |
+
xhttp.open( "POST", shield_vars_antibotjs.hrefs.ajax, true );
|
50 |
+
xhttp.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded;' );
|
51 |
+
xhttp.send( shield_vars_antibotjs.ajax.not_bot );
|
52 |
+
request_count++;
|
53 |
+
};
|
54 |
+
|
55 |
+
var getCookie = function ( name ) {
|
56 |
+
var value = "; " + document.cookie;
|
57 |
+
var parts = value.split( "; " + name + "=" );
|
58 |
+
if ( parts.length === 2 ) return parts.pop().split( ";" ).shift();
|
59 |
+
};
|
60 |
+
}();
|
61 |
+
Shield_Antibot.initialise();
|
62 |
+
}
|
resources/js/shield/charts.js
ADDED
@@ -0,0 +1,138 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
jQuery.fn.icwpWpsfChartWithFilters = function ( aOptions ) {
|
2 |
+
|
3 |
+
let resetFilters = function ( evt ) {
|
4 |
+
jQuery( 'select', chartForm ).each( function () {
|
5 |
+
jQuery( this ).prop( 'selectedIndex', 0 );
|
6 |
+
} );
|
7 |
+
opts[ 'chart' ].renderChartFromForm( chartForm );
|
8 |
+
};
|
9 |
+
|
10 |
+
let submitFilters = function ( evt ) {
|
11 |
+
evt.preventDefault();
|
12 |
+
opts[ 'chart' ].renderChartFromForm( chartForm );
|
13 |
+
return false;
|
14 |
+
};
|
15 |
+
|
16 |
+
let initialise = function () {
|
17 |
+
jQuery( document ).ready( function () {
|
18 |
+
chartForm = jQuery( opts[ 'selector_filter_form' ] );
|
19 |
+
chartForm.on( 'click', 'input[type=submit]', submitFilters );
|
20 |
+
chartForm.on( 'click', 'a#ClearForm', resetFilters );
|
21 |
+
} );
|
22 |
+
};
|
23 |
+
|
24 |
+
let $oThis = this;
|
25 |
+
let opts = jQuery.extend( {}, aOptions );
|
26 |
+
let chartForm;
|
27 |
+
initialise();
|
28 |
+
|
29 |
+
return this;
|
30 |
+
};
|
31 |
+
|
32 |
+
jQuery.fn.icwpWpsfAjaxChart = function ( options ) {
|
33 |
+
|
34 |
+
this.reloadChart = function () {
|
35 |
+
reqRenderChart();
|
36 |
+
};
|
37 |
+
|
38 |
+
let createChartContainer = function () {
|
39 |
+
chartTitleContainer = jQuery( '#CustomChartTitle' );
|
40 |
+
chartContainer = jQuery( '<div />' ).appendTo( $oThis );
|
41 |
+
chartContainer.addClass( 'icwpAjaxContainerChart' )
|
42 |
+
.addClass( 'ct-chart' );
|
43 |
+
};
|
44 |
+
|
45 |
+
let refreshChart = function ( event ) {
|
46 |
+
event.preventDefault();
|
47 |
+
let aChartRequestParams = {};
|
48 |
+
reqRenderChart( aChartRequestParams );
|
49 |
+
};
|
50 |
+
|
51 |
+
this.renderChartFromForm = function ( $oForm ) {
|
52 |
+
reqRenderChart( { 'form_params': $oForm.serialize() } );
|
53 |
+
};
|
54 |
+
|
55 |
+
let reqRenderChart = function ( reqParams ) {
|
56 |
+
if ( bReqRunning ) {
|
57 |
+
return false;
|
58 |
+
}
|
59 |
+
bReqRunning = true;
|
60 |
+
|
61 |
+
chartContainer.html( 'Loading...' );
|
62 |
+
chartTitleContainer.html( '' );
|
63 |
+
jQuery.post( ajaxurl, jQuery.extend( opts[ 'ajax_render' ], opts[ 'req_params' ], reqParams ),
|
64 |
+
function ( response ) {
|
65 |
+
|
66 |
+
if ( !response.success ) {
|
67 |
+
alert( response.data.message );
|
68 |
+
}
|
69 |
+
else {
|
70 |
+
if ( opts[ 'show_title' ] && typeof response.data.chart.title !== typeof undefined ) {
|
71 |
+
chartTitleContainer.html( response.data.chart.title );
|
72 |
+
}
|
73 |
+
|
74 |
+
chartContainer.html( '' );
|
75 |
+
new Chartist.Line(
|
76 |
+
$oThis[ 0 ].querySelectorAll( '.icwpAjaxContainerChart' )[ 0 ],
|
77 |
+
response.data.chart.data,
|
78 |
+
jQuery.extend( {
|
79 |
+
fullWidth: true,
|
80 |
+
showArea: false,
|
81 |
+
chartPadding: {
|
82 |
+
top: 10,
|
83 |
+
right: 10,
|
84 |
+
bottom: 10,
|
85 |
+
left: 10
|
86 |
+
},
|
87 |
+
axisX: {
|
88 |
+
showLabel: true,
|
89 |
+
showGrid: true,
|
90 |
+
},
|
91 |
+
axisY: {
|
92 |
+
onlyInteger: true,
|
93 |
+
showLabel: true,
|
94 |
+
labelInterpolationFnc: function ( value ) {
|
95 |
+
return value;
|
96 |
+
}
|
97 |
+
},
|
98 |
+
plugins: [
|
99 |
+
Chartist.plugins.legend( {
|
100 |
+
legendNames: response.data.chart.legend
|
101 |
+
} )
|
102 |
+
]
|
103 |
+
}, opts[ 'chart_options' ] )
|
104 |
+
);
|
105 |
+
}
|
106 |
+
}
|
107 |
+
).always(
|
108 |
+
function () {
|
109 |
+
bReqRunning = false;
|
110 |
+
}
|
111 |
+
);
|
112 |
+
};
|
113 |
+
|
114 |
+
let setHandlers = function () {
|
115 |
+
};
|
116 |
+
|
117 |
+
let initialise = function () {
|
118 |
+
jQuery( document ).ready( function () {
|
119 |
+
createChartContainer();
|
120 |
+
if ( opts[ 'init_render' ] ) {
|
121 |
+
reqRenderChart();
|
122 |
+
}
|
123 |
+
setHandlers();
|
124 |
+
} );
|
125 |
+
};
|
126 |
+
|
127 |
+
let $oThis = this;
|
128 |
+
let chartContainer;
|
129 |
+
let chartTitleContainer;
|
130 |
+
let bReqRunning = false;
|
131 |
+
let opts = jQuery.extend( {
|
132 |
+
init_render: true,
|
133 |
+
show_title: false
|
134 |
+
}, options );
|
135 |
+
initialise();
|
136 |
+
|
137 |
+
return this;
|
138 |
+
};
|
resources/js/shield/comments.js
ADDED
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/** @var shield_comments object */
|
2 |
+
var iCWP_WPSF_ShieldCommentGuard = new function () {
|
3 |
+
|
4 |
+
var submitButton;
|
5 |
+
var origButtonValue;
|
6 |
+
var nTimerCounter;
|
7 |
+
var sCountdownTimer;
|
8 |
+
|
9 |
+
this.initialise = function () {
|
10 |
+
jQuery( document ).ready( function () {
|
11 |
+
if ( typeof shield_comments !== 'undefined' ) {
|
12 |
+
insertPlaceHolder_Gasp( this );
|
13 |
+
}
|
14 |
+
} );
|
15 |
+
};
|
16 |
+
|
17 |
+
var reEnableButton = function () {
|
18 |
+
let nRemaining = shield_comments.vars.cooldown - nTimerCounter;
|
19 |
+
submitButton.value = shield_comments.strings.js_comment_wait.replace( "%s", nRemaining );
|
20 |
+
if ( nTimerCounter >= shield_comments.vars.cooldown ) {
|
21 |
+
submitButton.value = origButtonValue;
|
22 |
+
submitButton.disabled = false;
|
23 |
+
clearInterval( sCountdownTimer );
|
24 |
+
}
|
25 |
+
nTimerCounter++;
|
26 |
+
};
|
27 |
+
|
28 |
+
var assignElements = function ( shiep ) {
|
29 |
+
var maybecheckbox = document.getElementById( '_shieldcb_nombre' );
|
30 |
+
if ( typeof (maybecheckbox) === "undefined" || maybecheckbox === null ) {
|
31 |
+
var cbnombre = document.createElement( "input" );
|
32 |
+
cbnombre.type = "hidden";
|
33 |
+
cbnombre.id = "_shieldcb_nombre";
|
34 |
+
cbnombre.name = "cb_nombre";
|
35 |
+
cbnombre.value = shield_comments.vars.cbname;
|
36 |
+
shiep.appendChild( cbnombre );
|
37 |
+
|
38 |
+
document.body.style.cursor = 'wait';
|
39 |
+
submitButton.disabled = true;
|
40 |
+
|
41 |
+
var aAjaxVars = shield_comments.ajax.comment_token;
|
42 |
+
jQuery.post( aAjaxVars.ajaxurl, aAjaxVars,
|
43 |
+
function ( oResponse ) {
|
44 |
+
if ( typeof (oResponse) !== "undefined" && oResponse !== null ) {
|
45 |
+
if ( oResponse.success ) {
|
46 |
+
var inputBotts = document.createElement( "input" );
|
47 |
+
inputBotts.type = "hidden";
|
48 |
+
inputBotts.name = "botts";
|
49 |
+
inputBotts.value = aAjaxVars.ts;
|
50 |
+
var inputToken = document.createElement( "input" );
|
51 |
+
inputToken.type = "hidden";
|
52 |
+
inputToken.name = "comment_token";
|
53 |
+
inputToken.value = oResponse.data.token;
|
54 |
+
|
55 |
+
shiep.appendChild( inputBotts );
|
56 |
+
shiep.appendChild( inputToken );
|
57 |
+
}
|
58 |
+
}
|
59 |
+
}
|
60 |
+
).fail(
|
61 |
+
function () {
|
62 |
+
alert( 'There was a problem with the request. Please try reloading the page.' );
|
63 |
+
}
|
64 |
+
).always( function () {
|
65 |
+
submitButton.disabled = false;
|
66 |
+
document.body.style.cursor = 'default';
|
67 |
+
}
|
68 |
+
);
|
69 |
+
}
|
70 |
+
};
|
71 |
+
|
72 |
+
var reDisableButton = function () {
|
73 |
+
submitButton.value = shield_comments.strings.comment_reload;
|
74 |
+
submitButton.disabled = true;
|
75 |
+
};
|
76 |
+
|
77 |
+
var insertPlaceHolder_Gasp = function ( form ) {
|
78 |
+
var shiep = document.getElementById( shield_comments.vars.uniq );
|
79 |
+
if ( typeof (shiep) === "undefined" || shiep === null ) {
|
80 |
+
return;
|
81 |
+
}
|
82 |
+
|
83 |
+
var shieThe_cb = document.createElement( "input" );
|
84 |
+
shieThe_cb.type = "checkbox";
|
85 |
+
shieThe_cb.value = "Y";
|
86 |
+
shieThe_cb.name = shield_comments.vars.cbname;
|
87 |
+
shieThe_cb.id = '_' + shieThe_cb.name;
|
88 |
+
shieThe_cb.onchange = function () {
|
89 |
+
assignElements( shiep );
|
90 |
+
};
|
91 |
+
|
92 |
+
var shieThe_lab = document.createElement( "label" );
|
93 |
+
var shieThe_labspan = document.createElement( "span" );
|
94 |
+
shieThe_labspan.innerHTML = ' ' + shield_comments.strings.label;
|
95 |
+
|
96 |
+
shieThe_lab.appendChild( shieThe_cb );
|
97 |
+
shieThe_lab.appendChild( shieThe_labspan );
|
98 |
+
|
99 |
+
var shishoney = document.createElement( "input" );
|
100 |
+
shishoney.type = "hidden";
|
101 |
+
shishoney.name = "sugar_sweet_email";
|
102 |
+
|
103 |
+
shiep.appendChild( shishoney );
|
104 |
+
shiep.appendChild( shieThe_lab );
|
105 |
+
|
106 |
+
var comForm = shieThe_cb.form;
|
107 |
+
var subbuttonList = comForm.querySelectorAll( 'input[type="submit"]' );
|
108 |
+
|
109 |
+
if ( typeof (subbuttonList) !== "undefined" ) {
|
110 |
+
|
111 |
+
submitButton = subbuttonList[ 0 ];
|
112 |
+
|
113 |
+
if ( typeof (submitButton) !== "undefined" ) {
|
114 |
+
|
115 |
+
if ( shield_comments.vars.cooldown > 0 ) {
|
116 |
+
submitButton.disabled = true;
|
117 |
+
origButtonValue = submitButton.value;
|
118 |
+
nTimerCounter = 0;
|
119 |
+
reEnableButton();
|
120 |
+
sCountdownTimer = setInterval( reEnableButton, 1000 );
|
121 |
+
}
|
122 |
+
if ( shield_comments.vars.expires > 0 ) {
|
123 |
+
setTimeout( reDisableButton, (1000 * shield_comments.vars.expires - 1000) );
|
124 |
+
}
|
125 |
+
}
|
126 |
+
}
|
127 |
+
|
128 |
+
shieThe_cb.form.onsubmit = function () {
|
129 |
+
if ( shieThe_cb.checked !== true ) {
|
130 |
+
alert( shield_comments.strings.alert );
|
131 |
+
return false;
|
132 |
+
}
|
133 |
+
return true;
|
134 |
+
};
|
135 |
+
};
|
136 |
+
}();
|
137 |
+
iCWP_WPSF_ShieldCommentGuard.initialise();
|
resources/js/shield/ipanalyse.js
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
jQuery.fn.icwpWpsfIpAnalyse = function ( options ) {
|
2 |
|
3 |
var runAnalysis = function () {
|
4 |
-
let newUrl = window.location.href.replace( /&analyse_ip
|
5 |
if ( $oIpSelect.val().length > 0 ) {
|
6 |
newUrl += "&analyse_ip=" + $oIpSelect.val();
|
7 |
}
|
@@ -18,7 +18,7 @@ jQuery.fn.icwpWpsfIpAnalyse = function ( options ) {
|
|
18 |
window.history.replaceState(
|
19 |
{},
|
20 |
document.title,
|
21 |
-
window.location.href.replace( /&analyse_ip
|
22 |
);
|
23 |
};
|
24 |
|
@@ -35,15 +35,18 @@ jQuery.fn.icwpWpsfIpAnalyse = function ( options ) {
|
|
35 |
jQuery( '#IpSelectContent' ).addClass( "d-none" );
|
36 |
jQuery( '#IpReviewContent' ).removeClass( "d-none" )
|
37 |
.html( oResponse.data.html );
|
|
|
|
|
|
|
38 |
}
|
39 |
else {
|
40 |
-
var
|
41 |
if ( oResponse.data.message !== undefined ) {
|
42 |
-
|
43 |
}
|
44 |
jQuery( '#IpSelectContent' ).removeClass( "d-none" );
|
45 |
jQuery( '#IpReviewContent' ).addClass( "d-none" );
|
46 |
-
alert(
|
47 |
}
|
48 |
|
49 |
}
|
@@ -79,7 +82,7 @@ jQuery.fn.icwpWpsfIpAnalyse = function ( options ) {
|
|
79 |
let urlParams = new URLSearchParams( window.location.search );
|
80 |
let theIP = urlParams.get( 'analyse_ip' );
|
81 |
if ( theIP ) {
|
82 |
-
$oIpSelect.
|
83 |
runAnalysis();
|
84 |
}
|
85 |
else {
|
1 |
jQuery.fn.icwpWpsfIpAnalyse = function ( options ) {
|
2 |
|
3 |
var runAnalysis = function () {
|
4 |
+
let newUrl = window.location.href.replace( /&analyse_ip=.+/i, "" );
|
5 |
if ( $oIpSelect.val().length > 0 ) {
|
6 |
newUrl += "&analyse_ip=" + $oIpSelect.val();
|
7 |
}
|
18 |
window.history.replaceState(
|
19 |
{},
|
20 |
document.title,
|
21 |
+
window.location.href.replace( /&analyse_ip=.*/i, "" )
|
22 |
);
|
23 |
};
|
24 |
|
35 |
jQuery( '#IpSelectContent' ).addClass( "d-none" );
|
36 |
jQuery( '#IpReviewContent' ).removeClass( "d-none" )
|
37 |
.html( oResponse.data.html );
|
38 |
+
if ( oResponse.page_reload ) {
|
39 |
+
location.reload();
|
40 |
+
}
|
41 |
}
|
42 |
else {
|
43 |
+
var msg = 'Communications error with site.';
|
44 |
if ( oResponse.data.message !== undefined ) {
|
45 |
+
msg = oResponse.data.message;
|
46 |
}
|
47 |
jQuery( '#IpSelectContent' ).removeClass( "d-none" );
|
48 |
jQuery( '#IpReviewContent' ).addClass( "d-none" );
|
49 |
+
alert( msg );
|
50 |
}
|
51 |
|
52 |
}
|
82 |
let urlParams = new URLSearchParams( window.location.search );
|
83 |
let theIP = urlParams.get( 'analyse_ip' );
|
84 |
if ( theIP ) {
|
85 |
+
$oIpSelect.val( theIP );
|
86 |
runAnalysis();
|
87 |
}
|
88 |
else {
|
resources/js/{shield-antibot.js → shield/loginbot.js}
RENAMED
@@ -43,9 +43,9 @@ var iCWP_WPSF_LoginGuard_Gasp = new function () {
|
|
43 |
};
|
44 |
|
45 |
var cleanDuplicates = function ( form ) {
|
46 |
-
let $
|
47 |
-
if ( $
|
48 |
-
$
|
49 |
function ( nkey ) {
|
50 |
if ( nkey > 0 && this !== null ) {
|
51 |
jQuery( this ).remove();
|
@@ -65,39 +65,47 @@ var iCWP_WPSF_LoginGuard_Gasp = new function () {
|
|
65 |
};
|
66 |
|
67 |
var processPlaceHolder_Gasp = function ( shiep ) {
|
68 |
-
var shishoney = document.createElement( "input" );
|
69 |
-
shishoney.type = "hidden";
|
70 |
-
shishoney.name = "icwp_wpsf_login_email";
|
71 |
-
|
72 |
-
shiep.innerHTML = '';
|
73 |
-
shiep.appendChild( shishoney );
|
74 |
-
|
75 |
var shieThe_lab = document.createElement( "label" );
|
76 |
var shieThe_txt = document.createTextNode( ' ' + icwp_wpsf_vars_lpantibot.strings.label );
|
77 |
var shieThe_cb = document.createElement( "input" );
|
78 |
-
|
79 |
-
|
80 |
-
shieThe_cb.id = '_' + shieThe_cb.name;
|
81 |
-
shiep.appendChild( shieThe_lab );
|
82 |
-
shieThe_lab.appendChild( shieThe_cb );
|
83 |
-
shieThe_lab.appendChild( shieThe_txt );
|
84 |
|
85 |
let $oPH = jQuery( shiep );
|
86 |
if ( [ 'p', 'P' ].includes( $oPH.parent()[ 0 ].nodeName ) ) {
|
87 |
-
/**
|
88 |
jQuery( shiep ).insertBefore( $oPH.parent() )
|
89 |
}
|
90 |
|
91 |
-
let
|
92 |
-
if (
|
93 |
-
|
94 |
-
if ( shieThe_cb.checked
|
|
|
|
|
|
|
|
|
|
|
95 |
alert( icwp_wpsf_vars_lpantibot.strings.alert );
|
96 |
-
|
97 |
}
|
98 |
-
return
|
99 |
};
|
|
|
|
|
|
|
|
|
|
|
100 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
101 |
};
|
102 |
}();
|
103 |
iCWP_WPSF_LoginGuard_Gasp.initialise();
|
43 |
};
|
44 |
|
45 |
var cleanDuplicates = function ( form ) {
|
46 |
+
let $placeHolders = jQuery( 'p.shield_gasp_placeholder', form );
|
47 |
+
if ( $placeHolders.length > 1 ) {
|
48 |
+
$placeHolders.each(
|
49 |
function ( nkey ) {
|
50 |
if ( nkey > 0 && this !== null ) {
|
51 |
jQuery( this ).remove();
|
65 |
};
|
66 |
|
67 |
var processPlaceHolder_Gasp = function ( shiep ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
var shieThe_lab = document.createElement( "label" );
|
69 |
var shieThe_txt = document.createTextNode( ' ' + icwp_wpsf_vars_lpantibot.strings.label );
|
70 |
var shieThe_cb = document.createElement( "input" );
|
71 |
+
|
72 |
+
shiep.style.display = "inherit";
|
|
|
|
|
|
|
|
|
73 |
|
74 |
let $oPH = jQuery( shiep );
|
75 |
if ( [ 'p', 'P' ].includes( $oPH.parent()[ 0 ].nodeName ) ) {
|
76 |
+
/** prevent nested paragraphs */
|
77 |
jQuery( shiep ).insertBefore( $oPH.parent() )
|
78 |
}
|
79 |
|
80 |
+
let parentForm = $oPH.closest( 'form' );
|
81 |
+
if ( parentForm.length > 0 ) {
|
82 |
+
parentForm[ 0 ].addEventListener( "mouseover", function () {
|
83 |
+
if ( !shieThe_cb.checked ) {
|
84 |
+
// shieThe_cb.checked = true;
|
85 |
+
}
|
86 |
+
} );
|
87 |
+
parentForm[ 0 ].onsubmit = function () {
|
88 |
+
if ( !shieThe_cb.checked ) {
|
89 |
alert( icwp_wpsf_vars_lpantibot.strings.alert );
|
90 |
+
shiep.style.display = "inherit";
|
91 |
}
|
92 |
+
return shieThe_cb.checked;
|
93 |
};
|
94 |
+
|
95 |
+
var shishoney = document.createElement( "input" );
|
96 |
+
shishoney.type = "hidden";
|
97 |
+
shishoney.name = "icwp_wpsf_login_email";
|
98 |
+
parentForm[ 0 ].appendChild( shishoney );
|
99 |
}
|
100 |
+
|
101 |
+
shiep.innerHTML = '';
|
102 |
+
|
103 |
+
shieThe_cb.type = "checkbox";
|
104 |
+
shieThe_cb.name = icwp_wpsf_vars_lpantibot.cbname;
|
105 |
+
shieThe_cb.id = '_' + shieThe_cb.name;
|
106 |
+
shiep.appendChild( shieThe_lab );
|
107 |
+
shieThe_lab.appendChild( shieThe_cb );
|
108 |
+
shieThe_lab.appendChild( shieThe_txt );
|
109 |
};
|
110 |
}();
|
111 |
iCWP_WPSF_LoginGuard_Gasp.initialise();
|
resources/js/{shield-card-shuffle.js → shield/shuffle.js}
RENAMED
File without changes
|
resources/js/shield/tours.js
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
jQuery.fn.icwpWpsfTours = function ( options ) {
|
2 |
+
|
3 |
+
var setupAllTours = function ( forceShow = false ) {
|
4 |
+
shield_vars_tourmanager.tours.forEach( function ( tour_key, i ) {
|
5 |
+
if ( forceShow || !(tour_key in shield_vars_tourmanager.tour_states) ) {
|
6 |
+
setupTour( tour_key, forceShow );
|
7 |
+
}
|
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",
|
24 |
+
showProgress: true,
|
25 |
+
scrollToElement: true
|
26 |
+
}
|
27 |
+
};
|
28 |
+
|
29 |
+
var markTourFinished = function ( tourKey ) {
|
30 |
+
shield_vars_tourmanager.ajax[ 'tour_key' ] = tourKey;
|
31 |
+
jQuery.post( ajaxurl, shield_vars_tourmanager.ajax );
|
32 |
+
};
|
33 |
+
|
34 |
+
var initialise = function () {
|
35 |
+
jQuery( document ).ready( function () {
|
36 |
+
setupAllTours( false );
|
37 |
+
} );
|
38 |
+
};
|
39 |
+
|
40 |
+
initialise();
|
41 |
+
|
42 |
+
return this;
|
43 |
+
};
|
resources/js/shuffle.js
DELETED
@@ -1,2190 +0,0 @@
|
|
1 |
-
(function (global, factory) {
|
2 |
-
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
3 |
-
typeof define === 'function' && define.amd ? define(factory) :
|
4 |
-
(global = global || self, global.Shuffle = factory());
|
5 |
-
}(this, function () { 'use strict';
|
6 |
-
|
7 |
-
function _classCallCheck(instance, Constructor) {
|
8 |
-
if (!(instance instanceof Constructor)) {
|
9 |
-
throw new TypeError("Cannot call a class as a function");
|
10 |
-
}
|
11 |
-
}
|
12 |
-
|
13 |
-
function _defineProperties(target, props) {
|
14 |
-
for (var i = 0; i < props.length; i++) {
|
15 |
-
var descriptor = props[i];
|
16 |
-
descriptor.enumerable = descriptor.enumerable || false;
|
17 |
-
descriptor.configurable = true;
|
18 |
-
if ("value" in descriptor) descriptor.writable = true;
|
19 |
-
Object.defineProperty(target, descriptor.key, descriptor);
|
20 |
-
}
|
21 |
-
}
|
22 |
-
|
23 |
-
function _createClass(Constructor, protoProps, staticProps) {
|
24 |
-
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
|
25 |
-
if (staticProps) _defineProperties(Constructor, staticProps);
|
26 |
-
return Constructor;
|
27 |
-
}
|
28 |
-
|
29 |
-
function _inherits(subClass, superClass) {
|
30 |
-
if (typeof superClass !== "function" && superClass !== null) {
|
31 |
-
throw new TypeError("Super expression must either be null or a function");
|
32 |
-
}
|
33 |
-
|
34 |
-
subClass.prototype = Object.create(superClass && superClass.prototype, {
|
35 |
-
constructor: {
|
36 |
-
value: subClass,
|
37 |
-
writable: true,
|
38 |
-
configurable: true
|
39 |
-
}
|
40 |
-
});
|
41 |
-
if (superClass) _setPrototypeOf(subClass, superClass);
|
42 |
-
}
|
43 |
-
|
44 |
-
function _getPrototypeOf(o) {
|
45 |
-
_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
|
46 |
-
return o.__proto__ || Object.getPrototypeOf(o);
|
47 |
-
};
|
48 |
-
return _getPrototypeOf(o);
|
49 |
-
}
|
50 |
-
|
51 |
-
function _setPrototypeOf(o, p) {
|
52 |
-
_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
|
53 |
-
o.__proto__ = p;
|
54 |
-
return o;
|
55 |
-
};
|
56 |
-
|
57 |
-
return _setPrototypeOf(o, p);
|
58 |
-
}
|
59 |
-
|
60 |
-
function _assertThisInitialized(self) {
|
61 |
-
if (self === void 0) {
|
62 |
-
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
|
63 |
-
}
|
64 |
-
|
65 |
-
return self;
|
66 |
-
}
|
67 |
-
|
68 |
-
function _possibleConstructorReturn(self, call) {
|
69 |
-
if (call && (typeof call === "object" || typeof call === "function")) {
|
70 |
-
return call;
|
71 |
-
}
|
72 |
-
|
73 |
-
return _assertThisInitialized(self);
|
74 |
-
}
|
75 |
-
|
76 |
-
function E () {
|
77 |
-
// Keep this empty so it's easier to inherit from
|
78 |
-
// (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
|
79 |
-
}
|
80 |
-
|
81 |
-
E.prototype = {
|
82 |
-
on: function (name, callback, ctx) {
|
83 |
-
var e = this.e || (this.e = {});
|
84 |
-
|
85 |
-
(e[name] || (e[name] = [])).push({
|
86 |
-
fn: callback,
|
87 |
-
ctx: ctx
|
88 |
-
});
|
89 |
-
|
90 |
-
return this;
|
91 |
-
},
|
92 |
-
|
93 |
-
once: function (name, callback, ctx) {
|
94 |
-
var self = this;
|
95 |
-
function listener () {
|
96 |
-
self.off(name, listener);
|
97 |
-
callback.apply(ctx, arguments);
|
98 |
-
}
|
99 |
-
listener._ = callback;
|
100 |
-
return this.on(name, listener, ctx);
|
101 |
-
},
|
102 |
-
|
103 |
-
emit: function (name) {
|
104 |
-
var data = [].slice.call(arguments, 1);
|
105 |
-
var evtArr = ((this.e || (this.e = {}))[name] || []).slice();
|
106 |
-
var i = 0;
|
107 |
-
var len = evtArr.length;
|
108 |
-
|
109 |
-
for (i; i < len; i++) {
|
110 |
-
evtArr[i].fn.apply(evtArr[i].ctx, data);
|
111 |
-
}
|
112 |
-
|
113 |
-
return this;
|
114 |
-
},
|
115 |
-
|
116 |
-
off: function (name, callback) {
|
117 |
-
var e = this.e || (this.e = {});
|
118 |
-
var evts = e[name];
|
119 |
-
var liveEvents = [];
|
120 |
-
|
121 |
-
if (evts && callback) {
|
122 |
-
for (var i = 0, len = evts.length; i < len; i++) {
|
123 |
-
if (evts[i].fn !== callback && evts[i].fn._ !== callback)
|
124 |
-
liveEvents.push(evts[i]);
|
125 |
-
}
|
126 |
-
}
|
127 |
-
|
128 |
-
// Remove event from queue to prevent memory leak
|
129 |
-
// Suggested by https://github.com/lazd
|
130 |
-
// Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910
|
131 |
-
|
132 |
-
(liveEvents.length)
|
133 |
-
? e[name] = liveEvents
|
134 |
-
: delete e[name];
|
135 |
-
|
136 |
-
return this;
|
137 |
-
}
|
138 |
-
};
|
139 |
-
|
140 |
-
var tinyEmitter = E;
|
141 |
-
var TinyEmitter = E;
|
142 |
-
tinyEmitter.TinyEmitter = TinyEmitter;
|
143 |
-
|
144 |
-
var proto = typeof Element !== 'undefined' ? Element.prototype : {};
|
145 |
-
var vendor = proto.matches
|
146 |
-
|| proto.matchesSelector
|
147 |
-
|| proto.webkitMatchesSelector
|
148 |
-
|| proto.mozMatchesSelector
|
149 |
-
|| proto.msMatchesSelector
|
150 |
-
|| proto.oMatchesSelector;
|
151 |
-
|
152 |
-
var matchesSelector = match;
|
153 |
-
|
154 |
-
/**
|
155 |
-
* Match `el` to `selector`.
|
156 |
-
*
|
157 |
-
* @param {Element} el
|
158 |
-
* @param {String} selector
|
159 |
-
* @return {Boolean}
|
160 |
-
* @api public
|
161 |
-
*/
|
162 |
-
|
163 |
-
function match(el, selector) {
|
164 |
-
if (!el || el.nodeType !== 1) return false;
|
165 |
-
if (vendor) return vendor.call(el, selector);
|
166 |
-
var nodes = el.parentNode.querySelectorAll(selector);
|
167 |
-
for (var i = 0; i < nodes.length; i++) {
|
168 |
-
if (nodes[i] == el) return true;
|
169 |
-
}
|
170 |
-
return false;
|
171 |
-
}
|
172 |
-
|
173 |
-
var throttleit = throttle;
|
174 |
-
|
175 |
-
/**
|
176 |
-
* Returns a new function that, when invoked, invokes `func` at most once per `wait` milliseconds.
|
177 |
-
*
|
178 |
-
* @param {Function} func Function to wrap.
|
179 |
-
* @param {Number} wait Number of milliseconds that must elapse between `func` invocations.
|
180 |
-
* @return {Function} A new function that wraps the `func` function passed in.
|
181 |
-
*/
|
182 |
-
|
183 |
-
function throttle (func, wait) {
|
184 |
-
var ctx, args, rtn, timeoutID; // caching
|
185 |
-
var last = 0;
|
186 |
-
|
187 |
-
return function throttled () {
|
188 |
-
ctx = this;
|
189 |
-
args = arguments;
|
190 |
-
var delta = new Date() - last;
|
191 |
-
if (!timeoutID)
|
192 |
-
if (delta >= wait) call();
|
193 |
-
else timeoutID = setTimeout(call, wait - delta);
|
194 |
-
return rtn;
|
195 |
-
};
|
196 |
-
|
197 |
-
function call () {
|
198 |
-
timeoutID = 0;
|
199 |
-
last = +new Date();
|
200 |
-
rtn = func.apply(ctx, args);
|
201 |
-
ctx = null;
|
202 |
-
args = null;
|
203 |
-
}
|
204 |
-
}
|
205 |
-
|
206 |
-
var arrayParallel = function parallel(fns, context, callback) {
|
207 |
-
if (!callback) {
|
208 |
-
if (typeof context === 'function') {
|
209 |
-
callback = context;
|
210 |
-
context = null;
|
211 |
-
} else {
|
212 |
-
callback = noop;
|
213 |
-
}
|
214 |
-
}
|
215 |
-
|
216 |
-
var pending = fns && fns.length;
|
217 |
-
if (!pending) return callback(null, []);
|
218 |
-
|
219 |
-
var finished = false;
|
220 |
-
var results = new Array(pending);
|
221 |
-
|
222 |
-
fns.forEach(context ? function (fn, i) {
|
223 |
-
fn.call(context, maybeDone(i));
|
224 |
-
} : function (fn, i) {
|
225 |
-
fn(maybeDone(i));
|
226 |
-
});
|
227 |
-
|
228 |
-
function maybeDone(i) {
|
229 |
-
return function (err, result) {
|
230 |
-
if (finished) return;
|
231 |
-
|
232 |
-
if (err) {
|
233 |
-
callback(err, results);
|
234 |
-
finished = true;
|
235 |
-
return
|
236 |
-
}
|
237 |
-
|
238 |
-
results[i] = result;
|
239 |
-
|
240 |
-
if (!--pending) callback(null, results);
|
241 |
-
}
|
242 |
-
}
|
243 |
-
};
|
244 |
-
|
245 |
-
function noop() {}
|
246 |
-
|
247 |
-
/**
|
248 |
-
* Always returns a numeric value, given a value. Logic from jQuery's `isNumeric`.
|
249 |
-
* @param {*} value Possibly numeric value.
|
250 |
-
* @return {number} `value` or zero if `value` isn't numeric.
|
251 |
-
*/
|
252 |
-
function getNumber(value) {
|
253 |
-
return parseFloat(value) || 0;
|
254 |
-
}
|
255 |
-
|
256 |
-
var Point =
|
257 |
-
/*#__PURE__*/
|
258 |
-
function () {
|
259 |
-
/**
|
260 |
-
* Represents a coordinate pair.
|
261 |
-
* @param {number} [x=0] X.
|
262 |
-
* @param {number} [y=0] Y.
|
263 |
-
*/
|
264 |
-
function Point(x, y) {
|
265 |
-
_classCallCheck(this, Point);
|
266 |
-
|
267 |
-
this.x = getNumber(x);
|
268 |
-
this.y = getNumber(y);
|
269 |
-
}
|
270 |
-
/**
|
271 |
-
* Whether two points are equal.
|
272 |
-
* @param {Point} a Point A.
|
273 |
-
* @param {Point} b Point B.
|
274 |
-
* @return {boolean}
|
275 |
-
*/
|
276 |
-
|
277 |
-
|
278 |
-
_createClass(Point, null, [{
|
279 |
-
key: "equals",
|
280 |
-
value: function equals(a, b) {
|
281 |
-
return a.x === b.x && a.y === b.y;
|
282 |
-
}
|
283 |
-
}]);
|
284 |
-
|
285 |
-
return Point;
|
286 |
-
}();
|
287 |
-
|
288 |
-
var Rect =
|
289 |
-
/*#__PURE__*/
|
290 |
-
function () {
|
291 |
-
/**
|
292 |
-
* Class for representing rectangular regions.
|
293 |
-
* https://github.com/google/closure-library/blob/master/closure/goog/math/rect.js
|
294 |
-
* @param {number} x Left.
|
295 |
-
* @param {number} y Top.
|
296 |
-
* @param {number} w Width.
|
297 |
-
* @param {number} h Height.
|
298 |
-
* @param {number} id Identifier
|
299 |
-
* @constructor
|
300 |
-
*/
|
301 |
-
function Rect(x, y, w, h, id) {
|
302 |
-
_classCallCheck(this, Rect);
|
303 |
-
|
304 |
-
this.id = id;
|
305 |
-
/** @type {number} */
|
306 |
-
|
307 |
-
this.left = x;
|
308 |
-
/** @type {number} */
|
309 |
-
|
310 |
-
this.top = y;
|
311 |
-
/** @type {number} */
|
312 |
-
|
313 |
-
this.width = w;
|
314 |
-
/** @type {number} */
|
315 |
-
|
316 |
-
this.height = h;
|
317 |
-
}
|
318 |
-
/**
|
319 |
-
* Returns whether two rectangles intersect.
|
320 |
-
* @param {Rect} a A Rectangle.
|
321 |
-
* @param {Rect} b A Rectangle.
|
322 |
-
* @return {boolean} Whether a and b intersect.
|
323 |
-
*/
|
324 |
-
|
325 |
-
|
326 |
-
_createClass(Rect, null, [{
|
327 |
-
key: "intersects",
|
328 |
-
value: function intersects(a, b) {
|
329 |
-
return a.left < b.left + b.width && b.left < a.left + a.width && a.top < b.top + b.height && b.top < a.top + a.height;
|
330 |
-
}
|
331 |
-
}]);
|
332 |
-
|
333 |
-
return Rect;
|
334 |
-
}();
|
335 |
-
|
336 |
-
var Classes = {
|
337 |
-
BASE: 'shuffle',
|
338 |
-
SHUFFLE_ITEM: 'shuffle-item',
|
339 |
-
VISIBLE: 'shuffle-item--visible',
|
340 |
-
HIDDEN: 'shuffle-item--hidden'
|
341 |
-
};
|
342 |
-
|
343 |
-
var id = 0;
|
344 |
-
|
345 |
-
var ShuffleItem =
|
346 |
-
/*#__PURE__*/
|
347 |
-
function () {
|
348 |
-
function ShuffleItem(element) {
|
349 |
-
_classCallCheck(this, ShuffleItem);
|
350 |
-
|
351 |
-
id += 1;
|
352 |
-
this.id = id;
|
353 |
-
this.element = element;
|
354 |
-
/**
|
355 |
-
* Used to separate items for layout and shrink.
|
356 |
-
*/
|
357 |
-
|
358 |
-
this.isVisible = true;
|
359 |
-
/**
|
360 |
-
* Used to determine if a transition will happen. By the time the _layout
|
361 |
-
* and _shrink methods get the ShuffleItem instances, the `isVisible` value
|
362 |
-
* has already been changed by the separation methods, so this property is
|
363 |
-
* needed to know if the item was visible/hidden before the shrink/layout.
|
364 |
-
*/
|
365 |
-
|
366 |
-
this.isHidden = false;
|
367 |
-
}
|
368 |
-
|
369 |
-
_createClass(ShuffleItem, [{
|
370 |
-
key: "show",
|
371 |
-
value: function show() {
|
372 |
-
this.isVisible = true;
|
373 |
-
this.element.classList.remove(Classes.HIDDEN);
|
374 |
-
this.element.classList.add(Classes.VISIBLE);
|
375 |
-
this.element.removeAttribute('aria-hidden');
|
376 |
-
}
|
377 |
-
}, {
|
378 |
-
key: "hide",
|
379 |
-
value: function hide() {
|
380 |
-
this.isVisible = false;
|
381 |
-
this.element.classList.remove(Classes.VISIBLE);
|
382 |
-
this.element.classList.add(Classes.HIDDEN);
|
383 |
-
this.element.setAttribute('aria-hidden', true);
|
384 |
-
}
|
385 |
-
}, {
|
386 |
-
key: "init",
|
387 |
-
value: function init() {
|
388 |
-
this.addClasses([Classes.SHUFFLE_ITEM, Classes.VISIBLE]);
|
389 |
-
this.applyCss(ShuffleItem.Css.INITIAL);
|
390 |
-
this.scale = ShuffleItem.Scale.VISIBLE;
|
391 |
-
this.point = new Point();
|
392 |
-
}
|
393 |
-
}, {
|
394 |
-
key: "addClasses",
|
395 |
-
value: function addClasses(classes) {
|
396 |
-
var _this = this;
|
397 |
-
|
398 |
-
classes.forEach(function (className) {
|
399 |
-
_this.element.classList.add(className);
|
400 |
-
});
|
401 |
-
}
|
402 |
-
}, {
|
403 |
-
key: "removeClasses",
|
404 |
-
value: function removeClasses(classes) {
|
405 |
-
var _this2 = this;
|
406 |
-
|
407 |
-
classes.forEach(function (className) {
|
408 |
-
_this2.element.classList.remove(className);
|
409 |
-
});
|
410 |
-
}
|
411 |
-
}, {
|
412 |
-
key: "applyCss",
|
413 |
-
value: function applyCss(obj) {
|
414 |
-
var _this3 = this;
|
415 |
-
|
416 |
-
Object.keys(obj).forEach(function (key) {
|
417 |
-
_this3.element.style[key] = obj[key];
|
418 |
-
});
|
419 |
-
}
|
420 |
-
}, {
|
421 |
-
key: "dispose",
|
422 |
-
value: function dispose() {
|
423 |
-
this.removeClasses([Classes.HIDDEN, Classes.VISIBLE, Classes.SHUFFLE_ITEM]);
|
424 |
-
this.element.removeAttribute('style');
|
425 |
-
this.element = null;
|
426 |
-
}
|
427 |
-
}]);
|
428 |
-
|
429 |
-
return ShuffleItem;
|
430 |
-
}();
|
431 |
-
|
432 |
-
ShuffleItem.Css = {
|
433 |
-
INITIAL: {
|
434 |
-
position: 'absolute',
|
435 |
-
top: 0,
|
436 |
-
left: 0,
|
437 |
-
visibility: 'visible',
|
438 |
-
willChange: 'transform'
|
439 |
-
},
|
440 |
-
VISIBLE: {
|
441 |
-
before: {
|
442 |
-
opacity: 1,
|
443 |
-
visibility: 'visible'
|
444 |
-
},
|
445 |
-
after: {
|
446 |
-
transitionDelay: ''
|
447 |
-
}
|
448 |
-
},
|
449 |
-
HIDDEN: {
|
450 |
-
before: {
|
451 |
-
opacity: 0
|
452 |
-
},
|
453 |
-
after: {
|
454 |
-
visibility: 'hidden',
|
455 |
-
transitionDelay: ''
|
456 |
-
}
|
457 |
-
}
|
458 |
-
};
|
459 |
-
ShuffleItem.Scale = {
|
460 |
-
VISIBLE: 1,
|
461 |
-
HIDDEN: 0.001
|
462 |
-
};
|
463 |
-
|
464 |
-
var value = null;
|
465 |
-
var testComputedSize = (function () {
|
466 |
-
if (value !== null) {
|
467 |
-
return value;
|
468 |
-
}
|
469 |
-
|
470 |
-
var element = document.body || document.documentElement;
|
471 |
-
var e = document.createElement('div');
|
472 |
-
e.style.cssText = 'width:10px;padding:2px;box-sizing:border-box;';
|
473 |
-
element.appendChild(e);
|
474 |
-
value = window.getComputedStyle(e, null).width === '10px';
|
475 |
-
element.removeChild(e);
|
476 |
-
return value;
|
477 |
-
});
|
478 |
-
|
479 |
-
/**
|
480 |
-
* Retrieve the computed style for an element, parsed as a float.
|
481 |
-
* @param {Element} element Element to get style for.
|
482 |
-
* @param {string} style Style property.
|
483 |
-
* @param {CSSStyleDeclaration} [styles] Optionally include clean styles to
|
484 |
-
* use instead of asking for them again.
|
485 |
-
* @return {number} The parsed computed value or zero if that fails because IE
|
486 |
-
* will return 'auto' when the element doesn't have margins instead of
|
487 |
-
* the computed style.
|
488 |
-
*/
|
489 |
-
|
490 |
-
function getNumberStyle(element, style) {
|
491 |
-
var styles = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : window.getComputedStyle(element, null);
|
492 |
-
var value = getNumber(styles[style]); // Support IE<=11 and W3C spec.
|
493 |
-
|
494 |
-
if (!testComputedSize() && style === 'width') {
|
495 |
-
value += getNumber(styles.paddingLeft) + getNumber(styles.paddingRight) + getNumber(styles.borderLeftWidth) + getNumber(styles.borderRightWidth);
|
496 |
-
} else if (!testComputedSize() && style === 'height') {
|
497 |
-
value += getNumber(styles.paddingTop) + getNumber(styles.paddingBottom) + getNumber(styles.borderTopWidth) + getNumber(styles.borderBottomWidth);
|
498 |
-
}
|
499 |
-
|
500 |
-
return value;
|
501 |
-
}
|
502 |
-
|
503 |
-
/**
|
504 |
-
* Fisher-Yates shuffle.
|
505 |
-
* http://stackoverflow.com/a/962890/373422
|
506 |
-
* https://bost.ocks.org/mike/shuffle/
|
507 |
-
* @param {Array} array Array to shuffle.
|
508 |
-
* @return {Array} Randomly sorted array.
|
509 |
-
*/
|
510 |
-
function randomize(array) {
|
511 |
-
var n = array.length;
|
512 |
-
|
513 |
-
while (n) {
|
514 |
-
n -= 1;
|
515 |
-
var i = Math.floor(Math.random() * (n + 1));
|
516 |
-
var temp = array[i];
|
517 |
-
array[i] = array[n];
|
518 |
-
array[n] = temp;
|
519 |
-
}
|
520 |
-
|
521 |
-
return array;
|
522 |
-
}
|
523 |
-
|
524 |
-
var defaults = {
|
525 |
-
// Use array.reverse() to reverse the results
|
526 |
-
reverse: false,
|
527 |
-
// Sorting function
|
528 |
-
by: null,
|
529 |
-
// Custom sort function
|
530 |
-
compare: null,
|
531 |
-
// If true, this will skip the sorting and return a randomized order in the array
|
532 |
-
randomize: false,
|
533 |
-
// Determines which property of each item in the array is passed to the
|
534 |
-
// sorting method.
|
535 |
-
key: 'element'
|
536 |
-
};
|
537 |
-
/**
|
538 |
-
* You can return `undefined` from the `by` function to revert to DOM order.
|
539 |
-
* @param {Array<T>} arr Array to sort.
|
540 |
-
* @param {SortOptions} options Sorting options.
|
541 |
-
* @return {Array<T>}
|
542 |
-
*/
|
543 |
-
|
544 |
-
function sorter(arr, options) {
|
545 |
-
var opts = Object.assign({}, defaults, options);
|
546 |
-
var original = Array.from(arr);
|
547 |
-
var revert = false;
|
548 |
-
|
549 |
-
if (!arr.length) {
|
550 |
-
return [];
|
551 |
-
}
|
552 |
-
|
553 |
-
if (opts.randomize) {
|
554 |
-
return randomize(arr);
|
555 |
-
} // Sort the elements by the opts.by function.
|
556 |
-
// If we don't have opts.by, default to DOM order
|
557 |
-
|
558 |
-
|
559 |
-
if (typeof opts.by === 'function') {
|
560 |
-
arr.sort(function (a, b) {
|
561 |
-
// Exit early if we already know we want to revert
|
562 |
-
if (revert) {
|
563 |
-
return 0;
|
564 |
-
}
|
565 |
-
|
566 |
-
var valA = opts.by(a[opts.key]);
|
567 |
-
var valB = opts.by(b[opts.key]); // If both values are undefined, use the DOM order
|
568 |
-
|
569 |
-
if (valA === undefined && valB === undefined) {
|
570 |
-
revert = true;
|
571 |
-
return 0;
|
572 |
-
}
|
573 |
-
|
574 |
-
if (valA < valB || valA === 'sortFirst' || valB === 'sortLast') {
|
575 |
-
return -1;
|
576 |
-
}
|
577 |
-
|
578 |
-
if (valA > valB || valA === 'sortLast' || valB === 'sortFirst') {
|
579 |
-
return 1;
|
580 |
-
}
|
581 |
-
|
582 |
-
return 0;
|
583 |
-
});
|
584 |
-
} else if (typeof opts.compare === 'function') {
|
585 |
-
arr.sort(opts.compare);
|
586 |
-
} // Revert to the original array if necessary
|
587 |
-
|
588 |
-
|
589 |
-
if (revert) {
|
590 |
-
return original;
|
591 |
-
}
|
592 |
-
|
593 |
-
if (opts.reverse) {
|
594 |
-
arr.reverse();
|
595 |
-
}
|
596 |
-
|
597 |
-
return arr;
|
598 |
-
}
|
599 |
-
|
600 |
-
var transitions = {};
|
601 |
-
var eventName = 'transitionend';
|
602 |
-
var count = 0;
|
603 |
-
|
604 |
-
function uniqueId() {
|
605 |
-
count += 1;
|
606 |
-
return eventName + count;
|
607 |
-
}
|
608 |
-
|
609 |
-
function cancelTransitionEnd(id) {
|
610 |
-
if (transitions[id]) {
|
611 |
-
transitions[id].element.removeEventListener(eventName, transitions[id].listener);
|
612 |
-
transitions[id] = null;
|
613 |
-
return true;
|
614 |
-
}
|
615 |
-
|
616 |
-
return false;
|
617 |
-
}
|
618 |
-
function onTransitionEnd(element, callback) {
|
619 |
-
var id = uniqueId();
|
620 |
-
|
621 |
-
var listener = function listener(evt) {
|
622 |
-
if (evt.currentTarget === evt.target) {
|
623 |
-
cancelTransitionEnd(id);
|
624 |
-
callback(evt);
|
625 |
-
}
|
626 |
-
};
|
627 |
-
|
628 |
-
element.addEventListener(eventName, listener);
|
629 |
-
transitions[id] = {
|
630 |
-
element: element,
|
631 |
-
listener: listener
|
632 |
-
};
|
633 |
-
return id;
|
634 |
-
}
|
635 |
-
|
636 |
-
function arrayMax(array) {
|
637 |
-
return Math.max.apply(Math, array); // eslint-disable-line prefer-spread
|
638 |
-
}
|
639 |
-
|
640 |
-
function arrayMin(array) {
|
641 |
-
return Math.min.apply(Math, array); // eslint-disable-line prefer-spread
|
642 |
-
}
|
643 |
-
|
644 |
-
/**
|
645 |
-
* Determine the number of columns an items spans.
|
646 |
-
* @param {number} itemWidth Width of the item.
|
647 |
-
* @param {number} columnWidth Width of the column (includes gutter).
|
648 |
-
* @param {number} columns Total number of columns
|
649 |
-
* @param {number} threshold A buffer value for the size of the column to fit.
|
650 |
-
* @return {number}
|
651 |
-
*/
|
652 |
-
|
653 |
-
function getColumnSpan(itemWidth, columnWidth, columns, threshold) {
|
654 |
-
var columnSpan = itemWidth / columnWidth; // If the difference between the rounded column span number and the
|
655 |
-
// calculated column span number is really small, round the number to
|
656 |
-
// make it fit.
|
657 |
-
|
658 |
-
if (Math.abs(Math.round(columnSpan) - columnSpan) < threshold) {
|
659 |
-
// e.g. columnSpan = 4.0089945390298745
|
660 |
-
columnSpan = Math.round(columnSpan);
|
661 |
-
} // Ensure the column span is not more than the amount of columns in the whole layout.
|
662 |
-
|
663 |
-
|
664 |
-
return Math.min(Math.ceil(columnSpan), columns);
|
665 |
-
}
|
666 |
-
/**
|
667 |
-
* Retrieves the column set to use for placement.
|
668 |
-
* @param {number} columnSpan The number of columns this current item spans.
|
669 |
-
* @param {number} columns The total columns in the grid.
|
670 |
-
* @return {Array.<number>} An array of numbers represeting the column set.
|
671 |
-
*/
|
672 |
-
|
673 |
-
function getAvailablePositions(positions, columnSpan, columns) {
|
674 |
-
// The item spans only one column.
|
675 |
-
if (columnSpan === 1) {
|
676 |
-
return positions;
|
677 |
-
} // The item spans more than one column, figure out how many different
|
678 |
-
// places it could fit horizontally.
|
679 |
-
// The group count is the number of places within the positions this block
|
680 |
-
// could fit, ignoring the current positions of items.
|
681 |
-
// Imagine a 2 column brick as the second item in a 4 column grid with
|
682 |
-
// 10px height each. Find the places it would fit:
|
683 |
-
// [20, 10, 10, 0]
|
684 |
-
// | | |
|
685 |
-
// * * *
|
686 |
-
//
|
687 |
-
// Then take the places which fit and get the bigger of the two:
|
688 |
-
// max([20, 10]), max([10, 10]), max([10, 0]) = [20, 10, 10]
|
689 |
-
//
|
690 |
-
// Next, find the first smallest number (the short column).
|
691 |
-
// [20, 10, 10]
|
692 |
-
// |
|
693 |
-
// *
|
694 |
-
//
|
695 |
-
// And that's where it should be placed!
|
696 |
-
//
|
697 |
-
// Another example where the second column's item extends past the first:
|
698 |
-
// [10, 20, 10, 0] => [20, 20, 10] => 10
|
699 |
-
|
700 |
-
|
701 |
-
var available = []; // For how many possible positions for this item there are.
|
702 |
-
|
703 |
-
for (var i = 0; i <= columns - columnSpan; i++) {
|
704 |
-
// Find the bigger value for each place it could fit.
|
705 |
-
available.push(arrayMax(positions.slice(i, i + columnSpan)));
|
706 |
-
}
|
707 |
-
|
708 |
-
return available;
|
709 |
-
}
|
710 |
-
/**
|
711 |
-
* Find index of short column, the first from the left where this item will go.
|
712 |
-
*
|
713 |
-
* @param {Array.<number>} positions The array to search for the smallest number.
|
714 |
-
* @param {number} buffer Optional buffer which is very useful when the height
|
715 |
-
* is a percentage of the width.
|
716 |
-
* @return {number} Index of the short column.
|
717 |
-
*/
|
718 |
-
|
719 |
-
function getShortColumn(positions, buffer) {
|
720 |
-
var minPosition = arrayMin(positions);
|
721 |
-
|
722 |
-
for (var i = 0, len = positions.length; i < len; i++) {
|
723 |
-
if (positions[i] >= minPosition - buffer && positions[i] <= minPosition + buffer) {
|
724 |
-
return i;
|
725 |
-
}
|
726 |
-
}
|
727 |
-
|
728 |
-
return 0;
|
729 |
-
}
|
730 |
-
/**
|
731 |
-
* Determine the location of the next item, based on its size.
|
732 |
-
* @param {Object} itemSize Object with width and height.
|
733 |
-
* @param {Array.<number>} positions Positions of the other current items.
|
734 |
-
* @param {number} gridSize The column width or row height.
|
735 |
-
* @param {number} total The total number of columns or rows.
|
736 |
-
* @param {number} threshold Buffer value for the column to fit.
|
737 |
-
* @param {number} buffer Vertical buffer for the height of items.
|
738 |
-
* @return {Point}
|
739 |
-
*/
|
740 |
-
|
741 |
-
function getItemPosition(_ref) {
|
742 |
-
var itemSize = _ref.itemSize,
|
743 |
-
positions = _ref.positions,
|
744 |
-
gridSize = _ref.gridSize,
|
745 |
-
total = _ref.total,
|
746 |
-
threshold = _ref.threshold,
|
747 |
-
buffer = _ref.buffer;
|
748 |
-
var span = getColumnSpan(itemSize.width, gridSize, total, threshold);
|
749 |
-
var setY = getAvailablePositions(positions, span, total);
|
750 |
-
var shortColumnIndex = getShortColumn(setY, buffer); // Position the item
|
751 |
-
|
752 |
-
var point = new Point(gridSize * shortColumnIndex, setY[shortColumnIndex]); // Update the columns array with the new values for each column.
|
753 |
-
// e.g. before the update the columns could be [250, 0, 0, 0] for an item
|
754 |
-
// which spans 2 columns. After it would be [250, itemHeight, itemHeight, 0].
|
755 |
-
|
756 |
-
var setHeight = setY[shortColumnIndex] + itemSize.height;
|
757 |
-
|
758 |
-
for (var i = 0; i < span; i++) {
|
759 |
-
positions[shortColumnIndex + i] = setHeight;
|
760 |
-
}
|
761 |
-
|
762 |
-
return point;
|
763 |
-
}
|
764 |
-
/**
|
765 |
-
* This method attempts to center items. This method could potentially be slow
|
766 |
-
* with a large number of items because it must place items, then check every
|
767 |
-
* previous item to ensure there is no overlap.
|
768 |
-
* @param {Array.<Rect>} itemRects Item data objects.
|
769 |
-
* @param {number} containerWidth Width of the containing element.
|
770 |
-
* @return {Array.<Point>}
|
771 |
-
*/
|
772 |
-
|
773 |
-
function getCenteredPositions(itemRects, containerWidth) {
|
774 |
-
var rowMap = {}; // Populate rows by their offset because items could jump between rows like:
|
775 |
-
// a c
|
776 |
-
// bbb
|
777 |
-
|
778 |
-
itemRects.forEach(function (itemRect) {
|
779 |
-
if (rowMap[itemRect.top]) {
|
780 |
-
// Push the point to the last row array.
|
781 |
-
rowMap[itemRect.top].push(itemRect);
|
782 |
-
} else {
|
783 |
-
// Start of a new row.
|
784 |
-
rowMap[itemRect.top] = [itemRect];
|
785 |
-
}
|
786 |
-
}); // For each row, find the end of the last item, then calculate
|
787 |
-
// the remaining space by dividing it by 2. Then add that
|
788 |
-
// offset to the x position of each point.
|
789 |
-
|
790 |
-
var rects = [];
|
791 |
-
var rows = [];
|
792 |
-
var centeredRows = [];
|
793 |
-
Object.keys(rowMap).forEach(function (key) {
|
794 |
-
var itemRects = rowMap[key];
|
795 |
-
rows.push(itemRects);
|
796 |
-
var lastItem = itemRects[itemRects.length - 1];
|
797 |
-
var end = lastItem.left + lastItem.width;
|
798 |
-
var offset = Math.round((containerWidth - end) / 2);
|
799 |
-
var finalRects = itemRects;
|
800 |
-
var canMove = false;
|
801 |
-
|
802 |
-
if (offset > 0) {
|
803 |
-
var newRects = [];
|
804 |
-
canMove = itemRects.every(function (r) {
|
805 |
-
var newRect = new Rect(r.left + offset, r.top, r.width, r.height, r.id); // Check all current rects to make sure none overlap.
|
806 |
-
|
807 |
-
var noOverlap = !rects.some(function (r) {
|
808 |
-
return Rect.intersects(newRect, r);
|
809 |
-
});
|
810 |
-
newRects.push(newRect);
|
811 |
-
return noOverlap;
|
812 |
-
}); // If none of the rectangles overlapped, the whole group can be centered.
|
813 |
-
|
814 |
-
if (canMove) {
|
815 |
-
finalRects = newRects;
|
816 |
-
}
|
817 |
-
} // If the items are not going to be offset, ensure that the original
|
818 |
-
// placement for this row will not overlap previous rows (row-spanning
|
819 |
-
// elements could be in the way).
|
820 |
-
|
821 |
-
|
822 |
-
if (!canMove) {
|
823 |
-
var intersectingRect;
|
824 |
-
var hasOverlap = itemRects.some(function (itemRect) {
|
825 |
-
return rects.some(function (r) {
|
826 |
-
var intersects = Rect.intersects(itemRect, r);
|
827 |
-
|
828 |
-
if (intersects) {
|
829 |
-
intersectingRect = r;
|
830 |
-
}
|
831 |
-
|
832 |
-
return intersects;
|
833 |
-
});
|
834 |
-
}); // If there is any overlap, replace the overlapping row with the original.
|
835 |
-
|
836 |
-
if (hasOverlap) {
|
837 |
-
var rowIndex = centeredRows.findIndex(function (items) {
|
838 |
-
return items.includes(intersectingRect);
|
839 |
-
});
|
840 |
-
centeredRows.splice(rowIndex, 1, rows[rowIndex]);
|
841 |
-
}
|
842 |
-
}
|
843 |
-
|
844 |
-
rects = rects.concat(finalRects);
|
845 |
-
centeredRows.push(finalRects);
|
846 |
-
}); // Reduce array of arrays to a single array of points.
|
847 |
-
// https://stackoverflow.com/a/10865042/373422
|
848 |
-
// Then reset sort back to how the items were passed to this method.
|
849 |
-
// Remove the wrapper object with index, map to a Point.
|
850 |
-
|
851 |
-
return [].concat.apply([], centeredRows) // eslint-disable-line prefer-spread
|
852 |
-
.sort(function (a, b) {
|
853 |
-
return a.id - b.id;
|
854 |
-
}).map(function (itemRect) {
|
855 |
-
return new Point(itemRect.left, itemRect.top);
|
856 |
-
});
|
857 |
-
}
|
858 |
-
|
859 |
-
/**
|
860 |
-
* Hyphenates a javascript style string to a css one. For example:
|
861 |
-
* MozBoxSizing -> -moz-box-sizing.
|
862 |
-
* @param {string} str The string to hyphenate.
|
863 |
-
* @return {string} The hyphenated string.
|
864 |
-
*/
|
865 |
-
function hyphenate(str) {
|
866 |
-
return str.replace(/([A-Z])/g, function (str, m1) {
|
867 |
-
return "-".concat(m1.toLowerCase());
|
868 |
-
});
|
869 |
-
}
|
870 |
-
|
871 |
-
function arrayUnique(x) {
|
872 |
-
return Array.from(new Set(x));
|
873 |
-
} // Used for unique instance variables
|
874 |
-
|
875 |
-
|
876 |
-
var id$1 = 0;
|
877 |
-
|
878 |
-
var Shuffle =
|
879 |
-
/*#__PURE__*/
|
880 |
-
function (_TinyEmitter) {
|
881 |
-
_inherits(Shuffle, _TinyEmitter);
|
882 |
-
|
883 |
-
/**
|
884 |
-
* Categorize, sort, and filter a responsive grid of items.
|
885 |
-
*
|
886 |
-
* @param {Element} element An element which is the parent container for the grid items.
|
887 |
-
* @param {Object} [options=Shuffle.options] Options object.
|
888 |
-
* @constructor
|
889 |
-
*/
|
890 |
-
function Shuffle(element) {
|
891 |
-
var _this;
|
892 |
-
|
893 |
-
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
894 |
-
|
895 |
-
_classCallCheck(this, Shuffle);
|
896 |
-
|
897 |
-
_this = _possibleConstructorReturn(this, _getPrototypeOf(Shuffle).call(this));
|
898 |
-
_this.options = Object.assign({}, Shuffle.options, options); // Allow misspelling of delimiter since that's how it used to be.
|
899 |
-
// Remove in v6.
|
900 |
-
|
901 |
-
if (_this.options.delimeter) {
|
902 |
-
_this.options.delimiter = _this.options.delimeter;
|
903 |
-
}
|
904 |
-
|
905 |
-
_this.lastSort = {};
|
906 |
-
_this.group = Shuffle.ALL_ITEMS;
|
907 |
-
_this.lastFilter = Shuffle.ALL_ITEMS;
|
908 |
-
_this.isEnabled = true;
|
909 |
-
_this.isDestroyed = false;
|
910 |
-
_this.isInitialized = false;
|
911 |
-
_this._transitions = [];
|
912 |
-
_this.isTransitioning = false;
|
913 |
-
_this._queue = [];
|
914 |
-
|
915 |
-
var el = _this._getElementOption(element);
|
916 |
-
|
917 |
-
if (!el) {
|
918 |
-
throw new TypeError('Shuffle needs to be initialized with an element.');
|
919 |
-
}
|
920 |
-
|
921 |
-
_this.element = el;
|
922 |
-
_this.id = 'shuffle_' + id$1;
|
923 |
-
id$1 += 1;
|
924 |
-
|
925 |
-
_this._init();
|
926 |
-
|
927 |
-
_this.isInitialized = true;
|
928 |
-
return _this;
|
929 |
-
}
|
930 |
-
|
931 |
-
_createClass(Shuffle, [{
|
932 |
-
key: "_init",
|
933 |
-
value: function _init() {
|
934 |
-
this.items = this._getItems();
|
935 |
-
this.options.sizer = this._getElementOption(this.options.sizer); // Add class and invalidate styles
|
936 |
-
|
937 |
-
this.element.classList.add(Shuffle.Classes.BASE); // Set initial css for each item
|
938 |
-
|
939 |
-
this._initItems(this.items); // Bind resize events
|
940 |
-
|
941 |
-
|
942 |
-
this._onResize = this._getResizeFunction();
|
943 |
-
window.addEventListener('resize', this._onResize); // If the page has not already emitted the `load` event, call layout on load.
|
944 |
-
// This avoids layout issues caused by images and fonts loading after the
|
945 |
-
// instance has been initialized.
|
946 |
-
|
947 |
-
if (document.readyState !== 'complete') {
|
948 |
-
var layout = this.layout.bind(this);
|
949 |
-
window.addEventListener('load', function onLoad() {
|
950 |
-
window.removeEventListener('load', onLoad);
|
951 |
-
layout();
|
952 |
-
});
|
953 |
-
} // Get container css all in one request. Causes reflow
|
954 |
-
|
955 |
-
|
956 |
-
var containerCss = window.getComputedStyle(this.element, null);
|
957 |
-
var containerWidth = Shuffle.getSize(this.element).width; // Add styles to the container if it doesn't have them.
|
958 |
-
|
959 |
-
this._validateStyles(containerCss); // We already got the container's width above, no need to cause another
|
960 |
-
// reflow getting it again... Calculate the number of columns there will be
|
961 |
-
|
962 |
-
|
963 |
-
this._setColumns(containerWidth); // Kick off!
|
964 |
-
|
965 |
-
|
966 |
-
this.filter(this.options.group, this.options.initialSort); // The shuffle items haven't had transitions set on them yet so the user
|
967 |
-
// doesn't see the first layout. Set them now that the first layout is done.
|
968 |
-
// First, however, a synchronous layout must be caused for the previous
|
969 |
-
// styles to be applied without transitions.
|
970 |
-
|
971 |
-
this.element.offsetWidth; // eslint-disable-line no-unused-expressions
|
972 |
-
|
973 |
-
this.setItemTransitions(this.items);
|
974 |
-
this.element.style.transition = "height ".concat(this.options.speed, "ms ").concat(this.options.easing);
|
975 |
-
}
|
976 |
-
/**
|
977 |
-
* Returns a throttled and proxied function for the resize handler.
|
978 |
-
* @return {function}
|
979 |
-
* @private
|
980 |
-
*/
|
981 |
-
|
982 |
-
}, {
|
983 |
-
key: "_getResizeFunction",
|
984 |
-
value: function _getResizeFunction() {
|
985 |
-
var resizeFunction = this._handleResize.bind(this);
|
986 |
-
|
987 |
-
return this.options.throttle ? this.options.throttle(resizeFunction, this.options.throttleTime) : resizeFunction;
|
988 |
-
}
|
989 |
-
/**
|
990 |
-
* Retrieve an element from an option.
|
991 |
-
* @param {string|jQuery|Element} option The option to check.
|
992 |
-
* @return {?Element} The plain element or null.
|
993 |
-
* @private
|
994 |
-
*/
|
995 |
-
|
996 |
-
}, {
|
997 |
-
key: "_getElementOption",
|
998 |
-
value: function _getElementOption(option) {
|
999 |
-
// If column width is a string, treat is as a selector and search for the
|
1000 |
-
// sizer element within the outermost container
|
1001 |
-
if (typeof option === 'string') {
|
1002 |
-
return this.element.querySelector(option);
|
1003 |
-
} // Check for an element
|
1004 |
-
|
1005 |
-
|
1006 |
-
if (option && option.nodeType && option.nodeType === 1) {
|
1007 |
-
return option;
|
1008 |
-
} // Check for jQuery object
|
1009 |
-
|
1010 |
-
|
1011 |
-
if (option && option.jquery) {
|
1012 |
-
return option[0];
|
1013 |
-
}
|
1014 |
-
|
1015 |
-
return null;
|
1016 |
-
}
|
1017 |
-
/**
|
1018 |
-
* Ensures the shuffle container has the css styles it needs applied to it.
|
1019 |
-
* @param {Object} styles Key value pairs for position and overflow.
|
1020 |
-
* @private
|
1021 |
-
*/
|
1022 |
-
|
1023 |
-
}, {
|
1024 |
-
key: "_validateStyles",
|
1025 |
-
value: function _validateStyles(styles) {
|
1026 |
-
// Position cannot be static.
|
1027 |
-
if (styles.position === 'static') {
|
1028 |
-
this.element.style.position = 'relative';
|
1029 |
-
} // Overflow has to be hidden.
|
1030 |
-
|
1031 |
-
|
1032 |
-
if (styles.overflow !== 'hidden') {
|
1033 |
-
this.element.style.overflow = 'hidden';
|
1034 |
-
}
|
1035 |
-
}
|
1036 |
-
/**
|
1037 |
-
* Filter the elements by a category.
|
1038 |
-
* @param {string|string[]|function(Element):boolean} [category] Category to
|
1039 |
-
* filter by. If it's given, the last category will be used to filter the items.
|
1040 |
-
* @param {Array} [collection] Optionally filter a collection. Defaults to
|
1041 |
-
* all the items.
|
1042 |
-
* @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}}
|
1043 |
-
* @private
|
1044 |
-
*/
|
1045 |
-
|
1046 |
-
}, {
|
1047 |
-
key: "_filter",
|
1048 |
-
value: function _filter() {
|
1049 |
-
var category = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.lastFilter;
|
1050 |
-
var collection = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.items;
|
1051 |
-
|
1052 |
-
var set = this._getFilteredSets(category, collection); // Individually add/remove hidden/visible classes
|
1053 |
-
|
1054 |
-
|
1055 |
-
this._toggleFilterClasses(set); // Save the last filter in case elements are appended.
|
1056 |
-
|
1057 |
-
|
1058 |
-
this.lastFilter = category; // This is saved mainly because providing a filter function (like searching)
|
1059 |
-
// will overwrite the `lastFilter` property every time its called.
|
1060 |
-
|
1061 |
-
if (typeof category === 'string') {
|
1062 |
-
this.group = category;
|
1063 |
-
}
|
1064 |
-
|
1065 |
-
return set;
|
1066 |
-
}
|
1067 |
-
/**
|
1068 |
-
* Returns an object containing the visible and hidden elements.
|
1069 |
-
* @param {string|string[]|function(Element):boolean} category Category or function to filter by.
|
1070 |
-
* @param {ShuffleItem[]} items A collection of items to filter.
|
1071 |
-
* @return {{visible: ShuffleItem[], hidden: ShuffleItem[]}}
|
1072 |
-
* @private
|
1073 |
-
*/
|
1074 |
-
|
1075 |
-
}, {
|
1076 |
-
key: "_getFilteredSets",
|
1077 |
-
value: function _getFilteredSets(category, items) {
|
1078 |
-
var _this2 = this;
|
1079 |
-
|
1080 |
-
var visible = [];
|
1081 |
-
var hidden = []; // category === 'all', add visible class to everything
|
1082 |
-
|
1083 |
-
if (category === Shuffle.ALL_ITEMS) {
|
1084 |
-
visible = items; // Loop through each item and use provided function to determine
|
1085 |
-
// whether to hide it or not.
|
1086 |
-
} else {
|
1087 |
-
items.forEach(function (item) {
|
1088 |
-
if (_this2._doesPassFilter(category, item.element)) {
|
1089 |
-
visible.push(item);
|
1090 |
-
} else {
|
1091 |
-
hidden.push(item);
|
1092 |
-
}
|
1093 |
-
});
|
1094 |
-
}
|
1095 |
-
|
1096 |
-
return {
|
1097 |
-
visible: visible,
|
1098 |
-
hidden: hidden
|
1099 |
-
};
|
1100 |
-
}
|
1101 |
-
/**
|
1102 |
-
* Test an item to see if it passes a category.
|
1103 |
-
* @param {string|string[]|function():boolean} category Category or function to filter by.
|
1104 |
-
* @param {Element} element An element to test.
|
1105 |
-
* @return {boolean} Whether it passes the category/filter.
|
1106 |
-
* @private
|
1107 |
-
*/
|
1108 |
-
|
1109 |
-
}, {
|
1110 |
-
key: "_doesPassFilter",
|
1111 |
-
value: function _doesPassFilter(category, element) {
|
1112 |
-
if (typeof category === 'function') {
|
1113 |
-
return category.call(element, element, this);
|
1114 |
-
} // Check each element's data-groups attribute against the given category.
|
1115 |
-
|
1116 |
-
|
1117 |
-
var attr = element.getAttribute('data-' + Shuffle.FILTER_ATTRIBUTE_KEY);
|
1118 |
-
var keys = this.options.delimiter ? attr.split(this.options.delimiter) : JSON.parse(attr);
|
1119 |
-
|
1120 |
-
function testCategory(category) {
|
1121 |
-
return keys.includes(category);
|
1122 |
-
}
|
1123 |
-
|
1124 |
-
if (Array.isArray(category)) {
|
1125 |
-
if (this.options.filterMode === Shuffle.FilterMode.ANY) {
|
1126 |
-
return category.some(testCategory);
|
1127 |
-
}
|
1128 |
-
|
1129 |
-
return category.every(testCategory);
|
1130 |
-
}
|
1131 |
-
|
1132 |
-
return keys.includes(category);
|
1133 |
-
}
|
1134 |
-
/**
|
1135 |
-
* Toggles the visible and hidden class names.
|
1136 |
-
* @param {{visible, hidden}} Object with visible and hidden arrays.
|
1137 |
-
* @private
|
1138 |
-
*/
|
1139 |
-
|
1140 |
-
}, {
|
1141 |
-
key: "_toggleFilterClasses",
|
1142 |
-
value: function _toggleFilterClasses(_ref) {
|
1143 |
-
var visible = _ref.visible,
|
1144 |
-
hidden = _ref.hidden;
|
1145 |
-
visible.forEach(function (item) {
|
1146 |
-
item.show();
|
1147 |
-
});
|
1148 |
-
hidden.forEach(function (item) {
|
1149 |
-
item.hide();
|
1150 |
-
});
|
1151 |
-
}
|
1152 |
-
/**
|
1153 |
-
* Set the initial css for each item
|
1154 |
-
* @param {ShuffleItem[]} items Set to initialize.
|
1155 |
-
* @private
|
1156 |
-
*/
|
1157 |
-
|
1158 |
-
}, {
|
1159 |
-
key: "_initItems",
|
1160 |
-
value: function _initItems(items) {
|
1161 |
-
items.forEach(function (item) {
|
1162 |
-
item.init();
|
1163 |
-
});
|
1164 |
-
}
|
1165 |
-
/**
|
1166 |
-
* Remove element reference and styles.
|
1167 |
-
* @param {ShuffleItem[]} items Set to dispose.
|
1168 |
-
* @private
|
1169 |
-
*/
|
1170 |
-
|
1171 |
-
}, {
|
1172 |
-
key: "_disposeItems",
|
1173 |
-
value: function _disposeItems(items) {
|
1174 |
-
items.forEach(function (item) {
|
1175 |
-
item.dispose();
|
1176 |
-
});
|
1177 |
-
}
|
1178 |
-
/**
|
1179 |
-
* Updates the visible item count.
|
1180 |
-
* @private
|
1181 |
-
*/
|
1182 |
-
|
1183 |
-
}, {
|
1184 |
-
key: "_updateItemCount",
|
1185 |
-
value: function _updateItemCount() {
|
1186 |
-
this.visibleItems = this._getFilteredItems().length;
|
1187 |
-
}
|
1188 |
-
/**
|
1189 |
-
* Sets css transform transition on a group of elements. This is not executed
|
1190 |
-
* at the same time as `item.init` so that transitions don't occur upon
|
1191 |
-
* initialization of a new Shuffle instance.
|
1192 |
-
* @param {ShuffleItem[]} items Shuffle items to set transitions on.
|
1193 |
-
* @protected
|
1194 |
-
*/
|
1195 |
-
|
1196 |
-
}, {
|
1197 |
-
key: "setItemTransitions",
|
1198 |
-
value: function setItemTransitions(items) {
|
1199 |
-
var _this$options = this.options,
|
1200 |
-
speed = _this$options.speed,
|
1201 |
-
easing = _this$options.easing;
|
1202 |
-
var positionProps = this.options.useTransforms ? ['transform'] : ['top', 'left']; // Allow users to transtion other properties if they exist in the `before`
|
1203 |
-
// css mapping of the shuffle item.
|
1204 |
-
|
1205 |
-
var cssProps = Object.keys(ShuffleItem.Css.HIDDEN.before).map(function (k) {
|
1206 |
-
return hyphenate(k);
|
1207 |
-
});
|
1208 |
-
var properties = positionProps.concat(cssProps).join();
|
1209 |
-
items.forEach(function (item) {
|
1210 |
-
item.element.style.transitionDuration = speed + 'ms';
|
1211 |
-
item.element.style.transitionTimingFunction = easing;
|
1212 |
-
item.element.style.transitionProperty = properties;
|
1213 |
-
});
|
1214 |
-
}
|
1215 |
-
}, {
|
1216 |
-
key: "_getItems",
|
1217 |
-
value: function _getItems() {
|
1218 |
-
var _this3 = this;
|
1219 |
-
|
1220 |
-
return Array.from(this.element.children).filter(function (el) {
|
1221 |
-
return matchesSelector(el, _this3.options.itemSelector);
|
1222 |
-
}).map(function (el) {
|
1223 |
-
return new ShuffleItem(el);
|
1224 |
-
});
|
1225 |
-
}
|
1226 |
-
/**
|
1227 |
-
* Combine the current items array with a new one and sort it by DOM order.
|
1228 |
-
* @param {ShuffleItem[]} items Items to track.
|
1229 |
-
* @return {ShuffleItem[]}
|
1230 |
-
*/
|
1231 |
-
|
1232 |
-
}, {
|
1233 |
-
key: "_mergeNewItems",
|
1234 |
-
value: function _mergeNewItems(items) {
|
1235 |
-
var children = Array.from(this.element.children);
|
1236 |
-
return sorter(this.items.concat(items), {
|
1237 |
-
by: function by(element) {
|
1238 |
-
return children.indexOf(element);
|
1239 |
-
}
|
1240 |
-
});
|
1241 |
-
}
|
1242 |
-
}, {
|
1243 |
-
key: "_getFilteredItems",
|
1244 |
-
value: function _getFilteredItems() {
|
1245 |
-
return this.items.filter(function (item) {
|
1246 |
-
return item.isVisible;
|
1247 |
-
});
|
1248 |
-
}
|
1249 |
-
}, {
|
1250 |
-
key: "_getConcealedItems",
|
1251 |
-
value: function _getConcealedItems() {
|
1252 |
-
return this.items.filter(function (item) {
|
1253 |
-
return !item.isVisible;
|
1254 |
-
});
|
1255 |
-
}
|
1256 |
-
/**
|
1257 |
-
* Returns the column size, based on column width and sizer options.
|
1258 |
-
* @param {number} containerWidth Size of the parent container.
|
1259 |
-
* @param {number} gutterSize Size of the gutters.
|
1260 |
-
* @return {number}
|
1261 |
-
* @private
|
1262 |
-
*/
|
1263 |
-
|
1264 |
-
}, {
|
1265 |
-
key: "_getColumnSize",
|
1266 |
-
value: function _getColumnSize(containerWidth, gutterSize) {
|
1267 |
-
var size; // If the columnWidth property is a function, then the grid is fluid
|
1268 |
-
|
1269 |
-
if (typeof this.options.columnWidth === 'function') {
|
1270 |
-
size = this.options.columnWidth(containerWidth); // columnWidth option isn't a function, are they using a sizing element?
|
1271 |
-
} else if (this.options.sizer) {
|
1272 |
-
size = Shuffle.getSize(this.options.sizer).width; // if not, how about the explicitly set option?
|
1273 |
-
} else if (this.options.columnWidth) {
|
1274 |
-
size = this.options.columnWidth; // or use the size of the first item
|
1275 |
-
} else if (this.items.length > 0) {
|
1276 |
-
size = Shuffle.getSize(this.items[0].element, true).width; // if there's no items, use size of container
|
1277 |
-
} else {
|
1278 |
-
size = containerWidth;
|
1279 |
-
} // Don't let them set a column width of zero.
|
1280 |
-
|
1281 |
-
|
1282 |
-
if (size === 0) {
|
1283 |
-
size = containerWidth;
|
1284 |
-
}
|
1285 |
-
|
1286 |
-
return size + gutterSize;
|
1287 |
-
}
|
1288 |
-
/**
|
1289 |
-
* Returns the gutter size, based on gutter width and sizer options.
|
1290 |
-
* @param {number} containerWidth Size of the parent container.
|
1291 |
-
* @return {number}
|
1292 |
-
* @private
|
1293 |
-
*/
|
1294 |
-
|
1295 |
-
}, {
|
1296 |
-
key: "_getGutterSize",
|
1297 |
-
value: function _getGutterSize(containerWidth) {
|
1298 |
-
var size;
|
1299 |
-
|
1300 |
-
if (typeof this.options.gutterWidth === 'function') {
|
1301 |
-
size = this.options.gutterWidth(containerWidth);
|
1302 |
-
} else if (this.options.sizer) {
|
1303 |
-
size = getNumberStyle(this.options.sizer, 'marginLeft');
|
1304 |
-
} else {
|
1305 |
-
size = this.options.gutterWidth;
|
1306 |
-
}
|
1307 |
-
|
1308 |
-
return size;
|
1309 |
-
}
|
1310 |
-
/**
|
1311 |
-
* Calculate the number of columns to be used. Gets css if using sizer element.
|
1312 |
-
* @param {number} [containerWidth] Optionally specify a container width if
|
1313 |
-
* it's already available.
|
1314 |
-
*/
|
1315 |
-
|
1316 |
-
}, {
|
1317 |
-
key: "_setColumns",
|
1318 |
-
value: function _setColumns() {
|
1319 |
-
var containerWidth = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Shuffle.getSize(this.element).width;
|
1320 |
-
|
1321 |
-
var gutter = this._getGutterSize(containerWidth);
|
1322 |
-
|
1323 |
-
var columnWidth = this._getColumnSize(containerWidth, gutter);
|
1324 |
-
|
1325 |
-
var calculatedColumns = (containerWidth + gutter) / columnWidth; // Widths given from getStyles are not precise enough...
|
1326 |
-
|
1327 |
-
if (Math.abs(Math.round(calculatedColumns) - calculatedColumns) < this.options.columnThreshold) {
|
1328 |
-
// e.g. calculatedColumns = 11.998876
|
1329 |
-
calculatedColumns = Math.round(calculatedColumns);
|
1330 |
-
}
|
1331 |
-
|
1332 |
-
this.cols = Math.max(Math.floor(calculatedColumns || 0), 1);
|
1333 |
-
this.containerWidth = containerWidth;
|
1334 |
-
this.colWidth = columnWidth;
|
1335 |
-
}
|
1336 |
-
/**
|
1337 |
-
* Adjust the height of the grid
|
1338 |
-
*/
|
1339 |
-
|
1340 |
-
}, {
|
1341 |
-
key: "_setContainerSize",
|
1342 |
-
value: function _setContainerSize() {
|
1343 |
-
this.element.style.height = this._getContainerSize() + 'px';
|
1344 |
-
}
|
1345 |
-
/**
|
1346 |
-
* Based on the column heights, it returns the biggest one.
|
1347 |
-
* @return {number}
|
1348 |
-
* @private
|
1349 |
-
*/
|
1350 |
-
|
1351 |
-
}, {
|
1352 |
-
key: "_getContainerSize",
|
1353 |
-
value: function _getContainerSize() {
|
1354 |
-
return arrayMax(this.positions);
|
1355 |
-
}
|
1356 |
-
/**
|
1357 |
-
* Get the clamped stagger amount.
|
1358 |
-
* @param {number} index Index of the item to be staggered.
|
1359 |
-
* @return {number}
|
1360 |
-
*/
|
1361 |
-
|
1362 |
-
}, {
|
1363 |
-
key: "_getStaggerAmount",
|
1364 |
-
value: function _getStaggerAmount(index) {
|
1365 |
-
return Math.min(index * this.options.staggerAmount, this.options.staggerAmountMax);
|
1366 |
-
}
|
1367 |
-
/**
|
1368 |
-
* Emit an event from this instance.
|
1369 |
-
* @param {string} name Event name.
|
1370 |
-
* @param {Object} [data={}] Optional object data.
|
1371 |
-
*/
|
1372 |
-
|
1373 |
-
}, {
|
1374 |
-
key: "_dispatch",
|
1375 |
-
value: function _dispatch(name) {
|
1376 |
-
var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
1377 |
-
|
1378 |
-
if (this.isDestroyed) {
|
1379 |
-
return;
|
1380 |
-
}
|
1381 |
-
|
1382 |
-
data.shuffle = this;
|
1383 |
-
this.emit(name, data);
|
1384 |
-
}
|
1385 |
-
/**
|
1386 |
-
* Zeros out the y columns array, which is used to determine item placement.
|
1387 |
-
* @private
|
1388 |
-
*/
|
1389 |
-
|
1390 |
-
}, {
|
1391 |
-
key: "_resetCols",
|
1392 |
-
value: function _resetCols() {
|
1393 |
-
var i = this.cols;
|
1394 |
-
this.positions = [];
|
1395 |
-
|
1396 |
-
while (i) {
|
1397 |
-
i -= 1;
|
1398 |
-
this.positions.push(0);
|
1399 |
-
}
|
1400 |
-
}
|
1401 |
-
/**
|
1402 |
-
* Loops through each item that should be shown and calculates the x, y position.
|
1403 |
-
* @param {ShuffleItem[]} items Array of items that will be shown/layed
|
1404 |
-
* out in order in their array.
|
1405 |
-
*/
|
1406 |
-
|
1407 |
-
}, {
|
1408 |
-
key: "_layout",
|
1409 |
-
value: function _layout(items) {
|
1410 |
-
var _this4 = this;
|
1411 |
-
|
1412 |
-
var itemPositions = this._getNextPositions(items);
|
1413 |
-
|
1414 |
-
var count = 0;
|
1415 |
-
items.forEach(function (item, i) {
|
1416 |
-
function callback() {
|
1417 |
-
item.applyCss(ShuffleItem.Css.VISIBLE.after);
|
1418 |
-
} // If the item will not change its position, do not add it to the render
|
1419 |
-
// queue. Transitions don't fire when setting a property to the same value.
|
1420 |
-
|
1421 |
-
|
1422 |
-
if (Point.equals(item.point, itemPositions[i]) && !item.isHidden) {
|
1423 |
-
item.applyCss(ShuffleItem.Css.VISIBLE.before);
|
1424 |
-
callback();
|
1425 |
-
return;
|
1426 |
-
}
|
1427 |
-
|
1428 |
-
item.point = itemPositions[i];
|
1429 |
-
item.scale = ShuffleItem.Scale.VISIBLE;
|
1430 |
-
item.isHidden = false; // Clone the object so that the `before` object isn't modified when the
|
1431 |
-
// transition delay is added.
|
1432 |
-
|
1433 |
-
var styles = _this4.getStylesForTransition(item, ShuffleItem.Css.VISIBLE.before);
|
1434 |
-
|
1435 |
-
styles.transitionDelay = _this4._getStaggerAmount(count) + 'ms';
|
1436 |
-
|
1437 |
-
_this4._queue.push({
|
1438 |
-
item: item,
|
1439 |
-
styles: styles,
|
1440 |
-
callback: callback
|
1441 |
-
});
|
1442 |
-
|
1443 |
-
count += 1;
|
1444 |
-
});
|
1445 |
-
}
|
1446 |
-
/**
|
1447 |
-
* Return an array of Point instances representing the future positions of
|
1448 |
-
* each item.
|
1449 |
-
* @param {ShuffleItem[]} items Array of sorted shuffle items.
|
1450 |
-
* @return {Point[]}
|
1451 |
-
* @private
|
1452 |
-
*/
|
1453 |
-
|
1454 |
-
}, {
|
1455 |
-
key: "_getNextPositions",
|
1456 |
-
value: function _getNextPositions(items) {
|
1457 |
-
var _this5 = this;
|
1458 |
-
|
1459 |
-
// If position data is going to be changed, add the item's size to the
|
1460 |
-
// transformer to allow for calculations.
|
1461 |
-
if (this.options.isCentered) {
|
1462 |
-
var itemsData = items.map(function (item, i) {
|
1463 |
-
var itemSize = Shuffle.getSize(item.element, true);
|
1464 |
-
|
1465 |
-
var point = _this5._getItemPosition(itemSize);
|
1466 |
-
|
1467 |
-
return new Rect(point.x, point.y, itemSize.width, itemSize.height, i);
|
1468 |
-
});
|
1469 |
-
return this.getTransformedPositions(itemsData, this.containerWidth);
|
1470 |
-
} // If no transforms are going to happen, simply return an array of the
|
1471 |
-
// future points of each item.
|
1472 |
-
|
1473 |
-
|
1474 |
-
return items.map(function (item) {
|
1475 |
-
return _this5._getItemPosition(Shuffle.getSize(item.element, true));
|
1476 |
-
});
|
1477 |
-
}
|
1478 |
-
/**
|
1479 |
-
* Determine the location of the next item, based on its size.
|
1480 |
-
* @param {{width: number, height: number}} itemSize Object with width and height.
|
1481 |
-
* @return {Point}
|
1482 |
-
* @private
|
1483 |
-
*/
|
1484 |
-
|
1485 |
-
}, {
|
1486 |
-
key: "_getItemPosition",
|
1487 |
-
value: function _getItemPosition(itemSize) {
|
1488 |
-
return getItemPosition({
|
1489 |
-
itemSize: itemSize,
|
1490 |
-
positions: this.positions,
|
1491 |
-
gridSize: this.colWidth,
|
1492 |
-
total: this.cols,
|
1493 |
-
threshold: this.options.columnThreshold,
|
1494 |
-
buffer: this.options.buffer
|
1495 |
-
});
|
1496 |
-
}
|
1497 |
-
/**
|
1498 |
-
* Mutate positions before they're applied.
|
1499 |
-
* @param {Rect[]} itemRects Item data objects.
|
1500 |
-
* @param {number} containerWidth Width of the containing element.
|
1501 |
-
* @return {Point[]}
|
1502 |
-
* @protected
|
1503 |
-
*/
|
1504 |
-
|
1505 |
-
}, {
|
1506 |
-
key: "getTransformedPositions",
|
1507 |
-
value: function getTransformedPositions(itemRects, containerWidth) {
|
1508 |
-
return getCenteredPositions(itemRects, containerWidth);
|
1509 |
-
}
|
1510 |
-
/**
|
1511 |
-
* Hides the elements that don't match our filter.
|
1512 |
-
* @param {ShuffleItem[]} collection Collection to shrink.
|
1513 |
-
* @private
|
1514 |
-
*/
|
1515 |
-
|
1516 |
-
}, {
|
1517 |
-
key: "_shrink",
|
1518 |
-
value: function _shrink() {
|
1519 |
-
var _this6 = this;
|
1520 |
-
|
1521 |
-
var collection = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this._getConcealedItems();
|
1522 |
-
var count = 0;
|
1523 |
-
collection.forEach(function (item) {
|
1524 |
-
function callback() {
|
1525 |
-
item.applyCss(ShuffleItem.Css.HIDDEN.after);
|
1526 |
-
} // Continuing would add a transitionend event listener to the element, but
|
1527 |
-
// that listener would not execute because the transform and opacity would
|
1528 |
-
// stay the same.
|
1529 |
-
// The callback is executed here because it is not guaranteed to be called
|
1530 |
-
// after the transitionend event because the transitionend could be
|
1531 |
-
// canceled if another animation starts.
|
1532 |
-
|
1533 |
-
|
1534 |
-
if (item.isHidden) {
|
1535 |
-
item.applyCss(ShuffleItem.Css.HIDDEN.before);
|
1536 |
-
callback();
|
1537 |
-
return;
|
1538 |
-
}
|
1539 |
-
|
1540 |
-
item.scale = ShuffleItem.Scale.HIDDEN;
|
1541 |
-
item.isHidden = true;
|
1542 |
-
|
1543 |
-
var styles = _this6.getStylesForTransition(item, ShuffleItem.Css.HIDDEN.before);
|
1544 |
-
|
1545 |
-
styles.transitionDelay = _this6._getStaggerAmount(count) + 'ms';
|
1546 |
-
|
1547 |
-
_this6._queue.push({
|
1548 |
-
item: item,
|
1549 |
-
styles: styles,
|
1550 |
-
callback: callback
|
1551 |
-
});
|
1552 |
-
|
1553 |
-
count += 1;
|
1554 |
-
});
|
1555 |
-
}
|
1556 |
-
/**
|
1557 |
-
* Resize handler.
|
1558 |
-
* @private
|
1559 |
-
*/
|
1560 |
-
|
1561 |
-
}, {
|
1562 |
-
key: "_handleResize",
|
1563 |
-
value: function _handleResize() {
|
1564 |
-
// If shuffle is disabled, destroyed, don't do anything
|
1565 |
-
if (!this.isEnabled || this.isDestroyed) {
|
1566 |
-
return;
|
1567 |
-
}
|
1568 |
-
|
1569 |
-
this.update();
|
1570 |
-
}
|
1571 |
-
/**
|
1572 |
-
* Returns styles which will be applied to the an item for a transition.
|
1573 |
-
* @param {ShuffleItem} item Item to get styles for. Should have updated
|
1574 |
-
* scale and point properties.
|
1575 |
-
* @param {Object} styleObject Extra styles that will be used in the transition.
|
1576 |
-
* @return {!Object} Transforms for transitions, left/top for animate.
|
1577 |
-
* @protected
|
1578 |
-
*/
|
1579 |
-
|
1580 |
-
}, {
|
1581 |
-
key: "getStylesForTransition",
|
1582 |
-
value: function getStylesForTransition(item, styleObject) {
|
1583 |
-
// Clone the object to avoid mutating the original.
|
1584 |
-
var styles = Object.assign({}, styleObject);
|
1585 |
-
|
1586 |
-
if (this.options.useTransforms) {
|
1587 |
-
var x = this.options.roundTransforms ? Math.round(item.point.x) : item.point.x;
|
1588 |
-
var y = this.options.roundTransforms ? Math.round(item.point.y) : item.point.y;
|
1589 |
-
styles.transform = "translate(".concat(x, "px, ").concat(y, "px) scale(").concat(item.scale, ")");
|
1590 |
-
} else {
|
1591 |
-
styles.left = item.point.x + 'px';
|
1592 |
-
styles.top = item.point.y + 'px';
|
1593 |
-
}
|
1594 |
-
|
1595 |
-
return styles;
|
1596 |
-
}
|
1597 |
-
/**
|
1598 |
-
* Listen for the transition end on an element and execute the itemCallback
|
1599 |
-
* when it finishes.
|
1600 |
-
* @param {Element} element Element to listen on.
|
1601 |
-
* @param {function} itemCallback Callback for the item.
|
1602 |
-
* @param {function} done Callback to notify `parallel` that this one is done.
|
1603 |
-
*/
|
1604 |
-
|
1605 |
-
}, {
|
1606 |
-
key: "_whenTransitionDone",
|
1607 |
-
value: function _whenTransitionDone(element, itemCallback, done) {
|
1608 |
-
var id = onTransitionEnd(element, function (evt) {
|
1609 |
-
itemCallback();
|
1610 |
-
done(null, evt);
|
1611 |
-
});
|
1612 |
-
|
1613 |
-
this._transitions.push(id);
|
1614 |
-
}
|
1615 |
-
/**
|
1616 |
-
* Return a function which will set CSS styles and call the `done` function
|
1617 |
-
* when (if) the transition finishes.
|
1618 |
-
* @param {Object} opts Transition object.
|
1619 |
-
* @return {function} A function to be called with a `done` function.
|
1620 |
-
*/
|
1621 |
-
|
1622 |
-
}, {
|
1623 |
-
key: "_getTransitionFunction",
|
1624 |
-
value: function _getTransitionFunction(opts) {
|
1625 |
-
var _this7 = this;
|
1626 |
-
|
1627 |
-
return function (done) {
|
1628 |
-
opts.item.applyCss(opts.styles);
|
1629 |
-
|
1630 |
-
_this7._whenTransitionDone(opts.item.element, opts.callback, done);
|
1631 |
-
};
|
1632 |
-
}
|
1633 |
-
/**
|
1634 |
-
* Execute the styles gathered in the style queue. This applies styles to elements,
|
1635 |
-
* triggering transitions.
|
1636 |
-
* @private
|
1637 |
-
*/
|
1638 |
-
|
1639 |
-
}, {
|
1640 |
-
key: "_processQueue",
|
1641 |
-
value: function _processQueue() {
|
1642 |
-
if (this.isTransitioning) {
|
1643 |
-
this._cancelMovement();
|
1644 |
-
}
|
1645 |
-
|
1646 |
-
var hasSpeed = this.options.speed > 0;
|
1647 |
-
var hasQueue = this._queue.length > 0;
|
1648 |
-
|
1649 |
-
if (hasQueue && hasSpeed && this.isInitialized) {
|
1650 |
-
this._startTransitions(this._queue);
|
1651 |
-
} else if (hasQueue) {
|
1652 |
-
this._styleImmediately(this._queue);
|
1653 |
-
|
1654 |
-
this._dispatch(Shuffle.EventType.LAYOUT); // A call to layout happened, but none of the newly visible items will
|
1655 |
-
// change position or the transition duration is zero, which will not trigger
|
1656 |
-
// the transitionend event.
|
1657 |
-
|
1658 |
-
} else {
|
1659 |
-
this._dispatch(Shuffle.EventType.LAYOUT);
|
1660 |
-
} // Remove everything in the style queue
|
1661 |
-
|
1662 |
-
|
1663 |
-
this._queue.length = 0;
|
1664 |
-
}
|
1665 |
-
/**
|
1666 |
-
* Wait for each transition to finish, the emit the layout event.
|
1667 |
-
* @param {Object[]} transitions Array of transition objects.
|
1668 |
-
*/
|
1669 |
-
|
1670 |
-
}, {
|
1671 |
-
key: "_startTransitions",
|
1672 |
-
value: function _startTransitions(transitions) {
|
1673 |
-
var _this8 = this;
|
1674 |
-
|
1675 |
-
// Set flag that shuffle is currently in motion.
|
1676 |
-
this.isTransitioning = true; // Create an array of functions to be called.
|
1677 |
-
|
1678 |
-
var callbacks = transitions.map(function (obj) {
|
1679 |
-
return _this8._getTransitionFunction(obj);
|
1680 |
-
});
|
1681 |
-
arrayParallel(callbacks, this._movementFinished.bind(this));
|
1682 |
-
}
|
1683 |
-
}, {
|
1684 |
-
key: "_cancelMovement",
|
1685 |
-
value: function _cancelMovement() {
|
1686 |
-
// Remove the transition end event for each listener.
|
1687 |
-
this._transitions.forEach(cancelTransitionEnd); // Reset the array.
|
1688 |
-
|
1689 |
-
|
1690 |
-
this._transitions.length = 0; // Show it's no longer active.
|
1691 |
-
|
1692 |
-
this.isTransitioning = false;
|
1693 |
-
}
|
1694 |
-
/**
|
1695 |
-
* Apply styles without a transition.
|
1696 |
-
* @param {Object[]} objects Array of transition objects.
|
1697 |
-
* @private
|
1698 |
-
*/
|
1699 |
-
|
1700 |
-
}, {
|
1701 |
-
key: "_styleImmediately",
|
1702 |
-
value: function _styleImmediately(objects) {
|
1703 |
-
if (objects.length) {
|
1704 |
-
var elements = objects.map(function (obj) {
|
1705 |
-
return obj.item.element;
|
1706 |
-
});
|
1707 |
-
|
1708 |
-
Shuffle._skipTransitions(elements, function () {
|
1709 |
-
objects.forEach(function (obj) {
|
1710 |
-
obj.item.applyCss(obj.styles);
|
1711 |
-
obj.callback();
|
1712 |
-
});
|
1713 |
-
});
|
1714 |
-
}
|
1715 |
-
}
|
1716 |
-
}, {
|
1717 |
-
key: "_movementFinished",
|
1718 |
-
value: function _movementFinished() {
|
1719 |
-
this._transitions.length = 0;
|
1720 |
-
this.isTransitioning = false;
|
1721 |
-
|
1722 |
-
this._dispatch(Shuffle.EventType.LAYOUT);
|
1723 |
-
}
|
1724 |
-
/**
|
1725 |
-
* The magic. This is what makes the plugin 'shuffle'
|
1726 |
-
* @param {string|string[]|function(Element):boolean} [category] Category to filter by.
|
1727 |
-
* Can be a function, string, or array of strings.
|
1728 |
-
* @param {SortOptions} [sortOptions] A sort object which can sort the visible set
|
1729 |
-
*/
|
1730 |
-
|
1731 |
-
}, {
|
1732 |
-
key: "filter",
|
1733 |
-
value: function filter(category, sortOptions) {
|
1734 |
-
if (!this.isEnabled) {
|
1735 |
-
return;
|
1736 |
-
}
|
1737 |
-
|
1738 |
-
if (!category || category && category.length === 0) {
|
1739 |
-
category = Shuffle.ALL_ITEMS; // eslint-disable-line no-param-reassign
|
1740 |
-
}
|
1741 |
-
|
1742 |
-
this._filter(category); // Shrink each hidden item
|
1743 |
-
|
1744 |
-
|
1745 |
-
this._shrink(); // How many visible elements?
|
1746 |
-
|
1747 |
-
|
1748 |
-
this._updateItemCount(); // Update transforms on visible elements so they will animate to their new positions.
|
1749 |
-
|
1750 |
-
|
1751 |
-
this.sort(sortOptions);
|
1752 |
-
}
|
1753 |
-
/**
|
1754 |
-
* Gets the visible elements, sorts them, and passes them to layout.
|
1755 |
-
* @param {SortOptions} [sortOptions] The options object to pass to `sorter`.
|
1756 |
-
*/
|
1757 |
-
|
1758 |
-
}, {
|
1759 |
-
key: "sort",
|
1760 |
-
value: function sort() {
|
1761 |
-
var sortOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.lastSort;
|
1762 |
-
|
1763 |
-
if (!this.isEnabled) {
|
1764 |
-
return;
|
1765 |
-
}
|
1766 |
-
|
1767 |
-
this._resetCols();
|
1768 |
-
|
1769 |
-
var items = sorter(this._getFilteredItems(), sortOptions);
|
1770 |
-
|
1771 |
-
this._layout(items); // `_layout` always happens after `_shrink`, so it's safe to process the style
|
1772 |
-
// queue here with styles from the shrink method.
|
1773 |
-
|
1774 |
-
|
1775 |
-
this._processQueue(); // Adjust the height of the container.
|
1776 |
-
|
1777 |
-
|
1778 |
-
this._setContainerSize();
|
1779 |
-
|
1780 |
-
this.lastSort = sortOptions;
|
1781 |
-
}
|
1782 |
-
/**
|
1783 |
-
* Reposition everything.
|
1784 |
-
* @param {boolean} [isOnlyLayout=false] If true, column and gutter widths won't be recalculated.
|
1785 |
-
*/
|
1786 |
-
|
1787 |
-
}, {
|
1788 |
-
key: "update",
|
1789 |
-
value: function update() {
|
1790 |
-
var isOnlyLayout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
1791 |
-
|
1792 |
-
if (this.isEnabled) {
|
1793 |
-
if (!isOnlyLayout) {
|
1794 |
-
// Get updated colCount
|
1795 |
-
this._setColumns();
|
1796 |
-
} // Layout items
|
1797 |
-
|
1798 |
-
|
1799 |
-
this.sort();
|
1800 |
-
}
|
1801 |
-
}
|
1802 |
-
/**
|
1803 |
-
* Use this instead of `update()` if you don't need the columns and gutters updated
|
1804 |
-
* Maybe an image inside `shuffle` loaded (and now has a height), which means calculations
|
1805 |
-
* could be off.
|
1806 |
-
*/
|
1807 |
-
|
1808 |
-
}, {
|
1809 |
-
key: "layout",
|
1810 |
-
value: function layout() {
|
1811 |
-
this.update(true);
|
1812 |
-
}
|
1813 |
-
/**
|
1814 |
-
* New items have been appended to shuffle. Mix them in with the current
|
1815 |
-
* filter or sort status.
|
1816 |
-
* @param {Element[]} newItems Collection of new items.
|
1817 |
-
*/
|
1818 |
-
|
1819 |
-
}, {
|
1820 |
-
key: "add",
|
1821 |
-
value: function add(newItems) {
|
1822 |
-
var _this9 = this;
|
1823 |
-
|
1824 |
-
var items = arrayUnique(newItems).map(function (el) {
|
1825 |
-
return new ShuffleItem(el);
|
1826 |
-
}); // Add classes and set initial positions.
|
1827 |
-
|
1828 |
-
this._initItems(items); // Determine which items will go with the current filter.
|
1829 |
-
|
1830 |
-
|
1831 |
-
this._resetCols();
|
1832 |
-
|
1833 |
-
var allItems = this._mergeNewItems(items);
|
1834 |
-
|
1835 |
-
var sortedItems = sorter(allItems, this.lastSort);
|
1836 |
-
|
1837 |
-
var allSortedItemsSet = this._filter(this.lastFilter, sortedItems);
|
1838 |
-
|
1839 |
-
var isNewItem = function isNewItem(item) {
|
1840 |
-
return items.includes(item);
|
1841 |
-
};
|
1842 |
-
|
1843 |
-
var applyHiddenState = function applyHiddenState(item) {
|
1844 |
-
item.scale = ShuffleItem.Scale.HIDDEN;
|
1845 |
-
item.isHidden = true;
|
1846 |
-
item.applyCss(ShuffleItem.Css.HIDDEN.before);
|
1847 |
-
item.applyCss(ShuffleItem.Css.HIDDEN.after);
|
1848 |
-
}; // Layout all items again so that new items get positions.
|
1849 |
-
// Synchonously apply positions.
|
1850 |
-
|
1851 |
-
|
1852 |
-
var itemPositions = this._getNextPositions(allSortedItemsSet.visible);
|
1853 |
-
|
1854 |
-
allSortedItemsSet.visible.forEach(function (item, i) {
|
1855 |
-
if (isNewItem(item)) {
|
1856 |
-
item.point = itemPositions[i];
|
1857 |
-
applyHiddenState(item);
|
1858 |
-
item.applyCss(_this9.getStylesForTransition(item, {}));
|
1859 |
-
}
|
1860 |
-
});
|
1861 |
-
allSortedItemsSet.hidden.forEach(function (item) {
|
1862 |
-
if (isNewItem(item)) {
|
1863 |
-
applyHiddenState(item);
|
1864 |
-
}
|
1865 |
-
}); // Cause layout so that the styles above are applied.
|
1866 |
-
|
1867 |
-
this.element.offsetWidth; // eslint-disable-line no-unused-expressions
|
1868 |
-
// Add transition to each item.
|
1869 |
-
|
1870 |
-
this.setItemTransitions(items); // Update the list of items.
|
1871 |
-
|
1872 |
-
this.items = this._mergeNewItems(items); // Update layout/visibility of new and old items.
|
1873 |
-
|
1874 |
-
this.filter(this.lastFilter);
|
1875 |
-
}
|
1876 |
-
/**
|
1877 |
-
* Disables shuffle from updating dimensions and layout on resize
|
1878 |
-
*/
|
1879 |
-
|
1880 |
-
}, {
|
1881 |
-
key: "disable",
|
1882 |
-
value: function disable() {
|
1883 |
-
this.isEnabled = false;
|
1884 |
-
}
|
1885 |
-
/**
|
1886 |
-
* Enables shuffle again
|
1887 |
-
* @param {boolean} [isUpdateLayout=true] if undefined, shuffle will update columns and gutters
|
1888 |
-
*/
|
1889 |
-
|
1890 |
-
}, {
|
1891 |
-
key: "enable",
|
1892 |
-
value: function enable() {
|
1893 |
-
var isUpdateLayout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
1894 |
-
this.isEnabled = true;
|
1895 |
-
|
1896 |
-
if (isUpdateLayout) {
|
1897 |
-
this.update();
|
1898 |
-
}
|
1899 |
-
}
|
1900 |
-
/**
|
1901 |
-
* Remove 1 or more shuffle items.
|
1902 |
-
* @param {Element[]} elements An array containing one or more
|
1903 |
-
* elements in shuffle
|
1904 |
-
* @return {Shuffle} The shuffle instance.
|
1905 |
-
*/
|
1906 |
-
|
1907 |
-
}, {
|
1908 |
-
key: "remove",
|
1909 |
-
value: function remove(elements) {
|
1910 |
-
var _this10 = this;
|
1911 |
-
|
1912 |
-
if (!elements.length) {
|
1913 |
-
return;
|
1914 |
-
}
|
1915 |
-
|
1916 |
-
var collection = arrayUnique(elements);
|
1917 |
-
var oldItems = collection.map(function (element) {
|
1918 |
-
return _this10.getItemByElement(element);
|
1919 |
-
}).filter(function (item) {
|
1920 |
-
return !!item;
|
1921 |
-
});
|
1922 |
-
|
1923 |
-
var handleLayout = function handleLayout() {
|
1924 |
-
_this10._disposeItems(oldItems); // Remove the collection in the callback
|
1925 |
-
|
1926 |
-
|
1927 |
-
collection.forEach(function (element) {
|
1928 |
-
element.parentNode.removeChild(element);
|
1929 |
-
});
|
1930 |
-
|
1931 |
-
_this10._dispatch(Shuffle.EventType.REMOVED, {
|
1932 |
-
collection: collection
|
1933 |
-
});
|
1934 |
-
}; // Hide collection first.
|
1935 |
-
|
1936 |
-
|
1937 |
-
this._toggleFilterClasses({
|
1938 |
-
visible: [],
|
1939 |
-
hidden: oldItems
|
1940 |
-
});
|
1941 |
-
|
1942 |
-
this._shrink(oldItems);
|
1943 |
-
|
1944 |
-
this.sort(); // Update the list of items here because `remove` could be called again
|
1945 |
-
// with an item that is in the process of being removed.
|
1946 |
-
|
1947 |
-
this.items = this.items.filter(function (item) {
|
1948 |
-
return !oldItems.includes(item);
|
1949 |
-
});
|
1950 |
-
|
1951 |
-
this._updateItemCount();
|
1952 |
-
|
1953 |
-
this.once(Shuffle.EventType.LAYOUT, handleLayout);
|
1954 |
-
}
|
1955 |
-
/**
|
1956 |
-
* Retrieve a shuffle item by its element.
|
1957 |
-
* @param {Element} element Element to look for.
|
1958 |
-
* @return {?ShuffleItem} A shuffle item or undefined if it's not found.
|
1959 |
-
*/
|
1960 |
-
|
1961 |
-
}, {
|
1962 |
-
key: "getItemByElement",
|
1963 |
-
value: function getItemByElement(element) {
|
1964 |
-
return this.items.find(function (item) {
|
1965 |
-
return item.element === element;
|
1966 |
-
});
|
1967 |
-
}
|
1968 |
-
/**
|
1969 |
-
* Dump the elements currently stored and reinitialize all child elements which
|
1970 |
-
* match the `itemSelector`.
|
1971 |
-
*/
|
1972 |
-
|
1973 |
-
}, {
|
1974 |
-
key: "resetItems",
|
1975 |
-
value: function resetItems() {
|
1976 |
-
var _this11 = this;
|
1977 |
-
|
1978 |
-
// Remove refs to current items.
|
1979 |
-
this._disposeItems(this.items);
|
1980 |
-
|
1981 |
-
this.isInitialized = false; // Find new items in the DOM.
|
1982 |
-
|
1983 |
-
this.items = this._getItems(); // Set initial styles on the new items.
|
1984 |
-
|
1985 |
-
this._initItems(this.items);
|
1986 |
-
|
1987 |
-
this.once(Shuffle.EventType.LAYOUT, function () {
|
1988 |
-
// Add transition to each item.
|
1989 |
-
_this11.setItemTransitions(_this11.items);
|
1990 |
-
|
1991 |
-
_this11.isInitialized = true;
|
1992 |
-
}); // Lay out all items.
|
1993 |
-
|
1994 |
-
this.filter(this.lastFilter);
|
1995 |
-
}
|
1996 |
-
/**
|
1997 |
-
* Destroys shuffle, removes events, styles, and classes
|
1998 |
-
*/
|
1999 |
-
|
2000 |
-
}, {
|
2001 |
-
key: "destroy",
|
2002 |
-
value: function destroy() {
|
2003 |
-
this._cancelMovement();
|
2004 |
-
|
2005 |
-
window.removeEventListener('resize', this._onResize); // Reset container styles
|
2006 |
-
|
2007 |
-
this.element.classList.remove('shuffle');
|
2008 |
-
this.element.removeAttribute('style'); // Reset individual item styles
|
2009 |
-
|
2010 |
-
this._disposeItems(this.items);
|
2011 |
-
|
2012 |
-
this.items.length = 0;
|
2013 |
-
this._transitions.length = 0; // Null DOM references
|
2014 |
-
|
2015 |
-
this.options.sizer = null;
|
2016 |
-
this.element = null; // Set a flag so if a debounced resize has been triggered,
|
2017 |
-
// it can first check if it is actually isDestroyed and not doing anything
|
2018 |
-
|
2019 |
-
this.isDestroyed = true;
|
2020 |
-
this.isEnabled = false;
|
2021 |
-
}
|
2022 |
-
/**
|
2023 |
-
* Returns the outer width of an element, optionally including its margins.
|
2024 |
-
*
|
2025 |
-
* There are a few different methods for getting the width of an element, none of
|
2026 |
-
* which work perfectly for all Shuffle's use cases.
|
2027 |
-
*
|
2028 |
-
* 1. getBoundingClientRect() `left` and `right` properties.
|
2029 |
-
* - Accounts for transform scaled elements, making it useless for Shuffle
|
2030 |
-
* elements which have shrunk.
|
2031 |
-
* 2. The `offsetWidth` property.
|
2032 |
-
* - This value stays the same regardless of the elements transform property,
|
2033 |
-
* however, it does not return subpixel values.
|
2034 |
-
* 3. getComputedStyle()
|
2035 |
-
* - This works great Chrome, Firefox, Safari, but IE<=11 does not include
|
2036 |
-
* padding and border when box-sizing: border-box is set, requiring a feature
|
2037 |
-
* test and extra work to add the padding back for IE and other browsers which
|
2038 |
-
* follow the W3C spec here.
|
2039 |
-
*
|
2040 |
-
* @param {Element} element The element.
|
2041 |
-
* @param {boolean} [includeMargins=false] Whether to include margins.
|
2042 |
-
* @return {{width: number, height: number}} The width and height.
|
2043 |
-
*/
|
2044 |
-
|
2045 |
-
}], [{
|
2046 |
-
key: "getSize",
|
2047 |
-
value: function getSize(element) {
|
2048 |
-
var includeMargins = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
2049 |
-
// Store the styles so that they can be used by others without asking for it again.
|
2050 |
-
var styles = window.getComputedStyle(element, null);
|
2051 |
-
var width = getNumberStyle(element, 'width', styles);
|
2052 |
-
var height = getNumberStyle(element, 'height', styles);
|
2053 |
-
|
2054 |
-
if (includeMargins) {
|
2055 |
-
var marginLeft = getNumberStyle(element, 'marginLeft', styles);
|
2056 |
-
var marginRight = getNumberStyle(element, 'marginRight', styles);
|
2057 |
-
var marginTop = getNumberStyle(element, 'marginTop', styles);
|
2058 |
-
var marginBottom = getNumberStyle(element, 'marginBottom', styles);
|
2059 |
-
width += marginLeft + marginRight;
|
2060 |
-
height += marginTop + marginBottom;
|
2061 |
-
}
|
2062 |
-
|
2063 |
-
return {
|
2064 |
-
width: width,
|
2065 |
-
height: height
|
2066 |
-
};
|
2067 |
-
}
|
2068 |
-
/**
|
2069 |
-
* Change a property or execute a function which will not have a transition
|
2070 |
-
* @param {Element[]} elements DOM elements that won't be transitioned.
|
2071 |
-
* @param {function} callback A function which will be called while transition
|
2072 |
-
* is set to 0ms.
|
2073 |
-
* @private
|
2074 |
-
*/
|
2075 |
-
|
2076 |
-
}, {
|
2077 |
-
key: "_skipTransitions",
|
2078 |
-
value: function _skipTransitions(elements, callback) {
|
2079 |
-
var zero = '0ms'; // Save current duration and delay.
|
2080 |
-
|
2081 |
-
var data = elements.map(function (element) {
|
2082 |
-
var style = element.style;
|
2083 |
-
var duration = style.transitionDuration;
|
2084 |
-
var delay = style.transitionDelay; // Set the duration to zero so it happens immediately
|
2085 |
-
|
2086 |
-
style.transitionDuration = zero;
|
2087 |
-
style.transitionDelay = zero;
|
2088 |
-
return {
|
2089 |
-
duration: duration,
|
2090 |
-
delay: delay
|
2091 |
-
};
|
2092 |
-
});
|
2093 |
-
callback(); // Cause forced synchronous layout.
|
2094 |
-
|
2095 |
-
elements[0].offsetWidth; // eslint-disable-line no-unused-expressions
|
2096 |
-
// Put the duration back
|
2097 |
-
|
2098 |
-
elements.forEach(function (element, i) {
|
2099 |
-
element.style.transitionDuration = data[i].duration;
|
2100 |
-
element.style.transitionDelay = data[i].delay;
|
2101 |
-
});
|
2102 |
-
}
|
2103 |
-
}]);
|
2104 |
-
|
2105 |
-
return Shuffle;
|
2106 |
-
}(tinyEmitter);
|
2107 |
-
|
2108 |
-
Shuffle.ShuffleItem = ShuffleItem;
|
2109 |
-
Shuffle.ALL_ITEMS = 'all';
|
2110 |
-
Shuffle.FILTER_ATTRIBUTE_KEY = 'groups';
|
2111 |
-
/** @enum {string} */
|
2112 |
-
|
2113 |
-
Shuffle.EventType = {
|
2114 |
-
LAYOUT: 'shuffle:layout',
|
2115 |
-
REMOVED: 'shuffle:removed'
|
2116 |
-
};
|
2117 |
-
/** @enum {string} */
|
2118 |
-
|
2119 |
-
Shuffle.Classes = Classes;
|
2120 |
-
/** @enum {string} */
|
2121 |
-
|
2122 |
-
Shuffle.FilterMode = {
|
2123 |
-
ANY: 'any',
|
2124 |
-
ALL: 'all'
|
2125 |
-
}; // Overrideable options
|
2126 |
-
|
2127 |
-
Shuffle.options = {
|
2128 |
-
// Initial filter group.
|
2129 |
-
group: Shuffle.ALL_ITEMS,
|
2130 |
-
// Transition/animation speed (milliseconds).
|
2131 |
-
speed: 250,
|
2132 |
-
// CSS easing function to use.
|
2133 |
-
easing: 'cubic-bezier(0.4, 0.0, 0.2, 1)',
|
2134 |
-
// e.g. '.picture-item'.
|
2135 |
-
itemSelector: '*',
|
2136 |
-
// Element or selector string. Use an element to determine the size of columns
|
2137 |
-
// and gutters.
|
2138 |
-
sizer: null,
|
2139 |
-
// A static number or function that tells the plugin how wide the gutters
|
2140 |
-
// between columns are (in pixels).
|
2141 |
-
gutterWidth: 0,
|
2142 |
-
// A static number or function that returns a number which tells the plugin
|
2143 |
-
// how wide the columns are (in pixels).
|
2144 |
-
columnWidth: 0,
|
2145 |
-
// If your group is not json, and is comma delimeted, you could set delimiter
|
2146 |
-
// to ','.
|
2147 |
-
delimiter: null,
|
2148 |
-
// Useful for percentage based heights when they might not always be exactly
|
2149 |
-
// the same (in pixels).
|
2150 |
-
buffer: 0,
|
2151 |
-
// Reading the width of elements isn't precise enough and can cause columns to
|
2152 |
-
// jump between values.
|
2153 |
-
columnThreshold: 0.01,
|
2154 |
-
// Shuffle can be isInitialized with a sort object. It is the same object
|
2155 |
-
// given to the sort method.
|
2156 |
-
initialSort: null,
|
2157 |
-
// By default, shuffle will throttle resize events. This can be changed or
|
2158 |
-
// removed.
|
2159 |
-
throttle: throttleit,
|
2160 |
-
// How often shuffle can be called on resize (in milliseconds).
|
2161 |
-
throttleTime: 300,
|
2162 |
-
// Transition delay offset for each item in milliseconds.
|
2163 |
-
staggerAmount: 15,
|
2164 |
-
// Maximum stagger delay in milliseconds.
|
2165 |
-
staggerAmountMax: 150,
|
2166 |
-
// Whether to use transforms or absolute positioning.
|
2167 |
-
useTransforms: true,
|
2168 |
-
// Affects using an array with filter. e.g. `filter(['one', 'two'])`. With "any",
|
2169 |
-
// the element passes the test if any of its groups are in the array. With "all",
|
2170 |
-
// the element only passes if all groups are in the array.
|
2171 |
-
filterMode: Shuffle.FilterMode.ANY,
|
2172 |
-
// Attempt to center grid items in each row.
|
2173 |
-
isCentered: false,
|
2174 |
-
// Whether to round pixel values used in translate(x, y). This usually avoids
|
2175 |
-
// blurriness.
|
2176 |
-
roundTransforms: true
|
2177 |
-
};
|
2178 |
-
Shuffle.Point = Point;
|
2179 |
-
Shuffle.Rect = Rect; // Expose for testing. Hack at your own risk.
|
2180 |
-
|
2181 |
-
Shuffle.__sorter = sorter;
|
2182 |
-
Shuffle.__getColumnSpan = getColumnSpan;
|
2183 |
-
Shuffle.__getAvailablePositions = getAvailablePositions;
|
2184 |
-
Shuffle.__getShortColumn = getShortColumn;
|
2185 |
-
Shuffle.__getCenteredPositions = getCenteredPositions;
|
2186 |
-
|
2187 |
-
return Shuffle;
|
2188 |
-
|
2189 |
-
}));
|
2190 |
-
//# sourceMappingURL=shuffle.js.map
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resources/js/shuffle.min.js
DELETED
@@ -1,2 +0,0 @@
|
|
1 |
-
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).Shuffle=e()}(this,function(){"use strict";function t(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function e(t,e){for(var i=0;i<e.length;i++){var n=e[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}function i(t,i,n){return i&&e(t.prototype,i),n&&e(t,n),t}function n(t){return(n=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function s(t,e){return(s=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function o(t,e){return!e||"object"!=typeof e&&"function"!=typeof e?function(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}(t):e}function r(){}r.prototype={on:function(t,e,i){var n=this.e||(this.e={});return(n[t]||(n[t]=[])).push({fn:e,ctx:i}),this},once:function(t,e,i){var n=this;function s(){n.off(t,s),e.apply(i,arguments)}return s._=e,this.on(t,s,i)},emit:function(t){for(var e=[].slice.call(arguments,1),i=((this.e||(this.e={}))[t]||[]).slice(),n=0,s=i.length;n<s;n++)i[n].fn.apply(i[n].ctx,e);return this},off:function(t,e){var i=this.e||(this.e={}),n=i[t],s=[];if(n&&e)for(var o=0,r=n.length;o<r;o++)n[o].fn!==e&&n[o].fn._!==e&&s.push(n[o]);return s.length?i[t]=s:delete i[t],this}};var l=r,a=r;l.TinyEmitter=a;var u="undefined"!=typeof Element?Element.prototype:{},h=u.matches||u.matchesSelector||u.webkitMatchesSelector||u.mozMatchesSelector||u.msMatchesSelector||u.oMatchesSelector,f=function(t,e){if(!t||1!==t.nodeType)return!1;if(h)return h.call(t,e);for(var i=t.parentNode.querySelectorAll(e),n=0;n<i.length;n++)if(i[n]==t)return!0;return!1};var c=function(t,e){var i,n,s,o,r=0;return function(){i=this,n=arguments;var t=new Date-r;return o||(t>=e?l():o=setTimeout(l,e-t)),s};function l(){o=0,r=+new Date,s=t.apply(i,n),i=null,n=null}};function d(){}function m(t){return parseFloat(t)||0}var p=function(){function e(i,n){t(this,e),this.x=m(i),this.y=m(n)}return i(e,null,[{key:"equals",value:function(t,e){return t.x===e.x&&t.y===e.y}}]),e}(),v=function(){function e(i,n,s,o,r){t(this,e),this.id=r,this.left=i,this.top=n,this.width=s,this.height=o}return i(e,null,[{key:"intersects",value:function(t,e){return t.left<e.left+e.width&&e.left<t.left+t.width&&t.top<e.top+e.height&&e.top<t.top+t.height}}]),e}(),y={BASE:"shuffle",SHUFFLE_ITEM:"shuffle-item",VISIBLE:"shuffle-item--visible",HIDDEN:"shuffle-item--hidden"},g=0,_=function(){function e(i){t(this,e),g+=1,this.id=g,this.element=i,this.isVisible=!0,this.isHidden=!1}return i(e,[{key:"show",value:function(){this.isVisible=!0,this.element.classList.remove(y.HIDDEN),this.element.classList.add(y.VISIBLE),this.element.removeAttribute("aria-hidden")}},{key:"hide",value:function(){this.isVisible=!1,this.element.classList.remove(y.VISIBLE),this.element.classList.add(y.HIDDEN),this.element.setAttribute("aria-hidden",!0)}},{key:"init",value:function(){this.addClasses([y.SHUFFLE_ITEM,y.VISIBLE]),this.applyCss(e.Css.INITIAL),this.scale=e.Scale.VISIBLE,this.point=new p}},{key:"addClasses",value:function(t){var e=this;t.forEach(function(t){e.element.classList.add(t)})}},{key:"removeClasses",value:function(t){var e=this;t.forEach(function(t){e.element.classList.remove(t)})}},{key:"applyCss",value:function(t){var e=this;Object.keys(t).forEach(function(i){e.element.style[i]=t[i]})}},{key:"dispose",value:function(){this.removeClasses([y.HIDDEN,y.VISIBLE,y.SHUFFLE_ITEM]),this.element.removeAttribute("style"),this.element=null}}]),e}();_.Css={INITIAL:{position:"absolute",top:0,left:0,visibility:"visible",willChange:"transform"},VISIBLE:{before:{opacity:1,visibility:"visible"},after:{transitionDelay:""}},HIDDEN:{before:{opacity:0},after:{visibility:"hidden",transitionDelay:""}}},_.Scale={VISIBLE:1,HIDDEN:.001};var E=null,I=function(){if(null!==E)return E;var t=document.body||document.documentElement,e=document.createElement("div");return e.style.cssText="width:10px;padding:2px;box-sizing:border-box;",t.appendChild(e),E="10px"===window.getComputedStyle(e,null).width,t.removeChild(e),E};function b(t,e){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:window.getComputedStyle(t,null),n=m(i[e]);return I()||"width"!==e?I()||"height"!==e||(n+=m(i.paddingTop)+m(i.paddingBottom)+m(i.borderTopWidth)+m(i.borderBottomWidth)):n+=m(i.paddingLeft)+m(i.paddingRight)+m(i.borderLeftWidth)+m(i.borderRightWidth),n}var S={reverse:!1,by:null,compare:null,randomize:!1,key:"element"};function T(t,e){var i=Object.assign({},S,e),n=Array.from(t),s=!1;return t.length?i.randomize?function(t){for(var e=t.length;e;){e-=1;var i=Math.floor(Math.random()*(e+1)),n=t[i];t[i]=t[e],t[e]=n}return t}(t):("function"==typeof i.by?t.sort(function(t,e){if(s)return 0;var n=i.by(t[i.key]),o=i.by(e[i.key]);return void 0===n&&void 0===o?(s=!0,0):n<o||"sortFirst"===n||"sortLast"===o?-1:n>o||"sortLast"===n||"sortFirst"===o?1:0}):"function"==typeof i.compare&&t.sort(i.compare),s?n:(i.reverse&&t.reverse(),t)):[]}var k={},w="transitionend",C=0;function L(t){return!!k[t]&&(k[t].element.removeEventListener(w,k[t].listener),k[t]=null,!0)}function D(t,e){var i=w+(C+=1),n=function(t){t.currentTarget===t.target&&(L(i),e(t))};return t.addEventListener(w,n),k[i]={element:t,listener:n},i}function z(t){return Math.max.apply(Math,t)}function M(t,e,i,n){var s=t/e;return Math.abs(Math.round(s)-s)<n&&(s=Math.round(s)),Math.min(Math.ceil(s),i)}function A(t,e,i){if(1===e)return t;for(var n=[],s=0;s<=i-e;s++)n.push(z(t.slice(s,s+e)));return n}function F(t,e){for(var i,n=(i=t,Math.min.apply(Math,i)),s=0,o=t.length;s<o;s++)if(t[s]>=n-e&&t[s]<=n+e)return s;return 0}function x(t,e){var i={};t.forEach(function(t){i[t.top]?i[t.top].push(t):i[t.top]=[t]});var n=[],s=[],o=[];return Object.keys(i).forEach(function(t){var r=i[t];s.push(r);var l,a=r[r.length-1],u=a.left+a.width,h=Math.round((e-u)/2),f=r,c=!1;if(h>0){var d=[];(c=r.every(function(t){var e=new v(t.left+h,t.top,t.width,t.height,t.id),i=!n.some(function(t){return v.intersects(e,t)});return d.push(e),i}))&&(f=d)}if(!c&&r.some(function(t){return n.some(function(e){var i=v.intersects(t,e);return i&&(l=e),i})})){var m=o.findIndex(function(t){return t.includes(l)});o.splice(m,1,s[m])}n=n.concat(f),o.push(f)}),[].concat.apply([],o).sort(function(t,e){return t.id-e.id}).map(function(t){return new p(t.left,t.top)})}function O(t){return Array.from(new Set(t))}var N=0,H=function(e){function r(e){var i,s=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};t(this,r),(i=o(this,n(r).call(this))).options=Object.assign({},r.options,s),i.options.delimeter&&(i.options.delimiter=i.options.delimeter),i.lastSort={},i.group=r.ALL_ITEMS,i.lastFilter=r.ALL_ITEMS,i.isEnabled=!0,i.isDestroyed=!1,i.isInitialized=!1,i._transitions=[],i.isTransitioning=!1,i._queue=[];var l=i._getElementOption(e);if(!l)throw new TypeError("Shuffle needs to be initialized with an element.");return i.element=l,i.id="shuffle_"+N,N+=1,i._init(),i.isInitialized=!0,i}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&s(t,e)}(r,l),i(r,[{key:"_init",value:function(){if(this.items=this._getItems(),this.options.sizer=this._getElementOption(this.options.sizer),this.element.classList.add(r.Classes.BASE),this._initItems(this.items),this._onResize=this._getResizeFunction(),window.addEventListener("resize",this._onResize),"complete"!==document.readyState){var t=this.layout.bind(this);window.addEventListener("load",function e(){window.removeEventListener("load",e),t()})}var e=window.getComputedStyle(this.element,null),i=r.getSize(this.element).width;this._validateStyles(e),this._setColumns(i),this.filter(this.options.group,this.options.initialSort),this.element.offsetWidth,this.setItemTransitions(this.items),this.element.style.transition="height ".concat(this.options.speed,"ms ").concat(this.options.easing)}},{key:"_getResizeFunction",value:function(){var t=this._handleResize.bind(this);return this.options.throttle?this.options.throttle(t,this.options.throttleTime):t}},{key:"_getElementOption",value:function(t){return"string"==typeof t?this.element.querySelector(t):t&&t.nodeType&&1===t.nodeType?t:t&&t.jquery?t[0]:null}},{key:"_validateStyles",value:function(t){"static"===t.position&&(this.element.style.position="relative"),"hidden"!==t.overflow&&(this.element.style.overflow="hidden")}},{key:"_filter",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.lastFilter,e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.items,i=this._getFilteredSets(t,e);return this._toggleFilterClasses(i),this.lastFilter=t,"string"==typeof t&&(this.group=t),i}},{key:"_getFilteredSets",value:function(t,e){var i=this,n=[],s=[];return t===r.ALL_ITEMS?n=e:e.forEach(function(e){i._doesPassFilter(t,e.element)?n.push(e):s.push(e)}),{visible:n,hidden:s}}},{key:"_doesPassFilter",value:function(t,e){if("function"==typeof t)return t.call(e,e,this);var i=e.getAttribute("data-"+r.FILTER_ATTRIBUTE_KEY),n=this.options.delimiter?i.split(this.options.delimiter):JSON.parse(i);function s(t){return n.includes(t)}return Array.isArray(t)?this.options.filterMode===r.FilterMode.ANY?t.some(s):t.every(s):n.includes(t)}},{key:"_toggleFilterClasses",value:function(t){var e=t.visible,i=t.hidden;e.forEach(function(t){t.show()}),i.forEach(function(t){t.hide()})}},{key:"_initItems",value:function(t){t.forEach(function(t){t.init()})}},{key:"_disposeItems",value:function(t){t.forEach(function(t){t.dispose()})}},{key:"_updateItemCount",value:function(){this.visibleItems=this._getFilteredItems().length}},{key:"setItemTransitions",value:function(t){var e=this.options,i=e.speed,n=e.easing,s=this.options.useTransforms?["transform"]:["top","left"],o=Object.keys(_.Css.HIDDEN.before).map(function(t){return t.replace(/([A-Z])/g,function(t,e){return"-".concat(e.toLowerCase())})}),r=s.concat(o).join();t.forEach(function(t){t.element.style.transitionDuration=i+"ms",t.element.style.transitionTimingFunction=n,t.element.style.transitionProperty=r})}},{key:"_getItems",value:function(){var t=this;return Array.from(this.element.children).filter(function(e){return f(e,t.options.itemSelector)}).map(function(t){return new _(t)})}},{key:"_mergeNewItems",value:function(t){var e=Array.from(this.element.children);return T(this.items.concat(t),{by:function(t){return e.indexOf(t)}})}},{key:"_getFilteredItems",value:function(){return this.items.filter(function(t){return t.isVisible})}},{key:"_getConcealedItems",value:function(){return this.items.filter(function(t){return!t.isVisible})}},{key:"_getColumnSize",value:function(t,e){var i;return 0===(i="function"==typeof this.options.columnWidth?this.options.columnWidth(t):this.options.sizer?r.getSize(this.options.sizer).width:this.options.columnWidth?this.options.columnWidth:this.items.length>0?r.getSize(this.items[0].element,!0).width:t)&&(i=t),i+e}},{key:"_getGutterSize",value:function(t){return"function"==typeof this.options.gutterWidth?this.options.gutterWidth(t):this.options.sizer?b(this.options.sizer,"marginLeft"):this.options.gutterWidth}},{key:"_setColumns",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:r.getSize(this.element).width,e=this._getGutterSize(t),i=this._getColumnSize(t,e),n=(t+e)/i;Math.abs(Math.round(n)-n)<this.options.columnThreshold&&(n=Math.round(n)),this.cols=Math.max(Math.floor(n||0),1),this.containerWidth=t,this.colWidth=i}},{key:"_setContainerSize",value:function(){this.element.style.height=this._getContainerSize()+"px"}},{key:"_getContainerSize",value:function(){return z(this.positions)}},{key:"_getStaggerAmount",value:function(t){return Math.min(t*this.options.staggerAmount,this.options.staggerAmountMax)}},{key:"_dispatch",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};this.isDestroyed||(e.shuffle=this,this.emit(t,e))}},{key:"_resetCols",value:function(){var t=this.cols;for(this.positions=[];t;)t-=1,this.positions.push(0)}},{key:"_layout",value:function(t){var e=this,i=this._getNextPositions(t),n=0;t.forEach(function(t,s){function o(){t.applyCss(_.Css.VISIBLE.after)}if(p.equals(t.point,i[s])&&!t.isHidden)return t.applyCss(_.Css.VISIBLE.before),void o();t.point=i[s],t.scale=_.Scale.VISIBLE,t.isHidden=!1;var r=e.getStylesForTransition(t,_.Css.VISIBLE.before);r.transitionDelay=e._getStaggerAmount(n)+"ms",e._queue.push({item:t,styles:r,callback:o}),n+=1})}},{key:"_getNextPositions",value:function(t){var e=this;if(this.options.isCentered){var i=t.map(function(t,i){var n=r.getSize(t.element,!0),s=e._getItemPosition(n);return new v(s.x,s.y,n.width,n.height,i)});return this.getTransformedPositions(i,this.containerWidth)}return t.map(function(t){return e._getItemPosition(r.getSize(t.element,!0))})}},{key:"_getItemPosition",value:function(t){return function(t){for(var e=t.itemSize,i=t.positions,n=t.gridSize,s=t.total,o=t.threshold,r=t.buffer,l=M(e.width,n,s,o),a=A(i,l,s),u=F(a,r),h=new p(n*u,a[u]),f=a[u]+e.height,c=0;c<l;c++)i[u+c]=f;return h}({itemSize:t,positions:this.positions,gridSize:this.colWidth,total:this.cols,threshold:this.options.columnThreshold,buffer:this.options.buffer})}},{key:"getTransformedPositions",value:function(t,e){return x(t,e)}},{key:"_shrink",value:function(){var t=this,e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this._getConcealedItems(),i=0;e.forEach(function(e){function n(){e.applyCss(_.Css.HIDDEN.after)}if(e.isHidden)return e.applyCss(_.Css.HIDDEN.before),void n();e.scale=_.Scale.HIDDEN,e.isHidden=!0;var s=t.getStylesForTransition(e,_.Css.HIDDEN.before);s.transitionDelay=t._getStaggerAmount(i)+"ms",t._queue.push({item:e,styles:s,callback:n}),i+=1})}},{key:"_handleResize",value:function(){this.isEnabled&&!this.isDestroyed&&this.update()}},{key:"getStylesForTransition",value:function(t,e){var i=Object.assign({},e);if(this.options.useTransforms){var n=this.options.roundTransforms?Math.round(t.point.x):t.point.x,s=this.options.roundTransforms?Math.round(t.point.y):t.point.y;i.transform="translate(".concat(n,"px, ").concat(s,"px) scale(").concat(t.scale,")")}else i.left=t.point.x+"px",i.top=t.point.y+"px";return i}},{key:"_whenTransitionDone",value:function(t,e,i){var n=D(t,function(t){e(),i(null,t)});this._transitions.push(n)}},{key:"_getTransitionFunction",value:function(t){var e=this;return function(i){t.item.applyCss(t.styles),e._whenTransitionDone(t.item.element,t.callback,i)}}},{key:"_processQueue",value:function(){this.isTransitioning&&this._cancelMovement();var t=this.options.speed>0,e=this._queue.length>0;e&&t&&this.isInitialized?this._startTransitions(this._queue):e?(this._styleImmediately(this._queue),this._dispatch(r.EventType.LAYOUT)):this._dispatch(r.EventType.LAYOUT),this._queue.length=0}},{key:"_startTransitions",value:function(t){var e=this;this.isTransitioning=!0,function(t,e,i){i||("function"==typeof e?(i=e,e=null):i=d);var n=t&&t.length;if(!n)return i(null,[]);var s=!1,o=new Array(n);function r(t){return function(e,r){if(!s){if(e)return i(e,o),void(s=!0);o[t]=r,--n||i(null,o)}}}t.forEach(e?function(t,i){t.call(e,r(i))}:function(t,e){t(r(e))})}(t.map(function(t){return e._getTransitionFunction(t)}),this._movementFinished.bind(this))}},{key:"_cancelMovement",value:function(){this._transitions.forEach(L),this._transitions.length=0,this.isTransitioning=!1}},{key:"_styleImmediately",value:function(t){if(t.length){var e=t.map(function(t){return t.item.element});r._skipTransitions(e,function(){t.forEach(function(t){t.item.applyCss(t.styles),t.callback()})})}}},{key:"_movementFinished",value:function(){this._transitions.length=0,this.isTransitioning=!1,this._dispatch(r.EventType.LAYOUT)}},{key:"filter",value:function(t,e){this.isEnabled&&((!t||t&&0===t.length)&&(t=r.ALL_ITEMS),this._filter(t),this._shrink(),this._updateItemCount(),this.sort(e))}},{key:"sort",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.lastSort;if(this.isEnabled){this._resetCols();var e=T(this._getFilteredItems(),t);this._layout(e),this._processQueue(),this._setContainerSize(),this.lastSort=t}}},{key:"update",value:function(){var t=arguments.length>0&&void 0!==arguments[0]&&arguments[0];this.isEnabled&&(t||this._setColumns(),this.sort())}},{key:"layout",value:function(){this.update(!0)}},{key:"add",value:function(t){var e=this,i=O(t).map(function(t){return new _(t)});this._initItems(i),this._resetCols();var n=T(this._mergeNewItems(i),this.lastSort),s=this._filter(this.lastFilter,n),o=function(t){return i.includes(t)},r=function(t){t.scale=_.Scale.HIDDEN,t.isHidden=!0,t.applyCss(_.Css.HIDDEN.before),t.applyCss(_.Css.HIDDEN.after)},l=this._getNextPositions(s.visible);s.visible.forEach(function(t,i){o(t)&&(t.point=l[i],r(t),t.applyCss(e.getStylesForTransition(t,{})))}),s.hidden.forEach(function(t){o(t)&&r(t)}),this.element.offsetWidth,this.setItemTransitions(i),this.items=this._mergeNewItems(i),this.filter(this.lastFilter)}},{key:"disable",value:function(){this.isEnabled=!1}},{key:"enable",value:function(){var t=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];this.isEnabled=!0,t&&this.update()}},{key:"remove",value:function(t){var e=this;if(t.length){var i=O(t),n=i.map(function(t){return e.getItemByElement(t)}).filter(function(t){return!!t});this._toggleFilterClasses({visible:[],hidden:n}),this._shrink(n),this.sort(),this.items=this.items.filter(function(t){return!n.includes(t)}),this._updateItemCount(),this.once(r.EventType.LAYOUT,function(){e._disposeItems(n),i.forEach(function(t){t.parentNode.removeChild(t)}),e._dispatch(r.EventType.REMOVED,{collection:i})})}}},{key:"getItemByElement",value:function(t){return this.items.find(function(e){return e.element===t})}},{key:"resetItems",value:function(){var t=this;this._disposeItems(this.items),this.isInitialized=!1,this.items=this._getItems(),this._initItems(this.items),this.once(r.EventType.LAYOUT,function(){t.setItemTransitions(t.items),t.isInitialized=!0}),this.filter(this.lastFilter)}},{key:"destroy",value:function(){this._cancelMovement(),window.removeEventListener("resize",this._onResize),this.element.classList.remove("shuffle"),this.element.removeAttribute("style"),this._disposeItems(this.items),this.items.length=0,this._transitions.length=0,this.options.sizer=null,this.element=null,this.isDestroyed=!0,this.isEnabled=!1}}],[{key:"getSize",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],i=window.getComputedStyle(t,null),n=b(t,"width",i),s=b(t,"height",i);e&&(n+=b(t,"marginLeft",i)+b(t,"marginRight",i),s+=b(t,"marginTop",i)+b(t,"marginBottom",i));return{width:n,height:s}}},{key:"_skipTransitions",value:function(t,e){var i=t.map(function(t){var e=t.style,i=e.transitionDuration,n=e.transitionDelay;return e.transitionDuration="0ms",e.transitionDelay="0ms",{duration:i,delay:n}});e(),t[0].offsetWidth,t.forEach(function(t,e){t.style.transitionDuration=i[e].duration,t.style.transitionDelay=i[e].delay})}}]),r}();return H.ShuffleItem=_,H.ALL_ITEMS="all",H.FILTER_ATTRIBUTE_KEY="groups",H.EventType={LAYOUT:"shuffle:layout",REMOVED:"shuffle:removed"},H.Classes=y,H.FilterMode={ANY:"any",ALL:"all"},H.options={group:H.ALL_ITEMS,speed:250,easing:"cubic-bezier(0.4, 0.0, 0.2, 1)",itemSelector:"*",sizer:null,gutterWidth:0,columnWidth:0,delimiter:null,buffer:0,columnThreshold:.01,initialSort:null,throttle:c,throttleTime:300,staggerAmount:15,staggerAmountMax:150,useTransforms:!0,filterMode:H.FilterMode.ANY,isCentered:!1,roundTransforms:!0},H.Point=p,H.Rect=v,H.__sorter=T,H.__getColumnSpan=M,H.__getAvailablePositions=A,H.__getShortColumn=F,H.__getCenteredPositions=x,H});
|
2 |
-
//# sourceMappingURL=shuffle.min.js.map
|
|
|
|
resources/js/whitelabel.js
DELETED
@@ -1,8 +0,0 @@
|
|
1 |
-
var iCWP_WPSF_WhiteLabel = new function () {
|
2 |
-
this.initialise = function () {
|
3 |
-
jQuery( document ).ready( function () {
|
4 |
-
jQuery( 'select#plugin option[value="%s"]' ).remove();
|
5 |
-
} );
|
6 |
-
};
|
7 |
-
}();
|
8 |
-
iCWP_WPSF_WhiteLabel.initialise();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resources/js/wizard.js
DELETED
File without changes
|
src/config/feature-audit_trail.php
CHANGED
@@ -19,8 +19,7 @@
|
|
19 |
"menu_items": [
|
20 |
{
|
21 |
"title": "Audit Trail",
|
22 |
-
"slug": "audit-redirect"
|
23 |
-
"callback": ""
|
24 |
}
|
25 |
],
|
26 |
"custom_redirects": [
|
@@ -164,7 +163,22 @@
|
|
164 |
],
|
165 |
"definitions": {
|
166 |
"db_classes": {
|
167 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
168 |
},
|
169 |
"audit_trail_free_max_entries": 100,
|
170 |
"audit_trail_table_name": "audit_trail",
|
@@ -175,9 +189,7 @@
|
|
175 |
"context": "varchar(32) NOT NULL DEFAULT 'none' COMMENT 'Audit Context'",
|
176 |
"event": "varchar(50) NOT NULL DEFAULT 'none' COMMENT 'Specific Audit Event'",
|
177 |
"category": "int(3) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Severity'",
|
178 |
-
"message": "text COMMENT 'Audit Event Description'",
|
179 |
"meta": "text COMMENT 'Audit Event Data'",
|
180 |
-
"immutable": "tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'May Be Deleted'",
|
181 |
"count": "SMALLINT(5) UNSIGNED NOT NULL DEFAULT 1 COMMENT 'Repeat Count'"
|
182 |
},
|
183 |
"audittrail_table_timestamp_columns": {
|
19 |
"menu_items": [
|
20 |
{
|
21 |
"title": "Audit Trail",
|
22 |
+
"slug": "audit-redirect"
|
|
|
23 |
}
|
24 |
],
|
25 |
"custom_redirects": [
|
163 |
],
|
164 |
"definitions": {
|
165 |
"db_classes": {
|
166 |
+
"audit_trail": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\AuditTrail\\Handler",
|
167 |
+
"audit": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\AuditTrail\\Handler"
|
168 |
+
},
|
169 |
+
"db_table_audit_trail": {
|
170 |
+
"slug": "audit_trail",
|
171 |
+
"has_updated_at": true,
|
172 |
+
"cols_custom": {
|
173 |
+
"rid": "varchar(10) NOT NULL DEFAULT '' COMMENT 'Request ID'",
|
174 |
+
"ip": "varchar(40) NOT NULL DEFAULT 0 COMMENT 'Visitor IP Address'",
|
175 |
+
"wp_username": "varchar(255) NOT NULL DEFAULT '-' COMMENT 'WP User'",
|
176 |
+
"context": "varchar(32) NOT NULL DEFAULT 'none' COMMENT 'Audit Context'",
|
177 |
+
"event": "varchar(50) NOT NULL DEFAULT 'none' COMMENT 'Specific Audit Event'",
|
178 |
+
"category": "int(3) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Severity'",
|
179 |
+
"meta": "text COMMENT 'Audit Event Data'",
|
180 |
+
"count": "SMALLINT(5) UNSIGNED NOT NULL DEFAULT 1 COMMENT 'Repeat Count'"
|
181 |
+
}
|
182 |
},
|
183 |
"audit_trail_free_max_entries": 100,
|
184 |
"audit_trail_table_name": "audit_trail",
|
189 |
"context": "varchar(32) NOT NULL DEFAULT 'none' COMMENT 'Audit Context'",
|
190 |
"event": "varchar(50) NOT NULL DEFAULT 'none' COMMENT 'Specific Audit Event'",
|
191 |
"category": "int(3) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Severity'",
|
|
|
192 |
"meta": "text COMMENT 'Audit Event Data'",
|
|
|
193 |
"count": "SMALLINT(5) UNSIGNED NOT NULL DEFAULT 1 COMMENT 'Repeat Count'"
|
194 |
},
|
195 |
"audittrail_table_timestamp_columns": {
|
src/config/feature-comments_filter.php
CHANGED
@@ -119,6 +119,46 @@
|
|
119 |
"summary": "Don't Scan Comments For Users With The Following Roles",
|
120 |
"description": "Shield doesn't normally scan comments from logged-in or registered users. Specify user roles here that shouldn't be scanned."
|
121 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
122 |
{
|
123 |
"key": "google_recaptcha_style_comments",
|
124 |
"section": "section_bot_comment_spam_protection_filter",
|
@@ -163,35 +203,6 @@
|
|
163 |
"summary": "Block Bot Comment SPAM",
|
164 |
"description": "Taking the lead from the original GASP plugin for WordPress, we have extended it to include advanced spam-bot protection."
|
165 |
},
|
166 |
-
{
|
167 |
-
"key": "comments_default_action_spam_bot",
|
168 |
-
"section": "section_bot_comment_spam_protection_filter",
|
169 |
-
"default": "spam",
|
170 |
-
"type": "select",
|
171 |
-
"value_options": [
|
172 |
-
{
|
173 |
-
"value_key": "0",
|
174 |
-
"text": "Move To Pending Moderation"
|
175 |
-
},
|
176 |
-
{
|
177 |
-
"value_key": "spam",
|
178 |
-
"text": "Move To SPAM"
|
179 |
-
},
|
180 |
-
{
|
181 |
-
"value_key": "trash",
|
182 |
-
"text": "Move To Trash"
|
183 |
-
},
|
184 |
-
{
|
185 |
-
"value_key": "reject",
|
186 |
-
"text": "Block And Redirect"
|
187 |
-
}
|
188 |
-
],
|
189 |
-
"link_info": "https://shsec.io/6j",
|
190 |
-
"link_blog": "",
|
191 |
-
"name": "SPAM Action",
|
192 |
-
"summary": "How To Categorise Comments When Identified To Be SPAM",
|
193 |
-
"description": "When a comment is detected as being SPAM from an automatic bot, the comment will be categorised based on this setting."
|
194 |
-
},
|
195 |
{
|
196 |
"key": "enable_comments_human_spam_filter",
|
197 |
"section": "section_human_spam_filter",
|
@@ -303,6 +314,10 @@
|
|
303 |
"comments_expire": 1800,
|
304 |
"url_spam_blacklist_terms": "https://raw.githubusercontent.com/splorp/wordpress-comment-blacklist/master/blacklist.txt",
|
305 |
"events": {
|
|
|
|
|
|
|
|
|
306 |
"spam_block_bot": {
|
307 |
"recent": true,
|
308 |
"offense": true
|
119 |
"summary": "Don't Scan Comments For Users With The Following Roles",
|
120 |
"description": "Shield doesn't normally scan comments from logged-in or registered users. Specify user roles here that shouldn't be scanned."
|
121 |
},
|
122 |
+
{
|
123 |
+
"key": "enable_antibot_check",
|
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",
|
131 |
+
"description": "Use Shield's AntiBot Detection Engine In-Place of GASP Bot checking."
|
132 |
+
},
|
133 |
+
{
|
134 |
+
"key": "comments_default_action_spam_bot",
|
135 |
+
"section": "section_bot_comment_spam_protection_filter",
|
136 |
+
"default": "spam",
|
137 |
+
"type": "select",
|
138 |
+
"value_options": [
|
139 |
+
{
|
140 |
+
"value_key": "0",
|
141 |
+
"text": "Move To Pending Moderation"
|
142 |
+
},
|
143 |
+
{
|
144 |
+
"value_key": "spam",
|
145 |
+
"text": "Move To SPAM"
|
146 |
+
},
|
147 |
+
{
|
148 |
+
"value_key": "trash",
|
149 |
+
"text": "Move To Trash"
|
150 |
+
},
|
151 |
+
{
|
152 |
+
"value_key": "reject",
|
153 |
+
"text": "Block And Redirect"
|
154 |
+
}
|
155 |
+
],
|
156 |
+
"link_info": "https://shsec.io/6j",
|
157 |
+
"link_blog": "",
|
158 |
+
"name": "SPAM Action",
|
159 |
+
"summary": "How To Categorise Comments When Identified To Be SPAM",
|
160 |
+
"description": "When a comment is detected as being SPAM from an automatic bot, the comment will be categorised based on this setting."
|
161 |
+
},
|
162 |
{
|
163 |
"key": "google_recaptcha_style_comments",
|
164 |
"section": "section_bot_comment_spam_protection_filter",
|
203 |
"summary": "Block Bot Comment SPAM",
|
204 |
"description": "Taking the lead from the original GASP plugin for WordPress, we have extended it to include advanced spam-bot protection."
|
205 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
206 |
{
|
207 |
"key": "enable_comments_human_spam_filter",
|
208 |
"section": "section_human_spam_filter",
|
314 |
"comments_expire": 1800,
|
315 |
"url_spam_blacklist_terms": "https://raw.githubusercontent.com/splorp/wordpress-comment-blacklist/master/blacklist.txt",
|
316 |
"events": {
|
317 |
+
"spam_block_antibot": {
|
318 |
+
"recent": true,
|
319 |
+
"offense": true
|
320 |
+
},
|
321 |
"spam_block_bot": {
|
322 |
"recent": true,
|
323 |
"offense": true
|
src/config/feature-events.php
CHANGED
@@ -49,6 +49,13 @@
|
|
49 |
"db_classes": {
|
50 |
"events": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Events\\Handler"
|
51 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
"events_table_name": "events",
|
53 |
"events_table_columns": {
|
54 |
"event": "varchar(50) NOT NULL DEFAULT 'none' COMMENT 'Event ID'",
|
49 |
"db_classes": {
|
50 |
"events": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Events\\Handler"
|
51 |
},
|
52 |
+
"db_table_events": {
|
53 |
+
"slug": "events",
|
54 |
+
"cols_custom": {
|
55 |
+
"event": "varchar(50) NOT NULL DEFAULT 'none' COMMENT 'Event ID'",
|
56 |
+
"count": "int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Total'"
|
57 |
+
}
|
58 |
+
},
|
59 |
"events_table_name": "events",
|
60 |
"events_table_columns": {
|
61 |
"event": "varchar(50) NOT NULL DEFAULT 'none' COMMENT 'Event ID'",
|
src/config/feature-firewall.php
CHANGED
@@ -318,6 +318,8 @@
|
|
318 |
"icwp_wpsf_new_u2f_response",
|
319 |
"icwp_wpsf_u2f_otp",
|
320 |
"appId",
|
|
|
|
|
321 |
"aioseo-post-settings"
|
322 |
]
|
323 |
},
|
318 |
"icwp_wpsf_new_u2f_response",
|
319 |
"icwp_wpsf_u2f_otp",
|
320 |
"appId",
|
321 |
+
"/^et_.*/",
|
322 |
+
"ping_sites",
|
323 |
"aioseo-post-settings"
|
324 |
]
|
325 |
},
|
src/config/feature-hack_protect.php
CHANGED
@@ -22,8 +22,7 @@
|
|
22 |
"menu_items": [
|
23 |
{
|
24 |
"title": "Scans",
|
25 |
-
"slug": "scans-redirect"
|
26 |
-
"callback": ""
|
27 |
}
|
28 |
],
|
29 |
"custom_redirects": [
|
@@ -396,14 +395,65 @@
|
|
396 |
"tracking_exclude": true,
|
397 |
"type": "array",
|
398 |
"default": []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
399 |
}
|
400 |
],
|
401 |
"definitions": {
|
402 |
"db_classes": {
|
403 |
"file_protect": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\FileLocker\\Handler",
|
404 |
-
"
|
|
|
405 |
"scanq": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\ScanQueue\\Handler"
|
406 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
407 |
"all_scan_slugs": [
|
408 |
"apc",
|
409 |
"mal",
|
@@ -424,28 +474,6 @@
|
|
424 |
"notified_at": "int(15) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'TS Notification Sent'",
|
425 |
"updated_at": "int(15) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'TS Updated'"
|
426 |
},
|
427 |
-
"table_name_scanner": "scanner",
|
428 |
-
"table_columns_scanner": {
|
429 |
-
"hash": "varchar(32) NOT NULL DEFAULT '' COMMENT 'Unique Item Hash'",
|
430 |
-
"meta": "text COMMENT 'Relevant Item Data'",
|
431 |
-
"scan": "varchar(10) NOT NULL DEFAULT 0 COMMENT 'Scan Type'",
|
432 |
-
"severity": "int(3) NOT NULL DEFAULT 1 COMMENT 'Severity'"
|
433 |
-
},
|
434 |
-
"scanresults_table_timestamp_columns": {
|
435 |
-
"ignored_at": "Scan Result Ignored",
|
436 |
-
"notified_at": "Scan Notifiation Sent"
|
437 |
-
},
|
438 |
-
"table_name_scanqueue": "scanq",
|
439 |
-
"table_columns_scanqueue": {
|
440 |
-
"scan": "varchar(3) NOT NULL DEFAULT 0 COMMENT 'Scan Slug'",
|
441 |
-
"items": "text COMMENT 'Array of scan items'",
|
442 |
-
"results": "text COMMENT 'Array of results'",
|
443 |
-
"meta": "text COMMENT 'Meta Data'"
|
444 |
-
},
|
445 |
-
"scanqueue_table_timestamp_columns": {
|
446 |
-
"started_at": "Scan Started",
|
447 |
-
"finished_at": "Scan Completed"
|
448 |
-
},
|
449 |
"url_mal_sigs_simple": "https://raw.githubusercontent.com/scr34m/php-malware-scanner/master/definitions/patterns_raw.txt",
|
450 |
"url_mal_sigs_regex": "https://raw.githubusercontent.com/scr34m/php-malware-scanner/master/definitions/patterns_re.txt",
|
451 |
"malware_whitelist_paths": [
|
22 |
"menu_items": [
|
23 |
{
|
24 |
"title": "Scans",
|
25 |
+
"slug": "scans-redirect"
|
|
|
26 |
}
|
27 |
],
|
28 |
"custom_redirects": [
|
395 |
"tracking_exclude": true,
|
396 |
"type": "array",
|
397 |
"default": []
|
398 |
+
},
|
399 |
+
{
|
400 |
+
"key": "filelocker_state",
|
401 |
+
"section": "section_non_ui",
|
402 |
+
"transferable": false,
|
403 |
+
"tracking_exclude": true,
|
404 |
+
"type": "array",
|
405 |
+
"default": []
|
406 |
}
|
407 |
],
|
408 |
"definitions": {
|
409 |
"db_classes": {
|
410 |
"file_protect": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\FileLocker\\Handler",
|
411 |
+
"filelocker": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\FileLocker\\Handler",
|
412 |
+
"scanner": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Scanner\\Handler",
|
413 |
"scanq": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\ScanQueue\\Handler"
|
414 |
},
|
415 |
+
"db_table_filelocker": {
|
416 |
+
"slug": "filelocker",
|
417 |
+
"has_updated_at": true,
|
418 |
+
"cols_custom": {
|
419 |
+
"file": "varchar(256) NOT NULL COMMENT 'File Path relative to ABSPATH'",
|
420 |
+
"hash_original": "varchar(40) NOT NULL COMMENT 'SHA1 File Hash Original'",
|
421 |
+
"hash_current": "varchar(40) NOT NULL COMMENT 'SHA1 File Hash Current'",
|
422 |
+
"content": "MEDIUMBLOB COMMENT 'Content'",
|
423 |
+
"public_key_id": "TINYINT(2) UNSIGNED NOT NULL COMMENT 'Public Key ID'"
|
424 |
+
},
|
425 |
+
"cols_timestamps": {
|
426 |
+
"detected_at": "Change Last Detected",
|
427 |
+
"reverted_at": "Reverted To Backup",
|
428 |
+
"notified_at": "Notification Sent"
|
429 |
+
}
|
430 |
+
},
|
431 |
+
"db_table_scanner": {
|
432 |
+
"slug": "scanner",
|
433 |
+
"cols_custom": {
|
434 |
+
"hash": "varchar(32) NOT NULL DEFAULT '' COMMENT 'Unique Item Hash'",
|
435 |
+
"meta": "text COMMENT 'Relevant Item Data'",
|
436 |
+
"scan": "varchar(10) NOT NULL DEFAULT 0 COMMENT 'Scan Type'",
|
437 |
+
"severity": "int(3) NOT NULL DEFAULT 1 COMMENT 'Severity'"
|
438 |
+
},
|
439 |
+
"cols_timestamps": {
|
440 |
+
"ignored_at": "Scan Result Ignored",
|
441 |
+
"notified_at": "Scan Notifiation Sent"
|
442 |
+
}
|
443 |
+
},
|
444 |
+
"db_table_scanq": {
|
445 |
+
"slug": "scanq",
|
446 |
+
"cols_custom": {
|
447 |
+
"scan": "varchar(3) NOT NULL DEFAULT '' COMMENT 'Scan Slug'",
|
448 |
+
"items": "text COMMENT 'Array of scan items'",
|
449 |
+
"results": "text COMMENT 'Array of results'",
|
450 |
+
"meta": "text COMMENT 'Meta Data'"
|
451 |
+
},
|
452 |
+
"cols_timestamps": {
|
453 |
+
"started_at": "Scan Started",
|
454 |
+
"finished_at": "Scan Completed"
|
455 |
+
}
|
456 |
+
},
|
457 |
"all_scan_slugs": [
|
458 |
"apc",
|
459 |
"mal",
|
474 |
"notified_at": "int(15) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'TS Notification Sent'",
|
475 |
"updated_at": "int(15) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'TS Updated'"
|
476 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
477 |
"url_mal_sigs_simple": "https://raw.githubusercontent.com/scr34m/php-malware-scanner/master/definitions/patterns_raw.txt",
|
478 |
"url_mal_sigs_regex": "https://raw.githubusercontent.com/scr34m/php-malware-scanner/master/definitions/patterns_re.txt",
|
479 |
"malware_whitelist_paths": [
|
src/config/feature-integrations.php
CHANGED
@@ -27,6 +27,11 @@
|
|
27 |
"title": "Integrations",
|
28 |
"title_short": "Integrations"
|
29 |
},
|
|
|
|
|
|
|
|
|
|
|
30 |
{
|
31 |
"slug": "section_non_ui",
|
32 |
"hidden": true
|
@@ -43,10 +48,87 @@
|
|
43 |
"name": "Enable MainWP",
|
44 |
"summary": "Enable The Built-In MainWP Extension",
|
45 |
"description": "This option will enable Shield's built-in MainWP extension for both server and client."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
}
|
47 |
],
|
48 |
"definitions": {
|
49 |
"events": {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
}
|
51 |
}
|
52 |
}
|
27 |
"title": "Integrations",
|
28 |
"title_short": "Integrations"
|
29 |
},
|
30 |
+
{
|
31 |
+
"slug": "section_spam",
|
32 |
+
"title": "SPAM Detection",
|
33 |
+
"title_short": "SPAM Detection"
|
34 |
+
},
|
35 |
{
|
36 |
"slug": "section_non_ui",
|
37 |
"hidden": true
|
48 |
"name": "Enable MainWP",
|
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",
|
67 |
+
"premium": true,
|
68 |
+
"advanced": true,
|
69 |
+
"type": "multiple_select",
|
70 |
+
"default": [],
|
71 |
+
"value_options": [
|
72 |
+
{
|
73 |
+
"value_key": "contactform7",
|
74 |
+
"text": "Contact Form 7"
|
75 |
+
},
|
76 |
+
{
|
77 |
+
"value_key": "elementorpro",
|
78 |
+
"text": "Elementor Pro"
|
79 |
+
},
|
80 |
+
{
|
81 |
+
"value_key": "fluentforms",
|
82 |
+
"text": "Fluent Forms"
|
83 |
+
},
|
84 |
+
{
|
85 |
+
"value_key": "formidableforms",
|
86 |
+
"text": "Formidable Forms"
|
87 |
+
},
|
88 |
+
{
|
89 |
+
"value_key": "forminator",
|
90 |
+
"text": "Forminator"
|
91 |
+
},
|
92 |
+
{
|
93 |
+
"value_key": "gravityforms",
|
94 |
+
"text": "Gravity Forms"
|
95 |
+
},
|
96 |
+
{
|
97 |
+
"value_key": "kaliforms",
|
98 |
+
"text": "Kali Forms"
|
99 |
+
},
|
100 |
+
{
|
101 |
+
"value_key": "ninjaforms",
|
102 |
+
"text": "Ninja Forms"
|
103 |
+
},
|
104 |
+
{
|
105 |
+
"value_key": "wpforo",
|
106 |
+
"text": "wpForo"
|
107 |
+
},
|
108 |
+
{
|
109 |
+
"value_key": "wpforms",
|
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": {
|
121 |
"events": {
|
122 |
+
"spam_form_pass": {
|
123 |
+
"stat": true,
|
124 |
+
"audit": true,
|
125 |
+
"offense": false
|
126 |
+
},
|
127 |
+
"spam_form_fail": {
|
128 |
+
"stat": true,
|
129 |
+
"audit": true,
|
130 |
+
"offense": false
|
131 |
+
}
|
132 |
}
|
133 |
}
|
134 |
}
|
src/config/feature-ips.php
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
{
|
2 |
-
"slug":
|
3 |
-
"properties":
|
4 |
"slug": "ips",
|
5 |
"name": "Block Bad IPs/Visitors",
|
6 |
"sidebar_name": "IP Blocking",
|
@@ -19,8 +19,7 @@
|
|
19 |
"menu_items": [
|
20 |
{
|
21 |
"title": "IP Lists",
|
22 |
-
"slug": "ips-redirect"
|
23 |
-
"callback": ""
|
24 |
}
|
25 |
],
|
26 |
"custom_redirects": [
|
@@ -32,7 +31,7 @@
|
|
32 |
}
|
33 |
}
|
34 |
],
|
35 |
-
"admin_notices":
|
36 |
"visitor-whitelisted": {
|
37 |
"id": "visitor-whitelisted",
|
38 |
"schedule": "conditions",
|
@@ -41,7 +40,7 @@
|
|
41 |
"type": "info"
|
42 |
}
|
43 |
},
|
44 |
-
"requirements":
|
45 |
"php": {
|
46 |
"functions": [
|
47 |
"filter_var"
|
@@ -55,7 +54,7 @@
|
|
55 |
]
|
56 |
}
|
57 |
},
|
58 |
-
"sections":
|
59 |
{
|
60 |
"slug": "section_auto_black_list",
|
61 |
"primary": true,
|
@@ -66,6 +65,13 @@
|
|
66 |
"Recommendation - Keep the Automatic IP Black List feature turned on."
|
67 |
]
|
68 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
{
|
70 |
"slug": "section_logins",
|
71 |
"title": "Capture Login Bots",
|
@@ -123,7 +129,7 @@
|
|
123 |
"hidden": true
|
124 |
}
|
125 |
],
|
126 |
-
"options":
|
127 |
{
|
128 |
"key": "enable_ips",
|
129 |
"section": "section_enable_plugin_feature_ips",
|
@@ -136,6 +142,19 @@
|
|
136 |
"summary": "Enable (or Disable) The IP Manager module",
|
137 |
"description": "Un-Checking this option will completely disable the IP Manager module"
|
138 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
139 |
{
|
140 |
"key": "transgression_limit",
|
141 |
"section": "section_auto_black_list",
|
@@ -332,6 +351,40 @@
|
|
332 |
"summary": "Identify A Bot When It Accesses XML-RPC",
|
333 |
"description": "If you don't use XML-RPC, why would anyone access it?"
|
334 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
335 |
{
|
336 |
"key": "track_loginfailed",
|
337 |
"section": "section_logins",
|
@@ -495,9 +548,11 @@
|
|
495 |
"default": []
|
496 |
}
|
497 |
],
|
498 |
-
"definitions":
|
499 |
"db_classes": {
|
500 |
-
"
|
|
|
|
|
501 |
},
|
502 |
"ip_lists_table_name": "ip_lists",
|
503 |
"ip_list_table_columns": {
|
@@ -512,6 +567,55 @@
|
|
512 |
"last_access_at": "Last Access By IP",
|
513 |
"blocked_at": "IP Blocked"
|
514 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
515 |
"events": {
|
516 |
"custom_offense": {
|
517 |
"cat": 3,
|
@@ -526,9 +630,25 @@
|
|
526 |
"ip_blocked": {
|
527 |
"cat": 2
|
528 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
529 |
"ip_unblock_flag": {
|
530 |
"cat": 1
|
531 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
532 |
"bottrack_404": {
|
533 |
"cat": 2,
|
534 |
"offense": true
|
@@ -556,6 +676,19 @@
|
|
556 |
"bottrack_xmlrpc": {
|
557 |
"cat": 2,
|
558 |
"offense": true
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
559 |
}
|
560 |
}
|
561 |
}
|
1 |
{
|
2 |
+
"slug": "ips",
|
3 |
+
"properties": {
|
4 |
"slug": "ips",
|
5 |
"name": "Block Bad IPs/Visitors",
|
6 |
"sidebar_name": "IP Blocking",
|
19 |
"menu_items": [
|
20 |
{
|
21 |
"title": "IP Lists",
|
22 |
+
"slug": "ips-redirect"
|
|
|
23 |
}
|
24 |
],
|
25 |
"custom_redirects": [
|
31 |
}
|
32 |
}
|
33 |
],
|
34 |
+
"admin_notices": {
|
35 |
"visitor-whitelisted": {
|
36 |
"id": "visitor-whitelisted",
|
37 |
"schedule": "conditions",
|
40 |
"type": "info"
|
41 |
}
|
42 |
},
|
43 |
+
"requirements": {
|
44 |
"php": {
|
45 |
"functions": [
|
46 |
"filter_var"
|
54 |
]
|
55 |
}
|
56 |
},
|
57 |
+
"sections": [
|
58 |
{
|
59 |
"slug": "section_auto_black_list",
|
60 |
"primary": true,
|
65 |
"Recommendation - Keep the Automatic IP Black List feature turned on."
|
66 |
]
|
67 |
},
|
68 |
+
{
|
69 |
+
"slug": "section_antibot",
|
70 |
+
"title": "AntiBot System",
|
71 |
+
"title_short": "AntiBot System",
|
72 |
+
"summary": [
|
73 |
+
]
|
74 |
+
},
|
75 |
{
|
76 |
"slug": "section_logins",
|
77 |
"title": "Capture Login Bots",
|
129 |
"hidden": true
|
130 |
}
|
131 |
],
|
132 |
+
"options": [
|
133 |
{
|
134 |
"key": "enable_ips",
|
135 |
"section": "section_enable_plugin_feature_ips",
|
142 |
"summary": "Enable (or Disable) The IP Manager module",
|
143 |
"description": "Un-Checking this option will completely disable the IP Manager module"
|
144 |
},
|
145 |
+
{
|
146 |
+
"key": "antibot_minimum",
|
147 |
+
"section": "section_antibot",
|
148 |
+
"default": 35,
|
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)."
|
157 |
+
},
|
158 |
{
|
159 |
"key": "transgression_limit",
|
160 |
"section": "section_auto_black_list",
|
351 |
"summary": "Identify A Bot When It Accesses XML-RPC",
|
352 |
"description": "If you don't use XML-RPC, why would anyone access it?"
|
353 |
},
|
354 |
+
{
|
355 |
+
"key": "track_invalidscript",
|
356 |
+
"section": "section_probes",
|
357 |
+
"premium": true,
|
358 |
+
"default": "log",
|
359 |
+
"type": "select",
|
360 |
+
"value_options": [
|
361 |
+
{
|
362 |
+
"value_key": "disabled",
|
363 |
+
"text": "Disabled"
|
364 |
+
},
|
365 |
+
{
|
366 |
+
"value_key": "log",
|
367 |
+
"text": "Audit Log Only"
|
368 |
+
},
|
369 |
+
{
|
370 |
+
"value_key": "transgression-single",
|
371 |
+
"text": "Increment Offense Counter"
|
372 |
+
},
|
373 |
+
{
|
374 |
+
"value_key": "transgression-double",
|
375 |
+
"text": "Double-Increment Offense Counter"
|
376 |
+
},
|
377 |
+
{
|
378 |
+
"value_key": "block",
|
379 |
+
"text": "Immediate Block"
|
380 |
+
}
|
381 |
+
],
|
382 |
+
"link_info": "https://shsec.io/fo",
|
383 |
+
"link_blog": "https://shsec.io/f7",
|
384 |
+
"name": "Invalid Script Load",
|
385 |
+
"summary": "Identify A Bot Attempts To Load WordPress In A Non-Standard Way",
|
386 |
+
"description": "WordPress should only be loaded in a limited number of ways."
|
387 |
+
},
|
388 |
{
|
389 |
"key": "track_loginfailed",
|
390 |
"section": "section_logins",
|
548 |
"default": []
|
549 |
}
|
550 |
],
|
551 |
+
"definitions": {
|
552 |
"db_classes": {
|
553 |
+
"botsignals": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\BotSignals\\Handler",
|
554 |
+
"ip_lists": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\IPs\\Handler",
|
555 |
+
"ips": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\IPs\\Handler"
|
556 |
},
|
557 |
"ip_lists_table_name": "ip_lists",
|
558 |
"ip_list_table_columns": {
|
567 |
"last_access_at": "Last Access By IP",
|
568 |
"blocked_at": "IP Blocked"
|
569 |
},
|
570 |
+
"db_table_ip_lists": {
|
571 |
+
"slug": "ip_lists",
|
572 |
+
"cols_custom": {
|
573 |
+
"ip": "varchar(60) NOT NULL DEFAULT '' COMMENT 'Human readable IP address or range'",
|
574 |
+
"label": "varchar(255) NOT NULL DEFAULT '' COMMENT 'Description'",
|
575 |
+
"list": "varchar(4) NOT NULL DEFAULT '' COMMENT 'Block or Bypass'",
|
576 |
+
"ip6": "tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Is IPv6'",
|
577 |
+
"is_range": "tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Is Range'",
|
578 |
+
"transgressions": "int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Total Offenses'"
|
579 |
+
},
|
580 |
+
"cols_timestamps": {
|
581 |
+
"last_access_at": "Last Access By IP",
|
582 |
+
"blocked_at": "IP Blocked"
|
583 |
+
}
|
584 |
+
},
|
585 |
+
"db_table_botsignals": {
|
586 |
+
"autoexpire": 3,
|
587 |
+
"slug": "botsignals",
|
588 |
+
"col_older_than": "updated_at",
|
589 |
+
"has_updated_at": true,
|
590 |
+
"cols_custom": {
|
591 |
+
"ip": "varbinary(16) DEFAULT NULL COMMENT 'IP Address'"
|
592 |
+
},
|
593 |
+
"cols_timestamps": {
|
594 |
+
"notbot_at": "NotBot",
|
595 |
+
"frontpage_at": "Front Page Loaded",
|
596 |
+
"bt404_at": "BotTrack 404",
|
597 |
+
"btfake_at": "BotTrack FakeWebCrawler",
|
598 |
+
"btcheese_at": "BotTrack LinkCheese",
|
599 |
+
"btloginfail_at": "BotTrack LoginFailed",
|
600 |
+
"btua_at": "BotTrack Useragent Fail",
|
601 |
+
"btxml_at": "BotTrack XMLRPC Access",
|
602 |
+
"btlogininvalid_at": "BotTrack LoginInvalid",
|
603 |
+
"btinvalidscript_at": "BotTrack InvalidScript",
|
604 |
+
"cooldown_at": "Triggered Cooldown",
|
605 |
+
"humanspam_at": "Comment Marked As Human SPAM",
|
606 |
+
"markspam_at": "Mark Comment As SPAM",
|
607 |
+
"unmarkspam_at": "Unmark Comment As SPAM",
|
608 |
+
"captchapass_at": "Captcha Passed",
|
609 |
+
"captchafail_at": "Captcha Failed",
|
610 |
+
"auth_at": "Successful Login",
|
611 |
+
"firewall_at": "Triggered Firewall",
|
612 |
+
"ratelimit_at": "Rate Limit Exceeded",
|
613 |
+
"offense_at": "Last Offense",
|
614 |
+
"blocked_at": "Last Block",
|
615 |
+
"unblocked_at": "Unblocked",
|
616 |
+
"bypass_at": "Bypass"
|
617 |
+
}
|
618 |
+
},
|
619 |
"events": {
|
620 |
"custom_offense": {
|
621 |
"cat": 3,
|
630 |
"ip_blocked": {
|
631 |
"cat": 2
|
632 |
},
|
633 |
+
"ip_unblock": {
|
634 |
+
"offense": false,
|
635 |
+
"audit": false,
|
636 |
+
"stat": false
|
637 |
+
},
|
638 |
+
"ip_bypass": {
|
639 |
+
"offense": false,
|
640 |
+
"audit": false,
|
641 |
+
"stat": false
|
642 |
+
},
|
643 |
"ip_unblock_flag": {
|
644 |
"cat": 1
|
645 |
},
|
646 |
+
"bottrack_notbot": {
|
647 |
+
"cat": 0,
|
648 |
+
"offense": false,
|
649 |
+
"audit": false,
|
650 |
+
"stat": false
|
651 |
+
},
|
652 |
"bottrack_404": {
|
653 |
"cat": 2,
|
654 |
"offense": true
|
676 |
"bottrack_xmlrpc": {
|
677 |
"cat": 2,
|
678 |
"offense": true
|
679 |
+
},
|
680 |
+
"bottrack_invalidscript": {
|
681 |
+
"cat": 2,
|
682 |
+
"offense": true
|
683 |
+
},
|
684 |
+
"comment_markspam": {
|
685 |
+
"cat": 2,
|
686 |
+
"offense": true
|
687 |
+
},
|
688 |
+
"comment_unmarkspam": {
|
689 |
+
"audit": false,
|
690 |
+
"offense": false,
|
691 |
+
"stat": false
|
692 |
}
|
693 |
}
|
694 |
}
|
src/config/feature-license.php
CHANGED
@@ -1,10 +1,10 @@
|
|
1 |
{
|
2 |
-
"slug":
|
3 |
-
"properties":
|
4 |
"slug": "license",
|
5 |
"name": "Pro Security",
|
6 |
-
"menu_title": "
|
7 |
-
"show_module_menu_item":
|
8 |
"highlight_menu_item": true,
|
9 |
"tagline": "The Best In WordPress Security, Only Better.",
|
10 |
"auto_enabled": true,
|
@@ -16,7 +16,7 @@
|
|
16 |
"run_if_verified_bot": true,
|
17 |
"run_if_wpcli": true
|
18 |
},
|
19 |
-
"admin_notices":
|
20 |
"wphashes-token-fail": {
|
21 |
"id": "wphashes-token-fail",
|
22 |
"schedule": "conditions",
|
@@ -26,13 +26,29 @@
|
|
26 |
"type": "error"
|
27 |
}
|
28 |
},
|
29 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
{
|
31 |
"slug": "section_non_ui",
|
32 |
"hidden": true
|
33 |
}
|
34 |
],
|
35 |
-
"options":
|
36 |
{
|
37 |
"key": "license_key",
|
38 |
"section": "section_non_ui",
|
@@ -123,7 +139,7 @@
|
|
123 |
"default": []
|
124 |
}
|
125 |
],
|
126 |
-
"definitions":
|
127 |
"license_store_url_api": "https://api.getshieldsecurity.com/wp-json/odp-eddkeyless/v1",
|
128 |
"keyless_cp": "https://shsec.io/c5",
|
129 |
"license_item_name": "Shield Security Pro",
|
1 |
{
|
2 |
+
"slug": "license",
|
3 |
+
"properties": {
|
4 |
"slug": "license",
|
5 |
"name": "Pro Security",
|
6 |
+
"menu_title": "",
|
7 |
+
"show_module_menu_item": false,
|
8 |
"highlight_menu_item": true,
|
9 |
"tagline": "The Best In WordPress Security, Only Better.",
|
10 |
"auto_enabled": true,
|
16 |
"run_if_verified_bot": true,
|
17 |
"run_if_wpcli": true
|
18 |
},
|
19 |
+
"admin_notices": {
|
20 |
"wphashes-token-fail": {
|
21 |
"id": "wphashes-token-fail",
|
22 |
"schedule": "conditions",
|
26 |
"type": "error"
|
27 |
}
|
28 |
},
|
29 |
+
"menu_items": [
|
30 |
+
{
|
31 |
+
"title": "Go PRO!",
|
32 |
+
"slug": "pro-redirect",
|
33 |
+
"highlight": true
|
34 |
+
}
|
35 |
+
],
|
36 |
+
"custom_redirects": [
|
37 |
+
{
|
38 |
+
"source_mod_page": "pro-redirect",
|
39 |
+
"target_mod_page": "insights",
|
40 |
+
"query_args": {
|
41 |
+
"inav": "license"
|
42 |
+
}
|
43 |
+
}
|
44 |
+
],
|
45 |
+
"sections": [
|
46 |
{
|
47 |
"slug": "section_non_ui",
|
48 |
"hidden": true
|
49 |
}
|
50 |
],
|
51 |
+
"options": [
|
52 |
{
|
53 |
"key": "license_key",
|
54 |
"section": "section_non_ui",
|
139 |
"default": []
|
140 |
}
|
141 |
],
|
142 |
+
"definitions": {
|
143 |
"license_store_url_api": "https://api.getshieldsecurity.com/wp-json/odp-eddkeyless/v1",
|
144 |
"keyless_cp": "https://shsec.io/c5",
|
145 |
"license_item_name": "Shield Security Pro",
|
src/config/feature-login_protect.php
CHANGED
@@ -308,6 +308,17 @@
|
|
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_login_gasp_check",
|
313 |
"section": "section_brute_force_login_protection",
|
@@ -490,15 +501,18 @@
|
|
490 |
"2fa_email_send_fail": {
|
491 |
},
|
492 |
"cooldown_fail": {
|
|
|
493 |
},
|
494 |
"honeypot_fail": {
|
|
|
495 |
},
|
496 |
"botbox_fail": {
|
|
|
497 |
},
|
498 |
"login_block": {
|
499 |
"audit": false,
|
500 |
"recent": true,
|
501 |
-
"offense":
|
502 |
},
|
503 |
"hide_login_url": {
|
504 |
"audit": false
|
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",
|
501 |
"2fa_email_send_fail": {
|
502 |
},
|
503 |
"cooldown_fail": {
|
504 |
+
"offense": true
|
505 |
},
|
506 |
"honeypot_fail": {
|
507 |
+
"offense": true
|
508 |
},
|
509 |
"botbox_fail": {
|
510 |
+
"offense": true
|
511 |
},
|
512 |
"login_block": {
|
513 |
"audit": false,
|
514 |
"recent": true,
|
515 |
+
"offense": false
|
516 |
},
|
517 |
"hide_login_url": {
|
518 |
"audit": false
|
src/config/feature-plugin.php
CHANGED
@@ -529,29 +529,33 @@
|
|
529 |
}
|
530 |
],
|
531 |
"definitions": {
|
532 |
-
"survey_email":
|
533 |
-
"help_video_id":
|
534 |
-
"tracking_cron_handle":
|
535 |
-
"tracking_post_url":
|
536 |
-
"importexport_cron_name":
|
537 |
-
"href_privacy_policy":
|
538 |
-
"db_classes":
|
539 |
"geoip": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\GeoIp\\Handler",
|
540 |
"notes": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\AdminNotes\\Handler"
|
541 |
},
|
542 |
-
"
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
547 |
-
|
|
|
548 |
},
|
549 |
-
"
|
550 |
-
|
551 |
-
"
|
552 |
-
"
|
|
|
|
|
|
|
553 |
},
|
554 |
-
"active_plugin_features":
|
555 |
{
|
556 |
"slug": "insights",
|
557 |
"load_priority": 1,
|
@@ -632,7 +636,7 @@
|
|
632 |
"slug": "email"
|
633 |
}
|
634 |
],
|
635 |
-
"events":
|
636 |
"test_cron_run": {
|
637 |
"audit": false,
|
638 |
"recent": true
|
@@ -664,10 +668,24 @@
|
|
664 |
"audit": false
|
665 |
},
|
666 |
"recaptcha_fail": {
|
|
|
|
|
|
|
|
|
|
|
667 |
"audit": true
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
668 |
}
|
669 |
},
|
670 |
-
"wizards":
|
671 |
"welcome": {
|
672 |
"title": "Getting Started Setup Wizard",
|
673 |
"desc": "An introduction to this security plugin, helping you get setup and started quickly with the core features.",
|
529 |
}
|
530 |
],
|
531 |
"definitions": {
|
532 |
+
"survey_email": "c3VwcG9ydEBvbmVkb2xsYXJwbHVnaW4uY29t",
|
533 |
+
"help_video_id": "",
|
534 |
+
"tracking_cron_handle": "plugin_tracking_cron",
|
535 |
+
"tracking_post_url": "https://tracking.icontrolwp.com/track/plugin/shield",
|
536 |
+
"importexport_cron_name": "autoimport",
|
537 |
+
"href_privacy_policy": "https://shsec.io/wpshieldprivacypolicy",
|
538 |
+
"db_classes": {
|
539 |
"geoip": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\GeoIp\\Handler",
|
540 |
"notes": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\AdminNotes\\Handler"
|
541 |
},
|
542 |
+
"db_table_notes": {
|
543 |
+
"slug": "notes",
|
544 |
+
"has_updated_at": true,
|
545 |
+
"cols_custom": {
|
546 |
+
"wp_username": "varchar(255) NOT NULL DEFAULT 'unknown'",
|
547 |
+
"note": "TEXT"
|
548 |
+
}
|
549 |
},
|
550 |
+
"db_table_geoip": {
|
551 |
+
"autoexpire": 30,
|
552 |
+
"slug": "geoip",
|
553 |
+
"cols_custom": {
|
554 |
+
"ip": "varbinary(16) DEFAULT NULL COMMENT 'IP Address'",
|
555 |
+
"meta": "TEXT"
|
556 |
+
}
|
557 |
},
|
558 |
+
"active_plugin_features": [
|
559 |
{
|
560 |
"slug": "insights",
|
561 |
"load_priority": 1,
|
636 |
"slug": "email"
|
637 |
}
|
638 |
],
|
639 |
+
"events": {
|
640 |
"test_cron_run": {
|
641 |
"audit": false,
|
642 |
"recent": true
|
668 |
"audit": false
|
669 |
},
|
670 |
"recaptcha_fail": {
|
671 |
+
"offense": false,
|
672 |
+
"audit": true
|
673 |
+
},
|
674 |
+
"antibot_pass": {
|
675 |
+
"stat": true,
|
676 |
"audit": true
|
677 |
+
},
|
678 |
+
"antibot_fail": {
|
679 |
+
"stat": true,
|
680 |
+
"audit": true
|
681 |
+
},
|
682 |
+
"frontpage_load": {
|
683 |
+
"offense": false,
|
684 |
+
"stat": false,
|
685 |
+
"audit": false
|
686 |
}
|
687 |
},
|
688 |
+
"wizards": {
|
689 |
"welcome": {
|
690 |
"title": "Getting Started Setup Wizard",
|
691 |
"desc": "An introduction to this security plugin, helping you get setup and started quickly with the core features.",
|
src/config/feature-reporting.php
CHANGED
@@ -14,6 +14,21 @@
|
|
14 |
"run_if_wpcli": true,
|
15 |
"tracking_exclude": true
|
16 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
"sections": [
|
18 |
{
|
19 |
"slug": "section_timings",
|
@@ -119,20 +134,21 @@
|
|
119 |
}
|
120 |
],
|
121 |
"definitions": {
|
122 |
-
"db_classes":
|
123 |
"reports": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Reports\\Handler"
|
124 |
},
|
125 |
-
"
|
126 |
-
|
127 |
-
"
|
128 |
-
"
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
|
|
136 |
}
|
137 |
}
|
138 |
}
|
14 |
"run_if_wpcli": true,
|
15 |
"tracking_exclude": true
|
16 |
},
|
17 |
+
"menu_items": [
|
18 |
+
{
|
19 |
+
"title": "Stats (beta)",
|
20 |
+
"slug": "stats-redirect"
|
21 |
+
}
|
22 |
+
],
|
23 |
+
"custom_redirects": [
|
24 |
+
{
|
25 |
+
"source_mod_page": "stats-redirect",
|
26 |
+
"target_mod_page": "insights",
|
27 |
+
"query_args": {
|
28 |
+
"inav": "reports"
|
29 |
+
}
|
30 |
+
}
|
31 |
+
],
|
32 |
"sections": [
|
33 |
{
|
34 |
"slug": "section_timings",
|
134 |
}
|
135 |
],
|
136 |
"definitions": {
|
137 |
+
"db_classes": {
|
138 |
"reports": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Reports\\Handler"
|
139 |
},
|
140 |
+
"db_table_reports": {
|
141 |
+
"slug": "reports",
|
142 |
+
"autoexpire": 30,
|
143 |
+
"cols_custom": {
|
144 |
+
"rid": "int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Report ID'",
|
145 |
+
"type": "varchar(3) NOT NULL DEFAULT '' COMMENT 'Report Type'",
|
146 |
+
"frequency": "varchar(10) NOT NULL DEFAULT '' COMMENT 'Report Interval/Frequency'"
|
147 |
+
},
|
148 |
+
"cols_timestamps": {
|
149 |
+
"interval_end_at": "Reporting Interval End",
|
150 |
+
"sent_at": "Report Sent"
|
151 |
+
}
|
152 |
}
|
153 |
}
|
154 |
}
|
src/config/feature-sessions.php
CHANGED
@@ -56,7 +56,8 @@
|
|
56 |
],
|
57 |
"definitions": {
|
58 |
"db_classes": {
|
59 |
-
"
|
|
|
60 |
},
|
61 |
"sessions_table_name": "sessions",
|
62 |
"sessions_table_columns": {
|
@@ -72,6 +73,22 @@
|
|
72 |
"login_intent_expires_at": "2FA Window Expires",
|
73 |
"secadmin_at": "Security Admin Authenticated"
|
74 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
"events": {
|
76 |
"session_start": {
|
77 |
"audit": false
|
@@ -79,6 +96,11 @@
|
|
79 |
"session_terminate": {
|
80 |
"audit": false,
|
81 |
"recent": true
|
|
|
|
|
|
|
|
|
|
|
82 |
}
|
83 |
}
|
84 |
}
|
56 |
],
|
57 |
"definitions": {
|
58 |
"db_classes": {
|
59 |
+
"sessions": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Session\\Handler",
|
60 |
+
"session": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Session\\Handler"
|
61 |
},
|
62 |
"sessions_table_name": "sessions",
|
63 |
"sessions_table_columns": {
|
73 |
"login_intent_expires_at": "2FA Window Expires",
|
74 |
"secadmin_at": "Security Admin Authenticated"
|
75 |
},
|
76 |
+
"db_table_sessions": {
|
77 |
+
"slug": "sessions",
|
78 |
+
"cols_custom": {
|
79 |
+
"session_id": "varchar(32) NOT NULL DEFAULT ''",
|
80 |
+
"wp_username": "varchar(255) NOT NULL DEFAULT ''",
|
81 |
+
"ip": "varchar(60) NOT NULL DEFAULT '0'",
|
82 |
+
"browser": "varchar(32) NOT NULL DEFAULT ''",
|
83 |
+
"last_activity_uri": "text NOT NULL DEFAULT ''"
|
84 |
+
},
|
85 |
+
"cols_timestamps": {
|
86 |
+
"logged_in_at": "Session Started",
|
87 |
+
"last_activity_at": "Last Seen At",
|
88 |
+
"login_intent_expires_at": "2FA Window Expires",
|
89 |
+
"secadmin_at": "Security Admin Authenticated"
|
90 |
+
}
|
91 |
+
},
|
92 |
"events": {
|
93 |
"session_start": {
|
94 |
"audit": false
|
96 |
"session_terminate": {
|
97 |
"audit": false,
|
98 |
"recent": true
|
99 |
+
},
|
100 |
+
"login_success": {
|
101 |
+
"offense": false,
|
102 |
+
"audit": false,
|
103 |
+
"stat": false
|
104 |
}
|
105 |
}
|
106 |
}
|
src/config/feature-traffic.php
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
{
|
2 |
-
"slug":
|
3 |
-
"properties":
|
4 |
"slug": "traffic",
|
5 |
"name": "Traffic Watch",
|
6 |
"sidebar_name": "Traffic",
|
@@ -19,8 +19,7 @@
|
|
19 |
"menu_items": [
|
20 |
{
|
21 |
"title": "Traffic Log",
|
22 |
-
"slug": "traffic-redirect"
|
23 |
-
"callback": ""
|
24 |
}
|
25 |
],
|
26 |
"custom_redirects": [
|
@@ -32,7 +31,7 @@
|
|
32 |
}
|
33 |
}
|
34 |
],
|
35 |
-
"sections":
|
36 |
{
|
37 |
"slug": "section_traffic_options",
|
38 |
"primary": true,
|
@@ -66,7 +65,7 @@
|
|
66 |
"hidden": true
|
67 |
}
|
68 |
],
|
69 |
-
"options":
|
70 |
{
|
71 |
"key": "enable_traffic",
|
72 |
"section": "section_enable_plugin_feature_traffic",
|
@@ -214,10 +213,23 @@
|
|
214 |
"description": "The time limit within which to monitor for excessive requests that exceed the limit."
|
215 |
}
|
216 |
],
|
217 |
-
"definitions":
|
218 |
"db_classes": {
|
219 |
"traffic": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Traffic\\Handler"
|
220 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
221 |
"traffic_table_name": "traffic",
|
222 |
"traffic_table_columns": {
|
223 |
"rid": "varchar(10) NOT NULL DEFAULT '' COMMENT 'Request ID'",
|
1 |
{
|
2 |
+
"slug": "traffic",
|
3 |
+
"properties": {
|
4 |
"slug": "traffic",
|
5 |
"name": "Traffic Watch",
|
6 |
"sidebar_name": "Traffic",
|
19 |
"menu_items": [
|
20 |
{
|
21 |
"title": "Traffic Log",
|
22 |
+
"slug": "traffic-redirect"
|
|
|
23 |
}
|
24 |
],
|
25 |
"custom_redirects": [
|
31 |
}
|
32 |
}
|
33 |
],
|
34 |
+
"sections": [
|
35 |
{
|
36 |
"slug": "section_traffic_options",
|
37 |
"primary": true,
|
65 |
"hidden": true
|
66 |
}
|
67 |
],
|
68 |
+
"options": [
|
69 |
{
|
70 |
"key": "enable_traffic",
|
71 |
"section": "section_enable_plugin_feature_traffic",
|
213 |
"description": "The time limit within which to monitor for excessive requests that exceed the limit."
|
214 |
}
|
215 |
],
|
216 |
+
"definitions": {
|
217 |
"db_classes": {
|
218 |
"traffic": "\\FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Traffic\\Handler"
|
219 |
},
|
220 |
+
"db_table_traffic": {
|
221 |
+
"slug": "traffic",
|
222 |
+
"cols_custom": {
|
223 |
+
"rid": "varchar(10) NOT NULL DEFAULT '' COMMENT 'Request ID'",
|
224 |
+
"uid": "int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'User ID'",
|
225 |
+
"ip": "varbinary(16) DEFAULT NULL COMMENT 'Visitor IP Address'",
|
226 |
+
"path": "text NOT NULL DEFAULT '' COMMENT 'Request Path or URI'",
|
227 |
+
"code": "int(5) NOT NULL DEFAULT '200' COMMENT 'HTTP Response Code'",
|
228 |
+
"verb": "varchar(10) NOT NULL DEFAULT 'get' COMMENT 'HTTP Method'",
|
229 |
+
"ua": "text COMMENT 'Browser User Agent String'",
|
230 |
+
"trans": "tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Trangression'"
|
231 |
+
}
|
232 |
+
},
|
233 |
"traffic_table_name": "traffic",
|
234 |
"traffic_table_columns": {
|
235 |
"rid": "varchar(10) NOT NULL DEFAULT '' COMMENT 'Request ID'",
|
src/lib/functions/functions.php
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
use FernleafSystems\Wordpress\Plugin\Shield;
|
4 |
+
use FernleafSystems\Wordpress\Services\Services;
|
5 |
+
|
6 |
+
if ( function_exists( 'shield_security_get_plugin' ) ) {
|
7 |
+
return;
|
8 |
+
}
|
9 |
+
|
10 |
+
function shield_security_get_plugin() :ICWP_WPSF_Shield_Security {
|
11 |
+
return ICWP_WPSF_Shield_Security::GetInstance();
|
12 |
+
}
|
13 |
+
|
14 |
+
function shield_get_visitor_scores( $IP = null ) :array {
|
15 |
+
return ( new Shield\Modules\IPs\Lib\Bots\Calculator\CalculateVisitorBotScores() )
|
16 |
+
->setMod( shield_security_get_plugin()->getController()->getModule_IPs() )
|
17 |
+
->setIP( $IP ?? Services::IP()->getRequestIp() )
|
18 |
+
->scores();
|
19 |
+
}
|
20 |
+
|
21 |
+
function shield_get_visitor_score( $IP = null ) :int {
|
22 |
+
return ( new Shield\Modules\IPs\Lib\Bots\Calculator\CalculateVisitorBotScores() )
|
23 |
+
->setMod( shield_security_get_plugin()->getController()->getModule_IPs() )
|
24 |
+
->setIP( $IP ?? Services::IP()->getRequestIp() )
|
25 |
+
->probability();
|
26 |
+
}
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Calculates the visitor score then compares it against the user-defined score minimum for bots
|
30 |
+
* @param null $IP - defaults to current visitor
|
31 |
+
* @return bool - true if bot, false otherwise
|
32 |
+
* @throws Exception
|
33 |
+
*/
|
34 |
+
function shield_test_ip_is_bot( $IP = null ) :bool {
|
35 |
+
return shield_security_get_plugin()->getController()
|
36 |
+
->getModule_IPs()
|
37 |
+
->getBotSignalsController()
|
38 |
+
->isBot( (string)$IP );
|
39 |
+
}
|
src/lib/src/Controller/Admin/MainAdminMenu.php
CHANGED
@@ -32,9 +32,9 @@ class MainAdminMenu {
|
|
32 |
if ( $menu[ 'top_level' ] ) {
|
33 |
|
34 |
$labels = $con->getLabels();
|
35 |
-
$
|
36 |
-
if ( is_null( $
|
37 |
-
$
|
38 |
}
|
39 |
|
40 |
$sMenuIcon = $con->urls->forImage( $menu[ 'icon_image' ] );
|
@@ -43,7 +43,7 @@ class MainAdminMenu {
|
|
43 |
$parentMenuID = $con->getPluginPrefix();
|
44 |
add_menu_page(
|
45 |
$con->getHumanName(),
|
46 |
-
$
|
47 |
$con->getBasePermissions(),
|
48 |
$parentMenuID,
|
49 |
[ $this, 'onDisplayTopMenu' ],
|
@@ -54,11 +54,11 @@ class MainAdminMenu {
|
|
54 |
|
55 |
$menuItems = apply_filters( $con->prefix( 'submenu_items' ), [] );
|
56 |
if ( !empty( $menuItems ) ) {
|
57 |
-
foreach ( $menuItems as $
|
58 |
-
list( $sMenuItemText, $sMenuItemId, $aMenuCallBack, $bShowItem ) = $
|
59 |
add_submenu_page(
|
60 |
$bShowItem ? $parentMenuID : null,
|
61 |
-
$
|
62 |
$sMenuItemText,
|
63 |
$con->getBasePermissions(),
|
64 |
$sMenuItemId,
|
32 |
if ( $menu[ 'top_level' ] ) {
|
33 |
|
34 |
$labels = $con->getLabels();
|
35 |
+
$menuTitle = empty( $labels[ 'MenuTitle' ] ) ? $menu[ 'title' ] : $labels[ 'MenuTitle' ];
|
36 |
+
if ( is_null( $menuTitle ) ) {
|
37 |
+
$menuTitle = $con->getHumanName();
|
38 |
}
|
39 |
|
40 |
$sMenuIcon = $con->urls->forImage( $menu[ 'icon_image' ] );
|
43 |
$parentMenuID = $con->getPluginPrefix();
|
44 |
add_menu_page(
|
45 |
$con->getHumanName(),
|
46 |
+
$menuTitle,
|
47 |
$con->getBasePermissions(),
|
48 |
$parentMenuID,
|
49 |
[ $this, 'onDisplayTopMenu' ],
|
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,
|
src/lib/src/Controller/Ajax/Init.php
CHANGED
@@ -20,13 +20,18 @@ class Init {
|
|
20 |
$this->ajaxAction();
|
21 |
} );
|
22 |
add_action( 'wp_ajax_nopriv_'.$this->getCon()->prefix(), function () {
|
23 |
-
$this->ajaxAction();
|
24 |
} );
|
25 |
}
|
26 |
|
27 |
-
private function ajaxAction() {
|
28 |
-
$
|
29 |
-
|
|
|
|
|
|
|
|
|
|
|
30 |
|
31 |
ob_start();
|
32 |
$response = apply_filters(
|
@@ -52,4 +57,8 @@ class Init {
|
|
52 |
false
|
53 |
);
|
54 |
}
|
|
|
|
|
|
|
|
|
55 |
}
|
20 |
$this->ajaxAction();
|
21 |
} );
|
22 |
add_action( 'wp_ajax_nopriv_'.$this->getCon()->prefix(), function () {
|
23 |
+
$this->ajaxAction( false );
|
24 |
} );
|
25 |
}
|
26 |
|
27 |
+
private function ajaxAction( bool $forceDie = true ) {
|
28 |
+
$req = Services::Request();
|
29 |
+
$nonceAction = $req->request( 'exec' );
|
30 |
+
|
31 |
+
// if the ajax action is part of the allow list, is may fail the nonce.
|
32 |
+
// This is work around for front-end caching plugin that screw everything up.
|
33 |
+
check_ajax_referer( $nonceAction, 'exec_nonce',
|
34 |
+
$forceDie || !in_array( $nonceAction, $this->getAllowedNoPrivExecs() ) );
|
35 |
|
36 |
ob_start();
|
37 |
$response = apply_filters(
|
57 |
false
|
58 |
);
|
59 |
}
|
60 |
+
|
61 |
+
private function getAllowedNoPrivExecs() :array {
|
62 |
+
return [];
|
63 |
+
}
|
64 |
}
|
src/lib/src/Controller/Assets/Enqueue.php
CHANGED
@@ -23,6 +23,9 @@ class Enqueue {
|
|
23 |
}
|
24 |
|
25 |
protected function run() {
|
|
|
|
|
|
|
26 |
add_action( 'wp_enqueue_scripts', function () {
|
27 |
$this->enqueue();
|
28 |
}, 1000 );
|
@@ -95,6 +98,7 @@ class Enqueue {
|
|
95 |
|
96 |
$incl = $con->cfg->includes[ 'register' ];
|
97 |
|
|
|
98 |
foreach ( array_keys( $assetKeys ) as $type ) {
|
99 |
|
100 |
foreach ( $incl[ $type ] as $key => $spec ) {
|
@@ -102,24 +106,29 @@ class Enqueue {
|
|
102 |
|
103 |
$handle = $this->normaliseHandle( $key );
|
104 |
if ( $type === self::CSS ) {
|
105 |
-
$url = $spec[ 'url' ] ?? $con->urls->forCss( $key );
|
106 |
$reg = wp_register_style(
|
107 |
$handle,
|
108 |
-
$
|
109 |
$this->prefixKeys( $spec[ 'deps' ] ?? [] ),
|
110 |
$con->getVersion()
|
111 |
);
|
112 |
}
|
113 |
else {
|
114 |
-
$url = $spec[ 'url' ] ?? $con->urls->forJs( $key );
|
115 |
$reg = wp_register_script(
|
116 |
$handle,
|
117 |
-
$
|
118 |
$this->prefixKeys( $spec[ 'deps' ] ?? [] ),
|
119 |
-
$con->getVersion()
|
|
|
120 |
);
|
121 |
}
|
122 |
|
|
|
|
|
|
|
|
|
|
|
|
|
123 |
if ( $reg ) {
|
124 |
$assetKeys[ $type ][] = $handle;
|
125 |
}
|
@@ -167,7 +176,14 @@ class Enqueue {
|
|
167 |
|
168 |
private function runEnqueueOnAssets( string $type, array $asset ) {
|
169 |
array_map(
|
170 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
171 |
$this->prefixKeys( $asset )
|
172 |
);
|
173 |
}
|
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 );
|
98 |
|
99 |
$incl = $con->cfg->includes[ 'register' ];
|
100 |
|
101 |
+
$includesService = Services::Includes();
|
102 |
foreach ( array_keys( $assetKeys ) as $type ) {
|
103 |
|
104 |
foreach ( $incl[ $type ] as $key => $spec ) {
|
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 |
);
|
124 |
}
|
125 |
|
126 |
+
if ( !empty( $spec[ 'attributes' ] ) ) {
|
127 |
+
foreach ( $spec[ 'attributes' ] as $attribute => $value ) {
|
128 |
+
$includesService->addIncludeAttribute( $handle, $attribute, $value );
|
129 |
+
}
|
130 |
+
}
|
131 |
+
|
132 |
if ( $reg ) {
|
133 |
$assetKeys[ $type ][] = $handle;
|
134 |
}
|
176 |
|
177 |
private function runEnqueueOnAssets( string $type, array $asset ) {
|
178 |
array_map(
|
179 |
+
function ( $asset ) use ( $type ) {
|
180 |
+
if ( $type == self::CSS ) {
|
181 |
+
wp_enqueue_style( $asset );
|
182 |
+
}
|
183 |
+
else {
|
184 |
+
wp_enqueue_script( $asset );
|
185 |
+
}
|
186 |
+
},
|
187 |
$this->prefixKeys( $asset )
|
188 |
);
|
189 |
}
|
src/lib/src/Controller/Assets/Paths.php
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
+
|
7 |
+
class Paths {
|
8 |
+
|
9 |
+
use PluginControllerConsumer;
|
10 |
+
|
11 |
+
public function forAsset( string $asset = '' ) :string {
|
12 |
+
return $this->forPluginItem( $this->getCon()->cfg->paths[ 'assets' ].'/'.ltrim( $asset, '/' ) );
|
13 |
+
}
|
14 |
+
|
15 |
+
public function forFlag( string $flag = '' ) :string {
|
16 |
+
return $this->forPluginItem( $this->getCon()->cfg->paths[ 'flags' ].'/'.ltrim( $flag, '/' ) );
|
17 |
+
}
|
18 |
+
|
19 |
+
public function forImage( string $asset ) :string {
|
20 |
+
return $this->forAsset( 'images/'.ltrim( $asset, '/' ) );
|
21 |
+
}
|
22 |
+
|
23 |
+
public function forJs( string $asset ) :string {
|
24 |
+
return $this->forAsset( 'js/'.ltrim( $asset, '/' ) );
|
25 |
+
}
|
26 |
+
|
27 |
+
public function forPluginItem( string $item = '' ) :string {
|
28 |
+
return path_join( $this->getCon()->getRootDir(), ltrim( $item, '/' ) );
|
29 |
+
}
|
30 |
+
|
31 |
+
public function forSource( string $source = '' ) :string {
|
32 |
+
return $this->forPluginItem( $this->getCon()->cfg->paths[ 'source' ].'/'.ltrim( $source, '/' ) );
|
33 |
+
}
|
34 |
+
|
35 |
+
public function forTemplate( string $item = '' ) :string {
|
36 |
+
return $this->forPluginItem( $this->getCon()->cfg->paths[ 'templates' ].'/'.ltrim( $item, '/' ) );
|
37 |
+
}
|
38 |
+
}
|
src/lib/src/Controller/Assets/Urls.php
CHANGED
@@ -3,6 +3,7 @@
|
|
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 Urls {
|
@@ -22,26 +23,26 @@ class Urls {
|
|
22 |
|
23 |
public function forJs( string $asset ) :string {
|
24 |
$url = $this->lookupAssetUrlInSpec( $asset, 'js' );
|
25 |
-
|
26 |
-
$this->
|
27 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
}
|
29 |
|
30 |
public function forAsset( string $asset ) :string {
|
31 |
$con = $this->getCon();
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
$
|
36 |
-
|
37 |
-
$path
|
38 |
-
);
|
39 |
-
}
|
40 |
-
else {
|
41 |
-
$url = '';
|
42 |
-
}
|
43 |
-
|
44 |
-
return $url;
|
45 |
}
|
46 |
|
47 |
public function forPluginItem( string $path = '' ) :string {
|
@@ -49,16 +50,27 @@ class Urls {
|
|
49 |
return add_query_arg( [ 'ver' => $con->getVersion() ], plugins_url( $path, $con->getRootFile() ) );
|
50 |
}
|
51 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
/**
|
53 |
* @param string $asset
|
54 |
* @param string $type
|
55 |
* @return mixed|null
|
56 |
*/
|
57 |
protected function lookupAssetUrlInSpec( string $asset, string $type ) {
|
58 |
-
$
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
|
|
63 |
}
|
64 |
}
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Controller\Assets;
|
4 |
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\PluginControllerConsumer;
|
6 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Utilities\Resources\Dynamic;
|
7 |
use FernleafSystems\Wordpress\Services\Services;
|
8 |
|
9 |
class Urls {
|
23 |
|
24 |
public function forJs( string $asset ) :string {
|
25 |
$url = $this->lookupAssetUrlInSpec( $asset, 'js' );
|
26 |
+
if ( empty( $url ) ) {
|
27 |
+
if ( $this->isAssetDynamic( $asset, 'js' ) ) {
|
28 |
+
$url = ( new Dynamic() )
|
29 |
+
->setCon( $this->getCon() )
|
30 |
+
->getResourceUrl( Services::Data()->addExtensionToFilePath( $asset, 'js' ) );
|
31 |
+
}
|
32 |
+
else {
|
33 |
+
$url = $this->forAsset( 'js/'.Services::Data()->addExtensionToFilePath( $asset, 'js' ) );
|
34 |
+
}
|
35 |
+
}
|
36 |
+
return $url;
|
37 |
}
|
38 |
|
39 |
public function forAsset( string $asset ) :string {
|
40 |
$con = $this->getCon();
|
41 |
+
$path = $con->paths->forAsset( $asset );
|
42 |
+
return Services::Includes()->addIncludeModifiedParam(
|
43 |
+
$this->forPluginItem( $con->cfg->paths[ 'assets' ].'/'.$asset ),
|
44 |
+
$path
|
45 |
+
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
}
|
47 |
|
48 |
public function forPluginItem( string $path = '' ) :string {
|
50 |
return add_query_arg( [ 'ver' => $con->getVersion() ], plugins_url( $path, $con->getRootFile() ) );
|
51 |
}
|
52 |
|
53 |
+
/**
|
54 |
+
* @param string $asset
|
55 |
+
* @param string $type
|
56 |
+
* @return mixed|null
|
57 |
+
*/
|
58 |
+
protected function isAssetDynamic( string $asset, string $type ) :bool {
|
59 |
+
$asset = $this->lookupAssetInSpec( $asset, $type );
|
60 |
+
return !empty( $asset[ 'dynamic' ] );
|
61 |
+
}
|
62 |
+
|
63 |
/**
|
64 |
* @param string $asset
|
65 |
* @param string $type
|
66 |
* @return mixed|null
|
67 |
*/
|
68 |
protected function lookupAssetUrlInSpec( string $asset, string $type ) {
|
69 |
+
$asset = $this->lookupAssetInSpec( $asset, $type );
|
70 |
+
return empty( $asset[ 'url' ] ) ? null : $asset[ 'url' ];
|
71 |
+
}
|
72 |
+
|
73 |
+
protected function lookupAssetInSpec( string $asset, string $type ) :array {
|
74 |
+
return $this->getCon()->cfg->includes[ 'register' ][ $type ][ $asset ] ?? [];
|
75 |
}
|
76 |
}
|
src/lib/src/Controller/Config/ConfigVO.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Controller\Config;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Data\Adapter\
|
6 |
|
7 |
/**
|
8 |
* Class ConfigVO
|
@@ -23,11 +23,7 @@ use FernleafSystems\Utilities\Data\Adapter\StdClassAdapter;
|
|
23 |
* @property string $previous_version
|
24 |
* @property array $update_first_detected
|
25 |
*/
|
26 |
-
class ConfigVO {
|
27 |
-
|
28 |
-
use StdClassAdapter {
|
29 |
-
__get as __adapterGet;
|
30 |
-
}
|
31 |
|
32 |
/**
|
33 |
* @var bool
|
@@ -38,8 +34,8 @@ class ConfigVO {
|
|
38 |
* @param string $key
|
39 |
* @return mixed
|
40 |
*/
|
41 |
-
public function __get( $key ) {
|
42 |
-
$val =
|
43 |
|
44 |
switch ( $key ) {
|
45 |
|
@@ -70,4 +66,13 @@ class ConfigVO {
|
|
70 |
|
71 |
return $val;
|
72 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
73 |
}
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Controller\Config;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
|
6 |
|
7 |
/**
|
8 |
* Class ConfigVO
|
23 |
* @property string $previous_version
|
24 |
* @property array $update_first_detected
|
25 |
*/
|
26 |
+
class ConfigVO extends DynPropertiesClass {
|
|
|
|
|
|
|
|
|
27 |
|
28 |
/**
|
29 |
* @var bool
|
34 |
* @param string $key
|
35 |
* @return mixed
|
36 |
*/
|
37 |
+
public function __get( string $key ) {
|
38 |
+
$val = parent::__get( $key );
|
39 |
|
40 |
switch ( $key ) {
|
41 |
|
66 |
|
67 |
return $val;
|
68 |
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* @param $key
|
72 |
+
* @return mixed|null
|
73 |
+
* @deprecated 10.3
|
74 |
+
*/
|
75 |
+
private function __adapterGet( $key ) {
|
76 |
+
return $this->getRawData()[ $key ] ?? null;
|
77 |
+
}
|
78 |
}
|
src/lib/src/Controller/Controller.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Controller;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Data\Adapter\
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield;
|
7 |
use FernleafSystems\Wordpress\Services\Services;
|
8 |
use FernleafSystems\Wordpress\Services\Utilities\Options\Transient;
|
@@ -12,6 +12,7 @@ use FernleafSystems\Wordpress\Services\Utilities\Options\Transient;
|
|
12 |
* @package FernleafSystems\Wordpress\Plugin\Shield\Controller
|
13 |
* @property Config\ConfigVO $cfg
|
14 |
* @property Shield\Controller\Assets\Urls $urls
|
|
|
15 |
* @property bool $is_activating
|
16 |
* @property bool $is_debug
|
17 |
* @property bool $modules_loaded
|
@@ -20,18 +21,16 @@ use FernleafSystems\Wordpress\Services\Utilities\Options\Transient;
|
|
20 |
* @property bool $plugin_deactivating
|
21 |
* @property bool $plugin_deleting
|
22 |
* @property bool $plugin_reset
|
|
|
23 |
* @property false|string $file_forceoff
|
24 |
* @property string $base_file
|
25 |
* @property string $root_file
|
|
|
26 |
* @property bool $user_can_base_permissions
|
27 |
* @property Shield\Modules\Events\Lib\EventsService $service_events
|
28 |
* @property mixed[]|Shield\Modules\Base\ModCon[] $modules
|
29 |
*/
|
30 |
-
class Controller {
|
31 |
-
|
32 |
-
use StdClassAdapter {
|
33 |
-
__get as __adapterGet;
|
34 |
-
}
|
35 |
|
36 |
/**
|
37 |
* @var \stdClass
|
@@ -146,8 +145,8 @@ class Controller {
|
|
146 |
* @param string $key
|
147 |
* @return mixed
|
148 |
*/
|
149 |
-
public function __get( $key ) {
|
150 |
-
$val =
|
151 |
|
152 |
switch ( $key ) {
|
153 |
|
@@ -163,6 +162,13 @@ class Controller {
|
|
163 |
}
|
164 |
break;
|
165 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
166 |
case 'is_debug':
|
167 |
if ( is_null( $val ) ) {
|
168 |
$val = ( new Shield\Controller\Utilities\DebugMode() )
|
@@ -179,6 +185,15 @@ class Controller {
|
|
179 |
return $val;
|
180 |
}
|
181 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
182 |
/**
|
183 |
* @throws \Exception
|
184 |
*/
|
@@ -299,38 +314,72 @@ class Controller {
|
|
299 |
}
|
300 |
|
301 |
/**
|
302 |
-
* @param string $
|
303 |
* @return string|false
|
304 |
*/
|
305 |
-
public function getPluginCachePath( $
|
306 |
-
|
307 |
-
|
308 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
309 |
}
|
310 |
-
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
311 |
}
|
312 |
|
313 |
/**
|
314 |
-
* @return
|
|
|
315 |
*/
|
316 |
-
private function buildPluginCacheDir() {
|
317 |
-
$
|
318 |
-
|
319 |
-
$
|
320 |
-
if (
|
321 |
-
$
|
322 |
-
|
323 |
-
|
324 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
325 |
}
|
326 |
-
$
|
327 |
-
$
|
328 |
-
if ( !$
|
329 |
-
$
|
330 |
}
|
331 |
-
$
|
332 |
}
|
333 |
-
return $
|
334 |
}
|
335 |
|
336 |
protected function doRegisterHooks() {
|
@@ -350,7 +399,7 @@ class Controller {
|
|
350 |
add_filter( 'auto_update_plugin', [ $this, 'onWpAutoUpdate' ], 500, 2 );
|
351 |
add_filter( 'set_site_transient_update_plugins', [ $this, 'setUpdateFirstDetectedAt' ] );
|
352 |
|
353 |
-
add_action( 'shutdown', [ $this, 'onWpShutdown' ],
|
354 |
add_action( 'wp_logout', [ $this, 'onWpLogout' ] );
|
355 |
|
356 |
// GDPR
|
@@ -469,6 +518,9 @@ class Controller {
|
|
469 |
( new Admin\MainAdminMenu() )
|
470 |
->setCon( $this )
|
471 |
->execute();
|
|
|
|
|
|
|
472 |
}
|
473 |
|
474 |
protected function initCrons() {
|
@@ -495,14 +547,14 @@ class Controller {
|
|
495 |
}
|
496 |
|
497 |
/**
|
498 |
-
* @param string $
|
499 |
* @return array
|
500 |
*/
|
501 |
-
public function getNonceActionData( $
|
502 |
return [
|
503 |
'action' => $this->prefix(), //wp ajax doesn't work without this.
|
504 |
-
'exec' => $
|
505 |
-
'exec_nonce' => wp_create_nonce( $
|
506 |
// 'rand' => wp_rand( 10000, 99999 )
|
507 |
];
|
508 |
}
|
@@ -729,7 +781,7 @@ class Controller {
|
|
729 |
foreach ( [ '16x16', '32x32', '128x128' ] as $dimension ) {
|
730 |
$key = 'icon_url_'.$dimension;
|
731 |
if ( !empty( $labels[ $key ] ) && !$oDP->isValidWebUrl( $labels[ $key ] ) ) {
|
732 |
-
$labels[ $key ] = $this->
|
733 |
}
|
734 |
}
|
735 |
|
@@ -752,11 +804,11 @@ class Controller {
|
|
752 |
|
753 |
protected function deleteFlags() {
|
754 |
$FS = Services::WpFs();
|
755 |
-
if ( $FS->exists( $this->
|
756 |
-
$FS->deleteFile( $this->
|
757 |
}
|
758 |
if ( $this->getIsResetPlugin() ) {
|
759 |
-
$FS->deleteFile( $this->
|
760 |
}
|
761 |
}
|
762 |
|
@@ -825,7 +877,7 @@ class Controller {
|
|
825 |
*/
|
826 |
public function getPluginSpec() {
|
827 |
if ( isset( $this->cfg ) ) {
|
828 |
-
return $this->cfg->
|
829 |
}
|
830 |
return $this->getPluginControllerOptions()->plugin_spec;
|
831 |
}
|
@@ -835,11 +887,7 @@ class Controller {
|
|
835 |
* @return string|null
|
836 |
*/
|
837 |
public function getPluginSpec_Path( string $key ) {
|
838 |
-
|
839 |
-
return $this->cfg->paths[ $key ];
|
840 |
-
}
|
841 |
-
$aData = $this->getPluginSpec()[ 'paths' ];
|
842 |
-
return $aData[ $key ] ?? null;
|
843 |
}
|
844 |
|
845 |
/**
|
@@ -850,15 +898,6 @@ class Controller {
|
|
850 |
return $this->cfg->properties[ $key ] ?? null;
|
851 |
}
|
852 |
|
853 |
-
/**
|
854 |
-
* @param string $key
|
855 |
-
* @return mixed|null
|
856 |
-
* @deprecated 10.2.0 - getCfgProperty()
|
857 |
-
*/
|
858 |
-
protected function getPluginSpec_Property( string $key ) {
|
859 |
-
return $this->cfg->properties[ $key ] ?? null;
|
860 |
-
}
|
861 |
-
|
862 |
public function getBasePermissions() :string {
|
863 |
if ( isset( $this->cfg ) ) {
|
864 |
return $this->cfg->properties[ 'base_permissions' ];
|
@@ -936,17 +975,9 @@ class Controller {
|
|
936 |
return Services::WpGeneral()->getCurrentWpAdminPage() === $this->getPluginPrefix();
|
937 |
}
|
938 |
|
939 |
-
/**
|
940 |
-
* @return bool
|
941 |
-
* @deprecated 10.2
|
942 |
-
*/
|
943 |
-
public function getIsRebuildOptionsFromFile() :bool {
|
944 |
-
return $this->rebuild_options;
|
945 |
-
}
|
946 |
-
|
947 |
public function getIsResetPlugin() :bool {
|
948 |
if ( !isset( $this->plugin_reset ) ) {
|
949 |
-
$this->plugin_reset = (bool)Services::WpFs()->isFile( $this->
|
950 |
}
|
951 |
return (bool)$this->plugin_reset;
|
952 |
}
|
@@ -959,17 +990,6 @@ class Controller {
|
|
959 |
return $this->getCfgProperty( 'slug_parent' );
|
960 |
}
|
961 |
|
962 |
-
/**
|
963 |
-
* @return string
|
964 |
-
* @deprecated 10.2.0
|
965 |
-
*/
|
966 |
-
public function getPluginBaseFile() :string {
|
967 |
-
if ( !isset( $this->base_file ) ) {
|
968 |
-
$this->base_file = plugin_basename( $this->getRootFile() );
|
969 |
-
}
|
970 |
-
return $this->base_file;
|
971 |
-
}
|
972 |
-
|
973 |
public function getPluginSlug() :string {
|
974 |
return $this->getCfgProperty( 'slug_plugin' );
|
975 |
}
|
@@ -978,26 +998,6 @@ class Controller {
|
|
978 |
return add_query_arg( [ 'ver' => $this->getVersion() ], plugins_url( $path, $this->getRootFile() ) );
|
979 |
}
|
980 |
|
981 |
-
/**
|
982 |
-
* @deprecated 10.2
|
983 |
-
*/
|
984 |
-
public function getPluginUrl_Asset( string $asset ) :string {
|
985 |
-
$url = '';
|
986 |
-
$sAssetPath = $this->getPath_Assets( $asset );
|
987 |
-
if ( Services::WpFs()->exists( $sAssetPath ) ) {
|
988 |
-
$url = $this->getPluginUrl( $this->getPluginSpec_Path( 'assets' ).'/'.$asset );
|
989 |
-
return Services::Includes()->addIncludeModifiedParam( $url, $sAssetPath );
|
990 |
-
}
|
991 |
-
return $url;
|
992 |
-
}
|
993 |
-
|
994 |
-
/**
|
995 |
-
* @deprecated 10.2
|
996 |
-
*/
|
997 |
-
public function getPluginUrl_Css( string $asset ) :string {
|
998 |
-
return $this->urls->forCss( $asset );
|
999 |
-
}
|
1000 |
-
|
1001 |
/**
|
1002 |
* @deprecated 10.2
|
1003 |
*/
|
@@ -1006,7 +1006,7 @@ class Controller {
|
|
1006 |
}
|
1007 |
|
1008 |
/**
|
1009 |
-
* @deprecated 10.
|
1010 |
*/
|
1011 |
public function getPluginUrl_Js( string $asset ) :string {
|
1012 |
return $this->urls->forJs( $asset );
|
@@ -1017,11 +1017,19 @@ class Controller {
|
|
1017 |
}
|
1018 |
|
1019 |
public function getPath_Assets( string $asset = '' ) :string {
|
1020 |
-
$base = path_join( $this->getRootDir(), $this->
|
1021 |
-
return empty( $asset ) ? $base : path_join( $base, $asset );
|
1022 |
}
|
1023 |
|
|
|
|
|
|
|
|
|
|
|
1024 |
public function getPath_Flags( string $flag = '' ) :string {
|
|
|
|
|
|
|
1025 |
$base = path_join( $this->getRootDir(), $this->getPluginSpec_Path( 'flags' ) );
|
1026 |
return empty( $flag ) ? $base : path_join( $base, $flag );
|
1027 |
}
|
@@ -1068,11 +1076,27 @@ class Controller {
|
|
1068 |
return $this->getPath_SourceFile( $this->getPluginSpec_Path( 'autoload' ) );
|
1069 |
}
|
1070 |
|
|
|
|
|
|
|
|
|
1071 |
public function getPath_PluginCache() :string {
|
1072 |
-
|
|
|
|
|
|
|
|
|
1073 |
}
|
1074 |
|
|
|
|
|
|
|
|
|
|
|
1075 |
public function getPath_SourceFile( string $sourceFile ) :string {
|
|
|
|
|
|
|
1076 |
$base = path_join( $this->getRootDir(), $this->getPluginSpec_Path( 'source' ) );
|
1077 |
return empty( $sourceFile ) ? $base : path_join( $base, $sourceFile );
|
1078 |
}
|
@@ -1081,8 +1105,11 @@ class Controller {
|
|
1081 |
return path_join( $this->getRootDir(), $this->getPluginSpec_Path( 'templates' ) ).'/';
|
1082 |
}
|
1083 |
|
1084 |
-
public function getPath_TemplatesFile( string $
|
1085 |
-
|
|
|
|
|
|
|
1086 |
}
|
1087 |
|
1088 |
private function getPathPluginSpec() :string {
|
@@ -1334,7 +1361,7 @@ class Controller {
|
|
1334 |
* @return Shield\Modules\Base\ModCon|null|mixed
|
1335 |
*/
|
1336 |
public function getModule( string $slug ) {
|
1337 |
-
$mod =
|
1338 |
if ( !$mod instanceof Shield\Modules\Base\ModCon ) {
|
1339 |
try {
|
1340 |
$mods = $this->loadCorePluginFeatureHandler()->getActivePluginFeatures();
|
@@ -1587,7 +1614,7 @@ class Controller {
|
|
1587 |
*/
|
1588 |
private function buildPrivacyPolicyContent() {
|
1589 |
try {
|
1590 |
-
if ( $this->getModule_SecAdmin()->
|
1591 |
$name = $this->getHumanName();
|
1592 |
$href = $this->getLabels()[ 'PluginURI' ];
|
1593 |
}
|
@@ -1626,61 +1653,4 @@ class Controller {
|
|
1626 |
->run();
|
1627 |
}
|
1628 |
}
|
1629 |
-
|
1630 |
-
/**
|
1631 |
-
* @deprecated 10.2
|
1632 |
-
*/
|
1633 |
-
public function onWpAdminMenu() {
|
1634 |
-
}
|
1635 |
-
|
1636 |
-
/**
|
1637 |
-
* @param \WP_Admin_Bar $adminBar
|
1638 |
-
* @deprecated 10.2
|
1639 |
-
*/
|
1640 |
-
public function onWpAdminBarMenu( $adminBar ) {
|
1641 |
-
}
|
1642 |
-
|
1643 |
-
/**
|
1644 |
-
* @deprecated 10.2
|
1645 |
-
*/
|
1646 |
-
public function onWpDashboardSetup() {
|
1647 |
-
}
|
1648 |
-
|
1649 |
-
/**
|
1650 |
-
* @deprecated 10.2
|
1651 |
-
*/
|
1652 |
-
protected function createPluginMenu() :bool {
|
1653 |
-
}
|
1654 |
-
|
1655 |
-
/**
|
1656 |
-
* @deprecated 10.2
|
1657 |
-
*/
|
1658 |
-
protected function fixSubmenu() {
|
1659 |
-
}
|
1660 |
-
|
1661 |
-
/**
|
1662 |
-
* Displaying all views now goes through this central function and we work out
|
1663 |
-
* what to display based on the name of current hook/filter being processed.
|
1664 |
-
* @deprecated 10.2
|
1665 |
-
*/
|
1666 |
-
public function onDisplayTopMenu() {
|
1667 |
-
}
|
1668 |
-
|
1669 |
-
/**
|
1670 |
-
* @deprecated 10.2
|
1671 |
-
*/
|
1672 |
-
public function onWpEnqueueFrontendCss() {
|
1673 |
-
}
|
1674 |
-
|
1675 |
-
/**
|
1676 |
-
* @deprecated 10.2
|
1677 |
-
*/
|
1678 |
-
public function onWpEnqueueAdminJs() {
|
1679 |
-
}
|
1680 |
-
|
1681 |
-
/**
|
1682 |
-
* @deprecated 10.2
|
1683 |
-
*/
|
1684 |
-
public function onWpEnqueueAdminCss() {
|
1685 |
-
}
|
1686 |
}
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Controller;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield;
|
7 |
use FernleafSystems\Wordpress\Services\Services;
|
8 |
use FernleafSystems\Wordpress\Services\Utilities\Options\Transient;
|
12 |
* @package FernleafSystems\Wordpress\Plugin\Shield\Controller
|
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
|
21 |
* @property bool $plugin_deactivating
|
22 |
* @property bool $plugin_deleting
|
23 |
* @property bool $plugin_reset
|
24 |
+
* @property bool $cache_dir_ready
|
25 |
* @property false|string $file_forceoff
|
26 |
* @property string $base_file
|
27 |
* @property string $root_file
|
28 |
+
* @property bool $is_my_upgrade
|
29 |
* @property bool $user_can_base_permissions
|
30 |
* @property Shield\Modules\Events\Lib\EventsService $service_events
|
31 |
* @property mixed[]|Shield\Modules\Base\ModCon[] $modules
|
32 |
*/
|
33 |
+
class Controller extends DynPropertiesClass {
|
|
|
|
|
|
|
|
|
34 |
|
35 |
/**
|
36 |
* @var \stdClass
|
145 |
* @param string $key
|
146 |
* @return mixed
|
147 |
*/
|
148 |
+
public function __get( string $key ) {
|
149 |
+
$val = parent::__get( $key );
|
150 |
|
151 |
switch ( $key ) {
|
152 |
|
162 |
}
|
163 |
break;
|
164 |
|
165 |
+
case 'paths':
|
166 |
+
if ( !$val instanceof Shield\Controller\Assets\Paths ) {
|
167 |
+
$val = ( new Shield\Controller\Assets\Paths() )->setCon( $this );
|
168 |
+
$this->paths = $val;
|
169 |
+
}
|
170 |
+
break;
|
171 |
+
|
172 |
case 'is_debug':
|
173 |
if ( is_null( $val ) ) {
|
174 |
$val = ( new Shield\Controller\Utilities\DebugMode() )
|
185 |
return $val;
|
186 |
}
|
187 |
|
188 |
+
/**
|
189 |
+
* @param $key
|
190 |
+
* @return mixed|null
|
191 |
+
* @deprecated 10.3
|
192 |
+
*/
|
193 |
+
private function __adapterGet( $key ) {
|
194 |
+
return $this->getRawData()[ $key ] ?? null;
|
195 |
+
}
|
196 |
+
|
197 |
/**
|
198 |
* @throws \Exception
|
199 |
*/
|
314 |
}
|
315 |
|
316 |
/**
|
317 |
+
* @param string $cachePath
|
318 |
* @return string|false
|
319 |
*/
|
320 |
+
public function getPluginCachePath( $cachePath = '' ) {
|
321 |
+
$path = false;
|
322 |
+
if ( $this->hasCacheDir() ) {
|
323 |
+
try {
|
324 |
+
// Never throws an exception if "hasCacheDir" == true
|
325 |
+
$path = $this->buildPluginCacheDir();
|
326 |
+
if ( !empty( $cachePath ) ) {
|
327 |
+
$path = path_join( $path, $cachePath );
|
328 |
+
}
|
329 |
+
}
|
330 |
+
catch ( \Exception $e ) {
|
331 |
+
}
|
332 |
}
|
333 |
+
return $path;
|
334 |
+
}
|
335 |
+
|
336 |
+
public function hasCacheDir() :bool {
|
337 |
+
try {
|
338 |
+
$buildCacheDir = $this->buildPluginCacheDir();
|
339 |
+
}
|
340 |
+
catch ( \Exception $e ) {
|
341 |
+
$buildCacheDir = false;
|
342 |
+
}
|
343 |
+
return $buildCacheDir;
|
344 |
}
|
345 |
|
346 |
/**
|
347 |
+
* @return string
|
348 |
+
* @throws \Exception
|
349 |
*/
|
350 |
+
private function buildPluginCacheDir() :string {
|
351 |
+
$FS = Services::WpFs();
|
352 |
+
|
353 |
+
$cacheDirBasename = $this->cfg->paths[ 'cache' ];
|
354 |
+
if ( empty( $cacheDirBasename ) ) {
|
355 |
+
$this->cache_dir_ready = false;
|
356 |
+
throw new \Exception( 'No slug for cache dir' );
|
357 |
+
}
|
358 |
+
|
359 |
+
$cacheDir = path_join( WP_CONTENT_DIR, $cacheDirBasename );
|
360 |
+
if ( empty( $this->cache_dir_ready ) && $FS->mkdir( $cacheDir ) ) {
|
361 |
+
$htFile = path_join( $cacheDir, '.htaccess' );
|
362 |
+
$htContent = implode( "\n", [
|
363 |
+
"# BEGIN SHIELD",
|
364 |
+
"Options -Indexes",
|
365 |
+
"Order allow,deny",
|
366 |
+
"Deny from all",
|
367 |
+
'<FilesMatch "^.*\.(css|js)$">',
|
368 |
+
" Allow from all",
|
369 |
+
'</FilesMatch>',
|
370 |
+
"# END SHIELD"
|
371 |
+
] );
|
372 |
+
if ( !$FS->exists( $htFile ) || ( md5_file( $htFile ) !== md5( $htContent ) ) ) {
|
373 |
+
$FS->putFileContent( $htFile, $htContent );
|
374 |
}
|
375 |
+
$index = path_join( $cacheDir, 'index.php' );
|
376 |
+
$indexContent = "<?php\nhttp_response_code(404);";
|
377 |
+
if ( !$FS->exists( $index ) || ( md5_file( $index ) !== md5( $indexContent ) ) ) {
|
378 |
+
$FS->putFileContent( $index, $indexContent );
|
379 |
}
|
380 |
+
$this->cache_dir_ready = true;
|
381 |
}
|
382 |
+
return $cacheDir;
|
383 |
}
|
384 |
|
385 |
protected function doRegisterHooks() {
|
399 |
add_filter( 'auto_update_plugin', [ $this, 'onWpAutoUpdate' ], 500, 2 );
|
400 |
add_filter( 'set_site_transient_update_plugins', [ $this, 'setUpdateFirstDetectedAt' ] );
|
401 |
|
402 |
+
add_action( 'shutdown', [ $this, 'onWpShutdown' ], PHP_INT_MIN );
|
403 |
add_action( 'wp_logout', [ $this, 'onWpLogout' ] );
|
404 |
|
405 |
// GDPR
|
518 |
( new Admin\MainAdminMenu() )
|
519 |
->setCon( $this )
|
520 |
->execute();
|
521 |
+
( new Utilities\CaptureMyUpgrade() )
|
522 |
+
->setCon( $this )
|
523 |
+
->execute();
|
524 |
}
|
525 |
|
526 |
protected function initCrons() {
|
547 |
}
|
548 |
|
549 |
/**
|
550 |
+
* @param string $action
|
551 |
* @return array
|
552 |
*/
|
553 |
+
public function getNonceActionData( $action = '' ) {
|
554 |
return [
|
555 |
'action' => $this->prefix(), //wp ajax doesn't work without this.
|
556 |
+
'exec' => $action,
|
557 |
+
'exec_nonce' => wp_create_nonce( $action ),
|
558 |
// 'rand' => wp_rand( 10000, 99999 )
|
559 |
];
|
560 |
}
|
781 |
foreach ( [ '16x16', '32x32', '128x128' ] as $dimension ) {
|
782 |
$key = 'icon_url_'.$dimension;
|
783 |
if ( !empty( $labels[ $key ] ) && !$oDP->isValidWebUrl( $labels[ $key ] ) ) {
|
784 |
+
$labels[ $key ] = $this->urls->forImage( $labels[ $key ] );
|
785 |
}
|
786 |
}
|
787 |
|
804 |
|
805 |
protected function deleteFlags() {
|
806 |
$FS = Services::WpFs();
|
807 |
+
if ( $FS->exists( $this->paths->forFlag( 'rebuild' ) ) ) {
|
808 |
+
$FS->deleteFile( $this->paths->forFlag( 'rebuild' ) );
|
809 |
}
|
810 |
if ( $this->getIsResetPlugin() ) {
|
811 |
+
$FS->deleteFile( $this->paths->forFlag( 'reset' ) );
|
812 |
}
|
813 |
}
|
814 |
|
877 |
*/
|
878 |
public function getPluginSpec() {
|
879 |
if ( isset( $this->cfg ) ) {
|
880 |
+
return $this->cfg->getRawData();
|
881 |
}
|
882 |
return $this->getPluginControllerOptions()->plugin_spec;
|
883 |
}
|
887 |
* @return string|null
|
888 |
*/
|
889 |
public function getPluginSpec_Path( string $key ) {
|
890 |
+
return $this->cfg->paths[ $key ] ?? null;
|
|
|
|
|
|
|
|
|
891 |
}
|
892 |
|
893 |
/**
|
898 |
return $this->cfg->properties[ $key ] ?? null;
|
899 |
}
|
900 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
901 |
public function getBasePermissions() :string {
|
902 |
if ( isset( $this->cfg ) ) {
|
903 |
return $this->cfg->properties[ 'base_permissions' ];
|
975 |
return Services::WpGeneral()->getCurrentWpAdminPage() === $this->getPluginPrefix();
|
976 |
}
|
977 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
978 |
public function getIsResetPlugin() :bool {
|
979 |
if ( !isset( $this->plugin_reset ) ) {
|
980 |
+
$this->plugin_reset = (bool)Services::WpFs()->isFile( $this->paths->forFlag( 'reset' ) );
|
981 |
}
|
982 |
return (bool)$this->plugin_reset;
|
983 |
}
|
990 |
return $this->getCfgProperty( 'slug_parent' );
|
991 |
}
|
992 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
993 |
public function getPluginSlug() :string {
|
994 |
return $this->getCfgProperty( 'slug_plugin' );
|
995 |
}
|
998 |
return add_query_arg( [ 'ver' => $this->getVersion() ], plugins_url( $path, $this->getRootFile() ) );
|
999 |
}
|
1000 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1001 |
/**
|
1002 |
* @deprecated 10.2
|
1003 |
*/
|
1006 |
}
|
1007 |
|
1008 |
/**
|
1009 |
+
* @deprecated 10.3
|
1010 |
*/
|
1011 |
public function getPluginUrl_Js( string $asset ) :string {
|
1012 |
return $this->urls->forJs( $asset );
|
1017 |
}
|
1018 |
|
1019 |
public function getPath_Assets( string $asset = '' ) :string {
|
1020 |
+
$base = path_join( $this->getRootDir(), $this->cfg->paths[ 'assets' ] );
|
1021 |
+
return empty( $asset ) ? $base : path_join( $base, ltrim( $asset, '/' ) );
|
1022 |
}
|
1023 |
|
1024 |
+
/**
|
1025 |
+
* @param string $flag
|
1026 |
+
* @return string
|
1027 |
+
* @deprecated 10.3
|
1028 |
+
*/
|
1029 |
public function getPath_Flags( string $flag = '' ) :string {
|
1030 |
+
if ( isset( $this->paths ) ) {
|
1031 |
+
return $this->paths->forFlag( $flag );
|
1032 |
+
}
|
1033 |
$base = path_join( $this->getRootDir(), $this->getPluginSpec_Path( 'flags' ) );
|
1034 |
return empty( $flag ) ? $base : path_join( $base, $flag );
|
1035 |
}
|
1076 |
return $this->getPath_SourceFile( $this->getPluginSpec_Path( 'autoload' ) );
|
1077 |
}
|
1078 |
|
1079 |
+
/**
|
1080 |
+
* @return string
|
1081 |
+
* @throws \Exception
|
1082 |
+
*/
|
1083 |
public function getPath_PluginCache() :string {
|
1084 |
+
$cacheSlug = $this->getPluginSpec_Path( 'cache' );
|
1085 |
+
if ( empty( $cacheSlug ) ) {
|
1086 |
+
throw new \Exception( 'Cache dir slug was empty' );
|
1087 |
+
}
|
1088 |
+
return path_join( WP_CONTENT_DIR, $cacheSlug );
|
1089 |
}
|
1090 |
|
1091 |
+
/**
|
1092 |
+
* @param string $sourceFile
|
1093 |
+
* @return string
|
1094 |
+
* @deprecated 10.3
|
1095 |
+
*/
|
1096 |
public function getPath_SourceFile( string $sourceFile ) :string {
|
1097 |
+
if ( isset( $this->paths ) ) {
|
1098 |
+
return $this->paths->forSource( $sourceFile );
|
1099 |
+
}
|
1100 |
$base = path_join( $this->getRootDir(), $this->getPluginSpec_Path( 'source' ) );
|
1101 |
return empty( $sourceFile ) ? $base : path_join( $base, $sourceFile );
|
1102 |
}
|
1105 |
return path_join( $this->getRootDir(), $this->getPluginSpec_Path( 'templates' ) ).'/';
|
1106 |
}
|
1107 |
|
1108 |
+
public function getPath_TemplatesFile( string $template ) :string {
|
1109 |
+
if ( isset( $this->paths ) ) {
|
1110 |
+
return $this->paths->forTemplate( $template );
|
1111 |
+
}
|
1112 |
+
return path_join( $this->getPath_Templates(), $template );
|
1113 |
}
|
1114 |
|
1115 |
private function getPathPluginSpec() :string {
|
1361 |
* @return Shield\Modules\Base\ModCon|null|mixed
|
1362 |
*/
|
1363 |
public function getModule( string $slug ) {
|
1364 |
+
$mod = $this->modules[ $slug ] ?? null;
|
1365 |
if ( !$mod instanceof Shield\Modules\Base\ModCon ) {
|
1366 |
try {
|
1367 |
$mods = $this->loadCorePluginFeatureHandler()->getActivePluginFeatures();
|
1614 |
*/
|
1615 |
private function buildPrivacyPolicyContent() {
|
1616 |
try {
|
1617 |
+
if ( $this->getModule_SecAdmin()->isEnabledWhitelabel() ) {
|
1618 |
$name = $this->getHumanName();
|
1619 |
$href = $this->getLabels()[ 'PluginURI' ];
|
1620 |
}
|
1653 |
->run();
|
1654 |
}
|
1655 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1656 |
}
|
src/lib/src/Controller/Utilities/CaptureMyUpgrade.php
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Controller\Utilities;
|
4 |
+
|
5 |
+
use FernleafSystems\Utilities\Logic\ExecOnce;
|
6 |
+
use FernleafSystems\Wordpress\Plugin\Shield;
|
7 |
+
|
8 |
+
class CaptureMyUpgrade {
|
9 |
+
|
10 |
+
use Shield\Modules\PluginControllerConsumer;
|
11 |
+
use ExecOnce;
|
12 |
+
|
13 |
+
protected function run() {
|
14 |
+
add_filter( 'upgrader_post_install', [ $this, 'captureMyInstall' ], 10, 2 );
|
15 |
+
add_action( 'upgrader_process_complete', [ $this, 'captureMyUpgrade' ], 10, 2 );
|
16 |
+
}
|
17 |
+
|
18 |
+
public function captureMyInstall( $true, $hooksExtra ) {
|
19 |
+
if ( !empty( $hooksExtra[ 'plugin' ] ) && $hooksExtra['plugin'] === $this->getCon()->base_file ) {
|
20 |
+
$this->getCon()->is_my_upgrade = true;
|
21 |
+
}
|
22 |
+
return $true;
|
23 |
+
}
|
24 |
+
|
25 |
+
public function captureMyUpgrade( $upgradeHandler, $data ) {
|
26 |
+
if ( ( $data[ 'action' ] ?? null === 'update' )
|
27 |
+
&& ( $data[ 'type' ] ?? null === 'plugin' )
|
28 |
+
&& is_array( $data[ 'plugins' ] ?? null ) ) {
|
29 |
+
foreach ( $data[ 'plugins' ] as $item ) {
|
30 |
+
if ( $item === $this->getCon()->root_file ) {
|
31 |
+
$this->getCon()->is_my_upgrade = true;
|
32 |
+
break;
|
33 |
+
}
|
34 |
+
}
|
35 |
+
}
|
36 |
+
}
|
37 |
+
}
|
src/lib/src/Controller/Utilities/DebugMode.php
CHANGED
@@ -37,10 +37,10 @@ class DebugMode {
|
|
37 |
public function isActiveViaModeFile() :bool {
|
38 |
$con = $this->getCon();
|
39 |
$FS = Services::WpFs();
|
40 |
-
$correctPath = $con->
|
41 |
|
42 |
// We first look for the presence of the file (which may not be named in all lower-case)
|
43 |
-
$foundFile = $FS->findFileInDir( 'mode.debug', $con->
|
44 |
if ( !empty( $foundFile )
|
45 |
&& $FS->isFile( $foundFile ) && !$FS->isFile( $correctPath )
|
46 |
&& !basename( $correctPath ) !== basename( $foundFile ) ) {
|
@@ -50,6 +50,6 @@ class DebugMode {
|
|
50 |
}
|
51 |
|
52 |
private function getPathToModeFile() :string {
|
53 |
-
return $this->getCon()->
|
54 |
}
|
55 |
}
|
37 |
public function isActiveViaModeFile() :bool {
|
38 |
$con = $this->getCon();
|
39 |
$FS = Services::WpFs();
|
40 |
+
$correctPath = $con->paths->forFlag( 'mode.debug' );
|
41 |
|
42 |
// We first look for the presence of the file (which may not be named in all lower-case)
|
43 |
+
$foundFile = $FS->findFileInDir( 'mode.debug', $con->paths->forFlag(), false, false );
|
44 |
if ( !empty( $foundFile )
|
45 |
&& $FS->isFile( $foundFile ) && !$FS->isFile( $correctPath )
|
46 |
&& !basename( $correctPath ) !== basename( $foundFile ) ) {
|
50 |
}
|
51 |
|
52 |
private function getPathToModeFile() :string {
|
53 |
+
return $this->getCon()->paths->forFlag( 'mode.debug' );
|
54 |
}
|
55 |
}
|
src/lib/src/Crons/DailyCron.php
CHANGED
@@ -19,18 +19,18 @@ class DailyCron extends BaseCron {
|
|
19 |
}
|
20 |
|
21 |
public function getFirstRunTimestamp() :int {
|
22 |
-
$
|
23 |
-
if ( $
|
24 |
-
$
|
25 |
}
|
26 |
-
$
|
27 |
->carbon( true )
|
28 |
->minute( rand( 1, 59 ) )
|
29 |
->second( 0 );
|
30 |
-
if ( $
|
31 |
-
$
|
32 |
}
|
33 |
-
return $
|
34 |
}
|
35 |
|
36 |
/**
|
19 |
}
|
20 |
|
21 |
public function getFirstRunTimestamp() :int {
|
22 |
+
$hour = (int)apply_filters( 'shield/daily_cron_hour', 7 );
|
23 |
+
if ( $hour < 0 || $hour > 23 ) {
|
24 |
+
$hour = 7;
|
25 |
}
|
26 |
+
$carbon = Services::Request()
|
27 |
->carbon( true )
|
28 |
->minute( rand( 1, 59 ) )
|
29 |
->second( 0 );
|
30 |
+
if ( $carbon->hour >= $hour ) {
|
31 |
+
$carbon->addDays( 1 );
|
32 |
}
|
33 |
+
return $carbon->hour( $hour )->timestamp;
|
34 |
}
|
35 |
|
36 |
/**
|
src/lib/src/Databases/AdminNotes/Handler.php
CHANGED
@@ -2,15 +2,6 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\AdminNotes;
|
4 |
|
5 |
-
|
6 |
|
7 |
-
class Handler extends Base\Handler {
|
8 |
-
|
9 |
-
public function getCustomColumns() :array {
|
10 |
-
return $this->getOptions()->getDef( 'db_notes_table_columns' );
|
11 |
-
}
|
12 |
-
|
13 |
-
protected function getDefaultTableName() :string {
|
14 |
-
return $this->getOptions()->getDef( 'db_notes_name' );
|
15 |
-
}
|
16 |
}
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\AdminNotes;
|
4 |
|
5 |
+
class Handler extends \FernleafSystems\Wordpress\Plugin\Shield\Databases\Base\Handler {
|
6 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
}
|
src/lib/src/Databases/AdminNotes/Insert.php
CHANGED
@@ -14,20 +14,16 @@ class Insert extends Base\Insert {
|
|
14 |
protected function verifyInsertData() {
|
15 |
parent::verifyInsertData();
|
16 |
|
17 |
-
$
|
18 |
-
if ( empty( $
|
19 |
-
$
|
20 |
-
$
|
21 |
}
|
22 |
|
23 |
-
return $this->setInsertData( $
|
24 |
}
|
25 |
|
26 |
-
|
27 |
-
|
28 |
-
* @return bool
|
29 |
-
*/
|
30 |
-
public function create( $sNote ) {
|
31 |
-
return $this->setInsertData( [ 'note' => esc_sql( $sNote ) ] )->query() === 1;
|
32 |
}
|
33 |
}
|
14 |
protected function verifyInsertData() {
|
15 |
parent::verifyInsertData();
|
16 |
|
17 |
+
$data = $this->getInsertData();
|
18 |
+
if ( empty( $data[ 'wp_username' ] ) ) {
|
19 |
+
$username = Services::WpUsers()->getCurrentWpUsername();
|
20 |
+
$data[ 'wp_username' ] = empty( $username ) ? 'unknown' : $username;
|
21 |
}
|
22 |
|
23 |
+
return $this->setInsertData( $data );
|
24 |
}
|
25 |
|
26 |
+
public function create( string $note ) :bool {
|
27 |
+
return $this->setInsertData( [ 'note' => esc_sql( $note ) ] )->query() === 1;
|
|
|
|
|
|
|
|
|
28 |
}
|
29 |
}
|
src/lib/src/Databases/AuditTrail/EntryVO.php
CHANGED
@@ -7,11 +7,10 @@ use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
|
|
7 |
/**
|
8 |
* Class EntryVO
|
9 |
*
|
10 |
-
* @property
|
|
|
11 |
* @property string $message
|
12 |
* @property string $wp_username
|
13 |
-
* @property string $rid
|
14 |
-
* @property string $ip
|
15 |
* @property string $event
|
16 |
* @property string $context
|
17 |
* @property string $category
|
7 |
/**
|
8 |
* Class EntryVO
|
9 |
*
|
10 |
+
* @property int $rid
|
11 |
+
* @property string $ip
|
12 |
* @property string $message
|
13 |
* @property string $wp_username
|
|
|
|
|
14 |
* @property string $event
|
15 |
* @property string $context
|
16 |
* @property string $category
|
src/lib/src/Databases/AuditTrail/Insert.php
CHANGED
@@ -14,18 +14,18 @@ class Insert extends Base\Insert {
|
|
14 |
protected function verifyInsertData() {
|
15 |
parent::verifyInsertData();
|
16 |
|
17 |
-
$
|
18 |
|
19 |
-
if ( is_array( $
|
20 |
-
$
|
21 |
}
|
22 |
-
if ( isset( $
|
23 |
-
$
|
24 |
}
|
25 |
-
if ( empty( $
|
26 |
-
$
|
27 |
}
|
28 |
|
29 |
-
return $this->setInsertData( $
|
30 |
}
|
31 |
}
|
14 |
protected function verifyInsertData() {
|
15 |
parent::verifyInsertData();
|
16 |
|
17 |
+
$data = $this->getInsertData();
|
18 |
|
19 |
+
if ( isset( $data[ 'message' ] ) && is_array( $data[ 'message' ] ) ) {
|
20 |
+
$data[ 'message' ] = implode( ' ', $data[ 'message' ] );
|
21 |
}
|
22 |
+
if ( isset( $data[ 'data' ] ) && !is_string( $data[ 'data' ] ) ) {
|
23 |
+
$data[ 'data' ] = '';
|
24 |
}
|
25 |
+
if ( empty( $data[ 'ip' ] ) || !Services::IP()->isValidIp( $data[ 'ip' ] ) ) {
|
26 |
+
$data[ 'ip' ] = '';
|
27 |
}
|
28 |
|
29 |
+
return $this->setInsertData( $data );
|
30 |
}
|
31 |
}
|
src/lib/src/Databases/AuditTrail/Select.php
CHANGED
@@ -3,11 +3,12 @@
|
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\AuditTrail;
|
4 |
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
|
6 |
-
use FernleafSystems\Wordpress\Plugin\Shield\Utilities\Tool\IpListSort;
|
7 |
use FernleafSystems\Wordpress\Services\Services;
|
8 |
|
9 |
class Select extends Base\Select {
|
10 |
|
|
|
|
|
11 |
/**
|
12 |
* @return string[]
|
13 |
*/
|
@@ -15,13 +16,6 @@ class Select extends Base\Select {
|
|
15 |
return $this->getDistinct_FilterAndSort( 'event' );
|
16 |
}
|
17 |
|
18 |
-
/**
|
19 |
-
* @return string[]
|
20 |
-
*/
|
21 |
-
public function getDistinctIps() {
|
22 |
-
return IpListSort::Sort( $this->getDistinctForColumn( 'ip' ) );
|
23 |
-
}
|
24 |
-
|
25 |
/**
|
26 |
* @return string[]
|
27 |
*/
|
@@ -41,16 +35,24 @@ class Select extends Base\Select {
|
|
41 |
}
|
42 |
|
43 |
/**
|
44 |
-
* @param string $
|
45 |
* @return $this
|
46 |
*/
|
47 |
-
public function filterByIp( $
|
48 |
-
if ( Services::IP()->isValidIp( $
|
49 |
-
$this->addWhereEquals( 'ip', trim( $
|
50 |
}
|
51 |
return $this;
|
52 |
}
|
53 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
/**
|
55 |
* @param string $sIp
|
56 |
* @return $this
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\AuditTrail;
|
4 |
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
|
|
|
6 |
use FernleafSystems\Wordpress\Services\Services;
|
7 |
|
8 |
class Select extends Base\Select {
|
9 |
|
10 |
+
use Base\Traits\Select_IPTable;
|
11 |
+
|
12 |
/**
|
13 |
* @return string[]
|
14 |
*/
|
16 |
return $this->getDistinct_FilterAndSort( 'event' );
|
17 |
}
|
18 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
/**
|
20 |
* @return string[]
|
21 |
*/
|
35 |
}
|
36 |
|
37 |
/**
|
38 |
+
* @param string $ip
|
39 |
* @return $this
|
40 |
*/
|
41 |
+
public function filterByIp( $ip ) {
|
42 |
+
if ( Services::IP()->isValidIp( $ip ) ) {
|
43 |
+
$this->addWhereEquals( 'ip', trim( $ip ) );
|
44 |
}
|
45 |
return $this;
|
46 |
}
|
47 |
|
48 |
+
/**
|
49 |
+
* @param int $id
|
50 |
+
* @return $this
|
51 |
+
*/
|
52 |
+
public function filterByRequestID( int $id ) {
|
53 |
+
return $this->addWhereEquals( 'rid', $id );
|
54 |
+
}
|
55 |
+
|
56 |
/**
|
57 |
* @param string $sIp
|
58 |
* @return $this
|
src/lib/src/Databases/AuditTrail/Update.php
CHANGED
@@ -1,21 +1,17 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\AuditTrail;
|
4 |
|
5 |
-
|
6 |
-
use FernleafSystems\Wordpress\Services\Services;
|
7 |
-
|
8 |
-
class Update extends Base\Update {
|
9 |
|
10 |
/**
|
11 |
-
* @param EntryVO $
|
12 |
-
* @param int $
|
13 |
* @return bool
|
14 |
*/
|
15 |
-
public function updateCount( $
|
16 |
-
return $this->updateEntry( $
|
17 |
-
'count'
|
18 |
-
'updated_at' => Services::Request()->ts()
|
19 |
] );
|
20 |
}
|
21 |
}
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\AuditTrail;
|
4 |
|
5 |
+
class Update extends \FernleafSystems\Wordpress\Plugin\Shield\Databases\Base\Update {
|
|
|
|
|
|
|
6 |
|
7 |
/**
|
8 |
+
* @param EntryVO $entry
|
9 |
+
* @param int $increase
|
10 |
* @return bool
|
11 |
*/
|
12 |
+
public function updateCount( $entry, $increase = 1 ) :bool {
|
13 |
+
return $this->updateEntry( $entry, [
|
14 |
+
'count' => $entry->count + $increase,
|
|
|
15 |
] );
|
16 |
}
|
17 |
}
|
src/lib/src/Databases/Base/BaseQuery.php
CHANGED
@@ -53,13 +53,13 @@ abstract class BaseQuery {
|
|
53 |
}
|
54 |
|
55 |
/**
|
56 |
-
* @param string $
|
57 |
* @param string|array $mValue
|
58 |
-
* @param string $
|
59 |
* @return $this
|
60 |
*/
|
61 |
-
public function addWhere( $
|
62 |
-
if ( !$this->isValidComparisonOperator( $
|
63 |
return $this; // Exception?
|
64 |
}
|
65 |
|
@@ -70,7 +70,7 @@ abstract class BaseQuery {
|
|
70 |
else {
|
71 |
$mValue = esc_sql( $mValue );
|
72 |
|
73 |
-
if ( strcasecmp( $
|
74 |
$mValue = sprintf( '%%%s%%', $mValue );
|
75 |
}
|
76 |
if ( is_string( $mValue ) ) {
|
@@ -78,9 +78,9 @@ abstract class BaseQuery {
|
|
78 |
}
|
79 |
}
|
80 |
|
81 |
-
$
|
82 |
-
$
|
83 |
-
return $this->setWheres( $
|
84 |
}
|
85 |
|
86 |
/**
|
@@ -311,10 +311,7 @@ abstract class BaseQuery {
|
|
311 |
return max( (int)$this->nLimit, 0 );
|
312 |
}
|
313 |
|
314 |
-
|
315 |
-
* @return array
|
316 |
-
*/
|
317 |
-
public function getWheres() {
|
318 |
if ( !is_array( $this->aWheres ) ) {
|
319 |
$this->aWheres = [];
|
320 |
}
|
@@ -446,33 +443,33 @@ abstract class BaseQuery {
|
|
446 |
}
|
447 |
|
448 |
/**
|
449 |
-
* @param array $
|
450 |
* @return $this
|
451 |
*/
|
452 |
-
public function setWheres( $
|
453 |
-
$this->aWheres = $
|
454 |
return $this;
|
455 |
}
|
456 |
|
457 |
/**
|
458 |
-
* @param EntryVO $
|
459 |
* @return $this
|
460 |
*/
|
461 |
-
public function setWheresFromVo( $
|
462 |
-
foreach ( $
|
463 |
-
$this->addWhereEquals( $
|
464 |
}
|
465 |
return $this;
|
466 |
}
|
467 |
|
468 |
/**
|
469 |
* Very basic
|
470 |
-
* @param string $
|
471 |
* @return bool
|
472 |
*/
|
473 |
-
protected function isValidComparisonOperator( $
|
474 |
return in_array(
|
475 |
-
strtoupper( $
|
476 |
[ '=', '<', '>', '!=', '<>', '<=', '>=', '<=>', 'IN', 'LIKE', 'NOT LIKE' ]
|
477 |
);
|
478 |
}
|
53 |
}
|
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 |
|
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 ) ) {
|
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 |
/**
|
311 |
return max( (int)$this->nLimit, 0 );
|
312 |
}
|
313 |
|
314 |
+
public function getWheres() :array {
|
|
|
|
|
|
|
315 |
if ( !is_array( $this->aWheres ) ) {
|
316 |
$this->aWheres = [];
|
317 |
}
|
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 |
|
454 |
/**
|
455 |
+
* @param EntryVO $VO
|
456 |
* @return $this
|
457 |
*/
|
458 |
+
public function setWheresFromVo( $VO ) {
|
459 |
+
foreach ( $VO->getRawData() as $col => $mVal ) {
|
460 |
+
$this->addWhereEquals( $col, $mVal );
|
461 |
}
|
462 |
return $this;
|
463 |
}
|
464 |
|
465 |
/**
|
466 |
* Very basic
|
467 |
+
* @param string $op
|
468 |
* @return bool
|
469 |
*/
|
470 |
+
protected function isValidComparisonOperator( $op ) {
|
471 |
return in_array(
|
472 |
+
strtoupper( $op ),
|
473 |
[ '=', '<', '>', '!=', '<>', '<=', '>=', '<=>', 'IN', 'LIKE', 'NOT LIKE' ]
|
474 |
);
|
475 |
}
|
src/lib/src/Databases/Base/Delete.php
CHANGED
@@ -32,14 +32,14 @@ class Delete extends BaseQuery {
|
|
32 |
|
33 |
/**
|
34 |
* NOTE: Does not reset() before query, so may be customized with where.
|
35 |
-
* @param int $
|
36 |
-
* @param string $
|
37 |
* @param bool $bOldestFirst
|
38 |
* @return int
|
39 |
* @throws \Exception
|
40 |
*/
|
41 |
-
public function deleteExcess( $
|
42 |
-
if ( is_null( $
|
43 |
throw new \Exception( 'Max Entries not specified for table excess delete.' );
|
44 |
}
|
45 |
|
@@ -50,10 +50,10 @@ class Delete extends BaseQuery {
|
|
50 |
->getQuerySelector()
|
51 |
->setWheres( $this->getWheres() )
|
52 |
->count();
|
53 |
-
$nToDelete = $nTotal - $
|
54 |
|
55 |
if ( $nToDelete > 0 ) {
|
56 |
-
$nEntriesDeleted = $this->setOrderBy( $
|
57 |
->setLimit( $nToDelete )
|
58 |
->query();
|
59 |
}
|
32 |
|
33 |
/**
|
34 |
* NOTE: Does not reset() before query, so may be customized with where.
|
35 |
+
* @param int $maxEntries
|
36 |
+
* @param string $orderByColumn
|
37 |
* @param bool $bOldestFirst
|
38 |
* @return int
|
39 |
* @throws \Exception
|
40 |
*/
|
41 |
+
public function deleteExcess( $maxEntries, $orderByColumn = 'created_at', $bOldestFirst = true ) {
|
42 |
+
if ( is_null( $maxEntries ) ) {
|
43 |
throw new \Exception( 'Max Entries not specified for table excess delete.' );
|
44 |
}
|
45 |
|
50 |
->getQuerySelector()
|
51 |
->setWheres( $this->getWheres() )
|
52 |
->count();
|
53 |
+
$nToDelete = $nTotal - $maxEntries;
|
54 |
|
55 |
if ( $nToDelete > 0 ) {
|
56 |
+
$nEntriesDeleted = $this->setOrderBy( $orderByColumn, $bOldestFirst ? 'ASC' : 'DESC' )
|
57 |
->setLimit( $nToDelete )
|
58 |
->query();
|
59 |
}
|
src/lib/src/Databases/Base/EntryVO.php
CHANGED
@@ -1,8 +1,8 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Data\Adapter\
|
6 |
|
7 |
/**
|
8 |
* Class BaseEntryVO
|
@@ -12,40 +12,32 @@ use FernleafSystems\Utilities\Data\Adapter\StdClassAdapter;
|
|
12 |
* @property int $created_at
|
13 |
* @property int $deleted_at
|
14 |
*/
|
15 |
-
class EntryVO {
|
16 |
|
17 |
-
|
18 |
-
|
19 |
-
__set as __adapterSet;
|
20 |
}
|
21 |
|
22 |
/**
|
23 |
-
* @param
|
24 |
-
*/
|
25 |
-
public function __construct( $aRow = null ) {
|
26 |
-
$this->applyFromArray( $aRow );
|
27 |
-
}
|
28 |
-
|
29 |
-
/**
|
30 |
-
* @param string $sProperty
|
31 |
* @return mixed
|
32 |
*/
|
33 |
-
public function __get( $
|
34 |
|
35 |
-
$
|
36 |
|
37 |
-
switch ( $
|
38 |
|
39 |
case 'meta':
|
40 |
-
if ( is_string( $
|
41 |
-
$
|
42 |
-
if ( !empty( $
|
43 |
-
$
|
44 |
}
|
45 |
}
|
46 |
|
47 |
-
if ( !is_array( $
|
48 |
-
$
|
49 |
}
|
50 |
break;
|
51 |
|
@@ -53,50 +45,46 @@ class EntryVO {
|
|
53 |
break;
|
54 |
}
|
55 |
|
56 |
-
|
|
|
|
|
|
|
|
|
57 |
}
|
58 |
|
59 |
/**
|
60 |
-
* @param string $
|
61 |
-
* @param mixed $
|
62 |
-
* @return $this|mixed
|
63 |
*/
|
64 |
-
public function __set( $
|
65 |
|
66 |
-
switch ( $
|
67 |
|
68 |
case 'meta':
|
69 |
-
if ( !is_array( $
|
70 |
-
$
|
71 |
}
|
72 |
-
$
|
73 |
break;
|
74 |
|
75 |
default:
|
76 |
break;
|
77 |
}
|
78 |
|
79 |
-
|
80 |
}
|
81 |
|
82 |
-
|
83 |
-
* @return int
|
84 |
-
*/
|
85 |
-
public function getCreatedAt() {
|
86 |
return (int)$this->created_at;
|
87 |
}
|
88 |
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
return (int)$this->created_at;
|
94 |
}
|
95 |
|
96 |
-
|
97 |
-
* @return bool
|
98 |
-
*/
|
99 |
-
public function isDeleted() {
|
100 |
return $this->deleted_at > 0;
|
101 |
}
|
102 |
}
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
|
6 |
|
7 |
/**
|
8 |
* Class BaseEntryVO
|
12 |
* @property int $created_at
|
13 |
* @property int $deleted_at
|
14 |
*/
|
15 |
+
class EntryVO extends DynPropertiesClass {
|
16 |
|
17 |
+
public function __construct( array $row = [] ) {
|
18 |
+
$this->applyFromArray( $row );
|
|
|
19 |
}
|
20 |
|
21 |
/**
|
22 |
+
* @param string $key
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
* @return mixed
|
24 |
*/
|
25 |
+
public function __get( string $key ) {
|
26 |
|
27 |
+
$value = parent::__get( $key );
|
28 |
|
29 |
+
switch ( $key ) {
|
30 |
|
31 |
case 'meta':
|
32 |
+
if ( is_string( $value ) && !empty( $value ) ) {
|
33 |
+
$value = base64_decode( $value );
|
34 |
+
if ( !empty( $value ) ) {
|
35 |
+
$value = @json_decode( $value, true );
|
36 |
}
|
37 |
}
|
38 |
|
39 |
+
if ( !is_array( $value ) ) {
|
40 |
+
$value = [];
|
41 |
}
|
42 |
break;
|
43 |
|
45 |
break;
|
46 |
}
|
47 |
|
48 |
+
if ( preg_match( '#^.*_at$#i', $key ) ) {
|
49 |
+
$value = (int)$value;
|
50 |
+
}
|
51 |
+
|
52 |
+
return $value;
|
53 |
}
|
54 |
|
55 |
/**
|
56 |
+
* @param string $key
|
57 |
+
* @param mixed $value
|
|
|
58 |
*/
|
59 |
+
public function __set( string $key, $value ) {
|
60 |
|
61 |
+
switch ( $key ) {
|
62 |
|
63 |
case 'meta':
|
64 |
+
if ( !is_array( $value ) ) {
|
65 |
+
$value = [];
|
66 |
}
|
67 |
+
$value = base64_encode( json_encode( $value ) );
|
68 |
break;
|
69 |
|
70 |
default:
|
71 |
break;
|
72 |
}
|
73 |
|
74 |
+
parent::__set( $key, $value );
|
75 |
}
|
76 |
|
77 |
+
public function getCreatedAt() :int {
|
|
|
|
|
|
|
78 |
return (int)$this->created_at;
|
79 |
}
|
80 |
|
81 |
+
public function getHash() :string {
|
82 |
+
$data = $this->getRawData();
|
83 |
+
asort( $data );
|
84 |
+
return md5( serialize( $data ) );
|
|
|
85 |
}
|
86 |
|
87 |
+
public function isDeleted() :bool {
|
|
|
|
|
|
|
88 |
return $this->deleted_at > 0;
|
89 |
}
|
90 |
}
|
src/lib/src/Databases/Base/Handler.php
CHANGED
@@ -2,6 +2,7 @@
|
|
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\ModConsumer;
|
@@ -14,6 +15,7 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
14 |
abstract class Handler {
|
15 |
|
16 |
use ModConsumer;
|
|
|
17 |
|
18 |
/**
|
19 |
* @var string
|
@@ -25,41 +27,111 @@ abstract class Handler {
|
|
25 |
*/
|
26 |
private $bIsReady;
|
27 |
|
28 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
}
|
30 |
|
31 |
-
|
|
|
|
|
|
|
|
|
32 |
}
|
33 |
|
34 |
/**
|
35 |
-
* @param int $nAutoExpireDays
|
36 |
* @return $this
|
|
|
37 |
*/
|
38 |
-
public function
|
39 |
-
|
40 |
-
|
41 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
}
|
43 |
return $this;
|
44 |
}
|
45 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
/**
|
47 |
-
* @param int $
|
48 |
* @return bool
|
49 |
*/
|
50 |
-
public function deleteRowsOlderThan( $
|
51 |
-
return $this->isReady() &&
|
52 |
-
|
53 |
-
|
|
|
54 |
}
|
55 |
|
56 |
public function getTable() :string {
|
57 |
return Services::WpDb()->getPrefix()
|
58 |
-
.esc_sql( $this->getCon()->prefixOption( $this->
|
59 |
}
|
60 |
|
61 |
/**
|
62 |
* @return string
|
|
|
63 |
*/
|
64 |
protected function getTableSlug() {
|
65 |
return empty( $this->sTable ) ? $this->getDefaultTableName() : $this->sTable;
|
@@ -69,19 +141,27 @@ abstract class Handler {
|
|
69 |
* @return Insert|mixed
|
70 |
*/
|
71 |
public function getQueryInserter() {
|
72 |
-
$
|
73 |
/** @var Insert $o */
|
74 |
-
$o = new $
|
75 |
return $o->setDbH( $this );
|
76 |
}
|
77 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
78 |
/**
|
79 |
* @return Delete|mixed
|
80 |
*/
|
81 |
public function getQueryDeleter() {
|
82 |
-
$
|
83 |
/** @var Delete $o */
|
84 |
-
$o = new $
|
85 |
return $o->setDbH( $this );
|
86 |
}
|
87 |
|
@@ -89,9 +169,9 @@ abstract class Handler {
|
|
89 |
* @return Select|mixed
|
90 |
*/
|
91 |
public function getQuerySelector() {
|
92 |
-
$
|
93 |
/** @var Select $o */
|
94 |
-
$o = new $
|
95 |
return $o->setDbH( $this )
|
96 |
->setResultsAsVo( true );
|
97 |
}
|
@@ -100,9 +180,9 @@ abstract class Handler {
|
|
100 |
* @return Update|mixed
|
101 |
*/
|
102 |
public function getQueryUpdater() {
|
103 |
-
$
|
104 |
/** @var Update $o */
|
105 |
-
$o = new $
|
106 |
return $o->setDbH( $this );
|
107 |
}
|
108 |
|
@@ -110,10 +190,15 @@ abstract class Handler {
|
|
110 |
* @return EntryVO|mixed
|
111 |
*/
|
112 |
public function getVo() {
|
113 |
-
$
|
114 |
-
return new $
|
115 |
}
|
116 |
|
|
|
|
|
|
|
|
|
|
|
117 |
public function hasColumn( string $col ) :bool {
|
118 |
return in_array( strtolower( $col ), $this->getTableSchema()->getColumnNames() );
|
119 |
}
|
@@ -140,33 +225,13 @@ abstract class Handler {
|
|
140 |
return $mResult !== false;
|
141 |
}
|
142 |
|
143 |
-
|
144 |
-
* @return bool
|
145 |
-
*/
|
146 |
-
public function tableExists() {
|
147 |
return Services::WpDb()->getIfTableExists( $this->getTable() );
|
148 |
}
|
149 |
|
150 |
-
|
151 |
-
* @return $this
|
152 |
-
* @throws \Exception
|
153 |
-
*/
|
154 |
-
public function tableInit() {
|
155 |
-
if ( !$this->isReady() ) {
|
156 |
-
|
157 |
-
$this->tableCreate();
|
158 |
-
|
159 |
-
if ( !$this->isReady( true ) ) {
|
160 |
-
$this->tableDelete();
|
161 |
-
$this->tableCreate();
|
162 |
-
}
|
163 |
-
}
|
164 |
-
return $this;
|
165 |
-
}
|
166 |
-
|
167 |
-
public function tableTrimExcess( int $nRowsLimit ) :self {
|
168 |
try {
|
169 |
-
$this->getQueryDeleter()->deleteExcess( $
|
170 |
}
|
171 |
catch ( \Exception $e ) {
|
172 |
}
|
@@ -174,11 +239,11 @@ abstract class Handler {
|
|
174 |
}
|
175 |
|
176 |
/**
|
177 |
-
* @param bool $
|
178 |
* @return bool
|
179 |
*/
|
180 |
-
public function isReady( $
|
181 |
-
if ( $
|
182 |
$this->reset();
|
183 |
}
|
184 |
|
@@ -196,17 +261,13 @@ abstract class Handler {
|
|
196 |
return $this->bIsReady;
|
197 |
}
|
198 |
|
199 |
-
public function setTable( string $sTable ) :self {
|
200 |
-
$this->sTable = $sTable;
|
201 |
-
return $this;
|
202 |
-
}
|
203 |
-
|
204 |
protected function getDefaultTableName() :string {
|
205 |
-
|
206 |
}
|
207 |
|
208 |
/**
|
209 |
* @return string[]
|
|
|
210 |
*/
|
211 |
protected function getCustomColumns() :array {
|
212 |
return [];
|
@@ -214,17 +275,22 @@ abstract class Handler {
|
|
214 |
|
215 |
/**
|
216 |
* @return string[]
|
|
|
217 |
*/
|
218 |
protected function getTimestampColumns() :array {
|
219 |
return [];
|
220 |
}
|
221 |
|
222 |
public function getTableSchema() :TableSchema {
|
223 |
-
$
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
|
|
|
|
|
|
|
|
228 |
}
|
229 |
|
230 |
private function getNamespace() :string {
|
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;
|
15 |
abstract class Handler {
|
16 |
|
17 |
use ModConsumer;
|
18 |
+
use ExecOnce;
|
19 |
|
20 |
/**
|
21 |
* @var string
|
27 |
*/
|
28 |
private $bIsReady;
|
29 |
|
30 |
+
/**
|
31 |
+
* @var string
|
32 |
+
*/
|
33 |
+
protected $slug;
|
34 |
+
|
35 |
+
/**
|
36 |
+
* @var TableSchema
|
37 |
+
*/
|
38 |
+
protected $schema;
|
39 |
+
|
40 |
+
public function __construct( $slug = '' ) {
|
41 |
+
$this->slug = $slug;
|
42 |
}
|
43 |
|
44 |
+
/**
|
45 |
+
* @throws \Exception
|
46 |
+
*/
|
47 |
+
protected function run() {
|
48 |
+
$this->tableInit();
|
49 |
}
|
50 |
|
51 |
/**
|
|
|
52 |
* @return $this
|
53 |
+
* @throws \Exception
|
54 |
*/
|
55 |
+
public function tableInit() {
|
56 |
+
|
57 |
+
$this->setupTableSchema();
|
58 |
+
|
59 |
+
if ( !$this->isReady() ) {
|
60 |
+
|
61 |
+
$this->tableCreate();
|
62 |
+
|
63 |
+
if ( !$this->isReady( true ) ) {
|
64 |
+
$this->tableDelete();
|
65 |
+
$this->tableCreate();
|
66 |
+
}
|
67 |
}
|
68 |
return $this;
|
69 |
}
|
70 |
|
71 |
+
private function setupTableSchema() :TableSchema {
|
72 |
+
$this->schema = new TableSchema();
|
73 |
+
|
74 |
+
$spec = $this->getOptions()->getDef( 'db_table_'.$this->slug );
|
75 |
+
|
76 |
+
if ( empty( $spec ) ) {
|
77 |
+
$this->schema->slug = $this->slug;
|
78 |
+
$this->schema->primary_key = 'id';
|
79 |
+
$this->schema->cols_custom = $this->getCustomColumns();
|
80 |
+
$this->schema->cols_timestamps = $this->getTimestampColumns();
|
81 |
+
$this->schema->autoexpire = 0;
|
82 |
+
}
|
83 |
+
else {
|
84 |
+
$this->schema->applyFromArray( array_merge(
|
85 |
+
[
|
86 |
+
'slug' => $this->slug,
|
87 |
+
'primary_key' => 'id',
|
88 |
+
'cols_custom' => [],
|
89 |
+
'cols_timestamps' => [],
|
90 |
+
'has_updated_at' => false,
|
91 |
+
'col_older_than' => 'created_at',
|
92 |
+
'autoexpire' => 0,
|
93 |
+
'has_ip_col' => false,
|
94 |
+
],
|
95 |
+
$spec
|
96 |
+
) );
|
97 |
+
}
|
98 |
+
|
99 |
+
$this->schema->table = $this->getTable();
|
100 |
+
return $this->schema;
|
101 |
+
}
|
102 |
+
|
103 |
+
public function autoCleanDb() {
|
104 |
+
}
|
105 |
+
|
106 |
+
public function tableCleanExpired( int $autoExpireDays ) {
|
107 |
+
if ( $autoExpireDays > 0 ) {
|
108 |
+
$this->deleteRowsOlderThan( Services::Request()->ts() - $autoExpireDays*DAY_IN_SECONDS );
|
109 |
+
}
|
110 |
+
}
|
111 |
+
|
112 |
+
protected function getColumnForOlderThanComparison() :string {
|
113 |
+
return 'created_at';
|
114 |
+
}
|
115 |
+
|
116 |
/**
|
117 |
+
* @param int $timestamp
|
118 |
* @return bool
|
119 |
*/
|
120 |
+
public function deleteRowsOlderThan( $timestamp ) :bool {
|
121 |
+
return $this->isReady() &&
|
122 |
+
$this->getQueryDeleter()
|
123 |
+
->addWhereOlderThan( $timestamp, $this->getTableSchema()->col_older_than ?? 'created_at' )
|
124 |
+
->query();
|
125 |
}
|
126 |
|
127 |
public function getTable() :string {
|
128 |
return Services::WpDb()->getPrefix()
|
129 |
+
.esc_sql( $this->getCon()->prefixOption( $this->getDefaultTableName() ) );
|
130 |
}
|
131 |
|
132 |
/**
|
133 |
* @return string
|
134 |
+
* @deprecated 10.3
|
135 |
*/
|
136 |
protected function getTableSlug() {
|
137 |
return empty( $this->sTable ) ? $this->getDefaultTableName() : $this->sTable;
|
141 |
* @return Insert|mixed
|
142 |
*/
|
143 |
public function getQueryInserter() {
|
144 |
+
$class = $this->getNamespace().'Insert';
|
145 |
/** @var Insert $o */
|
146 |
+
$o = new $class();
|
147 |
return $o->setDbH( $this );
|
148 |
}
|
149 |
|
150 |
+
/**
|
151 |
+
* @return Iterator
|
152 |
+
*/
|
153 |
+
public function getIterator() {
|
154 |
+
$o = new Iterator();
|
155 |
+
return $o->setDbHandler( $this );
|
156 |
+
}
|
157 |
+
|
158 |
/**
|
159 |
* @return Delete|mixed
|
160 |
*/
|
161 |
public function getQueryDeleter() {
|
162 |
+
$class = $this->getNamespace().'Delete';
|
163 |
/** @var Delete $o */
|
164 |
+
$o = new $class();
|
165 |
return $o->setDbH( $this );
|
166 |
}
|
167 |
|
169 |
* @return Select|mixed
|
170 |
*/
|
171 |
public function getQuerySelector() {
|
172 |
+
$class = $this->getNamespace().'Select';
|
173 |
/** @var Select $o */
|
174 |
+
$o = new $class();
|
175 |
return $o->setDbH( $this )
|
176 |
->setResultsAsVo( true );
|
177 |
}
|
180 |
* @return Update|mixed
|
181 |
*/
|
182 |
public function getQueryUpdater() {
|
183 |
+
$class = $this->getNamespace().'Update';
|
184 |
/** @var Update $o */
|
185 |
+
$o = new $class();
|
186 |
return $o->setDbH( $this );
|
187 |
}
|
188 |
|
190 |
* @return EntryVO|mixed
|
191 |
*/
|
192 |
public function getVo() {
|
193 |
+
$class = $this->getNamespace().'EntryVO';
|
194 |
+
return new $class();
|
195 |
}
|
196 |
|
197 |
+
/**
|
198 |
+
* @param string $col
|
199 |
+
* @return bool
|
200 |
+
* @deprecated 10.3 - moved to schema
|
201 |
+
*/
|
202 |
public function hasColumn( string $col ) :bool {
|
203 |
return in_array( strtolower( $col ), $this->getTableSchema()->getColumnNames() );
|
204 |
}
|
225 |
return $mResult !== false;
|
226 |
}
|
227 |
|
228 |
+
public function tableExists() :bool {
|
|
|
|
|
|
|
229 |
return Services::WpDb()->getIfTableExists( $this->getTable() );
|
230 |
}
|
231 |
|
232 |
+
public function tableTrimExcess( int $rowsLimit ) :self {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
233 |
try {
|
234 |
+
$this->getQueryDeleter()->deleteExcess( $rowsLimit );
|
235 |
}
|
236 |
catch ( \Exception $e ) {
|
237 |
}
|
239 |
}
|
240 |
|
241 |
/**
|
242 |
+
* @param bool $reTest
|
243 |
* @return bool
|
244 |
*/
|
245 |
+
public function isReady( bool $reTest = false ) {
|
246 |
+
if ( $reTest ) {
|
247 |
$this->reset();
|
248 |
}
|
249 |
|
261 |
return $this->bIsReady;
|
262 |
}
|
263 |
|
|
|
|
|
|
|
|
|
|
|
264 |
protected function getDefaultTableName() :string {
|
265 |
+
return $this->getTableSchema()->slug;
|
266 |
}
|
267 |
|
268 |
/**
|
269 |
* @return string[]
|
270 |
+
* @deprecated 10.3
|
271 |
*/
|
272 |
protected function getCustomColumns() :array {
|
273 |
return [];
|
275 |
|
276 |
/**
|
277 |
* @return string[]
|
278 |
+
* @deprecated 10.3
|
279 |
*/
|
280 |
protected function getTimestampColumns() :array {
|
281 |
return [];
|
282 |
}
|
283 |
|
284 |
public function getTableSchema() :TableSchema {
|
285 |
+
if ( empty( $this->schema ) ) { // TODO: Delete empty test after 10.3
|
286 |
+
$sch = new TableSchema();
|
287 |
+
$sch->table = $this->getTable();
|
288 |
+
$sch->col_older_than = 'created_at';
|
289 |
+
$sch->cols_custom = $this->getCustomColumns();
|
290 |
+
$sch->cols_timestamps = $this->getTimestampColumns();
|
291 |
+
return $sch;
|
292 |
+
}
|
293 |
+
return $this->schema;
|
294 |
}
|
295 |
|
296 |
private function getNamespace() :string {
|
src/lib/src/Databases/Base/Insert.php
CHANGED
@@ -12,20 +12,20 @@ class Insert extends BaseQuery {
|
|
12 |
protected $aInsertData;
|
13 |
|
14 |
public function getInsertData() :array {
|
15 |
-
$dbh = $this->getDbH();
|
16 |
-
$cols = $dbh->getTableSchema()->getColumnNames();
|
17 |
return array_intersect_key(
|
18 |
is_array( $this->aInsertData ) ? $this->aInsertData : [],
|
19 |
-
array_flip( $
|
20 |
);
|
21 |
}
|
22 |
|
23 |
/**
|
24 |
-
* @param EntryVO $
|
25 |
* @return bool
|
26 |
*/
|
27 |
-
public function insert( $
|
28 |
-
|
|
|
|
|
29 |
}
|
30 |
|
31 |
/**
|
@@ -34,12 +34,8 @@ class Insert extends BaseQuery {
|
|
34 |
* @return $this
|
35 |
*/
|
36 |
protected function setInsertData( $data ) {
|
37 |
-
if ( !is_array( $data ) ) {
|
38 |
-
$data = [];
|
39 |
-
}
|
40 |
-
|
41 |
$this->aInsertData = array_intersect_key(
|
42 |
-
$data,
|
43 |
array_flip( $this->getDbH()->getTableSchema()->getColumnNames() )
|
44 |
);
|
45 |
return $this;
|
@@ -50,20 +46,11 @@ class Insert extends BaseQuery {
|
|
50 |
* @throws \Exception
|
51 |
*/
|
52 |
protected function verifyInsertData() {
|
53 |
-
$
|
54 |
-
|
55 |
-
|
56 |
-
$aData = [];
|
57 |
}
|
58 |
-
$
|
59 |
-
[ 'created_at' => Services::Request()->ts(), ],
|
60 |
-
$aData
|
61 |
-
);
|
62 |
-
if ( !isset( $aData[ 'updated_at' ] ) && $this->getDbH()->hasColumn( 'updated_at' ) ) {
|
63 |
-
$aData[ 'updated_at' ] = Services::Request()->ts();
|
64 |
-
}
|
65 |
-
|
66 |
-
return $this->setInsertData( $aData );
|
67 |
}
|
68 |
|
69 |
/**
|
12 |
protected $aInsertData;
|
13 |
|
14 |
public function getInsertData() :array {
|
|
|
|
|
15 |
return array_intersect_key(
|
16 |
is_array( $this->aInsertData ) ? $this->aInsertData : [],
|
17 |
+
array_flip( $this->getDbH()->getTableSchema()->getColumnNames() )
|
18 |
);
|
19 |
}
|
20 |
|
21 |
/**
|
22 |
+
* @param EntryVO $entry
|
23 |
* @return bool
|
24 |
*/
|
25 |
+
public function insert( $entry ) :bool {
|
26 |
+
// @deprecated 10.3- get rid of casting after moving filelockerVO to normal VO
|
27 |
+
$data = (array)$entry->getRawData();
|
28 |
+
return $this->setInsertData( $data )->query() === 1;
|
29 |
}
|
30 |
|
31 |
/**
|
34 |
* @return $this
|
35 |
*/
|
36 |
protected function setInsertData( $data ) {
|
|
|
|
|
|
|
|
|
37 |
$this->aInsertData = array_intersect_key(
|
38 |
+
is_array( $data ) ? $data : [],
|
39 |
array_flip( $this->getDbH()->getTableSchema()->getColumnNames() )
|
40 |
);
|
41 |
return $this;
|
46 |
* @throws \Exception
|
47 |
*/
|
48 |
protected function verifyInsertData() {
|
49 |
+
$baseData = [ 'created_at' => Services::Request()->ts() ];
|
50 |
+
if ( $this->getDbH()->hasColumn( 'updated_at' ) ) {
|
51 |
+
$baseData[ 'updated_at' ] = Services::Request()->ts();
|
|
|
52 |
}
|
53 |
+
return $this->setInsertData( array_merge( $baseData, $this->getInsertData() ) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
}
|
55 |
|
56 |
/**
|
src/lib/src/Databases/Base/Iterator.php
ADDED
@@ -0,0 +1,111 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
|
4 |
+
|
5 |
+
use Elliotchance\Iterator\AbstractPagedIterator;
|
6 |
+
|
7 |
+
class Iterator extends AbstractPagedIterator {
|
8 |
+
|
9 |
+
const PAGE_LIMIT = 50;
|
10 |
+
use HandlerConsumer;
|
11 |
+
|
12 |
+
/**
|
13 |
+
* @var Select|mixed
|
14 |
+
*/
|
15 |
+
private $selector;
|
16 |
+
|
17 |
+
/**
|
18 |
+
* @var int
|
19 |
+
*/
|
20 |
+
private $totalSize;
|
21 |
+
|
22 |
+
/**
|
23 |
+
* @var array
|
24 |
+
*/
|
25 |
+
private $customFilters = [];
|
26 |
+
|
27 |
+
/**
|
28 |
+
* @return EntryVO|mixed|null
|
29 |
+
*/
|
30 |
+
public function current() {
|
31 |
+
return parent::current();
|
32 |
+
}
|
33 |
+
|
34 |
+
public function getCustomQueryFilters() :array {
|
35 |
+
return is_array( $this->customFilters ) ? $this->customFilters : [];
|
36 |
+
}
|
37 |
+
|
38 |
+
protected function getDefaultQueryFilters() :array {
|
39 |
+
return [
|
40 |
+
'orderby' => 'id',
|
41 |
+
'order' => 'ASC',
|
42 |
+
];
|
43 |
+
}
|
44 |
+
|
45 |
+
protected function getFinalQueryFilters() :array {
|
46 |
+
return array_merge( $this->getDefaultQueryFilters(), $this->getCustomQueryFilters() );
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
* @param int $nPage - always starts at 0
|
51 |
+
* @return array
|
52 |
+
*/
|
53 |
+
public function getPage( $nPage ) {
|
54 |
+
$aParams = $this->getFinalQueryFilters();
|
55 |
+
|
56 |
+
$this->getSelector()
|
57 |
+
->setResultsAsVo( true )
|
58 |
+
->setPage( $nPage + 1 ) // Pages start at 1, not zero.
|
59 |
+
->setLimit( $this->getPageSize() )
|
60 |
+
->setOrderBy( $aParams[ 'orderby' ], $aParams[ 'order' ] );
|
61 |
+
|
62 |
+
return $this->runQuery();
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* @return int
|
67 |
+
*/
|
68 |
+
public function getPageSize() {
|
69 |
+
return static::PAGE_LIMIT;
|
70 |
+
}
|
71 |
+
|
72 |
+
/**
|
73 |
+
* @return Select|mixed
|
74 |
+
*/
|
75 |
+
public function getSelector() {
|
76 |
+
if ( empty( $this->selector ) ) {
|
77 |
+
$this->selector = $this->getDbHandler()->getQuerySelector();
|
78 |
+
}
|
79 |
+
return $this->selector;
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* @return int
|
84 |
+
*/
|
85 |
+
public function getTotalSize() {
|
86 |
+
if ( !isset( $this->totalSize ) ) {
|
87 |
+
$this->totalSize = $this->runQueryCount();
|
88 |
+
}
|
89 |
+
return $this->totalSize;
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* @return EntryVO[]|mixed[]
|
94 |
+
*/
|
95 |
+
protected function runQuery() {
|
96 |
+
return ( clone $this->getSelector() )->query();
|
97 |
+
}
|
98 |
+
|
99 |
+
protected function runQueryCount() :int {
|
100 |
+
return (int)( clone $this->getSelector() )->count();
|
101 |
+
}
|
102 |
+
|
103 |
+
/**
|
104 |
+
* @param Select|mixed $selector
|
105 |
+
* @return $this
|
106 |
+
*/
|
107 |
+
public function setSelector( $selector ) {
|
108 |
+
$this->selector = $selector;
|
109 |
+
return $this;
|
110 |
+
}
|
111 |
+
}
|
src/lib/src/Databases/Base/Traits/Select_IPTable.php
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\Base\Traits;
|
4 |
+
|
5 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Utilities\Tool\IpListSort;
|
6 |
+
|
7 |
+
trait Select_IPTable {
|
8 |
+
|
9 |
+
/**
|
10 |
+
* @return string[]
|
11 |
+
*/
|
12 |
+
public function getDistinctIps() :array {
|
13 |
+
$ips = $this->getDistinctForColumn( 'ip' );
|
14 |
+
if ( $this->getDbH()->getTableSchema()->is_ip_binary ) {
|
15 |
+
$ips = array_map(
|
16 |
+
function ( $binaryIP ) {
|
17 |
+
return inet_ntop( $binaryIP );
|
18 |
+
},
|
19 |
+
$ips
|
20 |
+
);
|
21 |
+
}
|
22 |
+
return IpListSort::Sort( $ips );
|
23 |
+
}
|
24 |
+
}
|
src/lib/src/Databases/Base/Update.php
CHANGED
@@ -26,11 +26,11 @@ class Update extends Insert {
|
|
26 |
}
|
27 |
|
28 |
/**
|
29 |
-
* @param array $
|
30 |
* @return $this
|
31 |
*/
|
32 |
-
public function setUpdateData( $
|
33 |
-
return $this->setInsertData( $
|
34 |
}
|
35 |
|
36 |
/**
|
@@ -52,44 +52,52 @@ class Update extends Insert {
|
|
52 |
}
|
53 |
|
54 |
/**
|
55 |
-
* @param EntryVO $
|
56 |
-
* @param array $
|
57 |
* @return bool
|
58 |
*/
|
59 |
-
public function updateEntry( $
|
60 |
$success = false;
|
61 |
|
62 |
-
if ( $
|
63 |
-
|
64 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
65 |
}
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
|
|
|
|
71 |
}
|
72 |
}
|
73 |
}
|
|
|
74 |
return $success;
|
75 |
}
|
76 |
|
77 |
/**
|
78 |
-
* @param int $
|
79 |
-
* @param array $
|
80 |
* @return bool true is success or no update necessary
|
81 |
*/
|
82 |
-
public function updateById( $
|
83 |
-
$
|
84 |
-
|
85 |
-
if ( !empty( $
|
86 |
-
$
|
87 |
-
|
88 |
-
|
89 |
-
->query();
|
90 |
-
$bSuccess = $mResult === 1;
|
91 |
}
|
92 |
-
return $
|
93 |
}
|
94 |
|
95 |
/**
|
26 |
}
|
27 |
|
28 |
/**
|
29 |
+
* @param array $data
|
30 |
* @return $this
|
31 |
*/
|
32 |
+
public function setUpdateData( $data ) {
|
33 |
+
return $this->setInsertData( $data );
|
34 |
}
|
35 |
|
36 |
/**
|
52 |
}
|
53 |
|
54 |
/**
|
55 |
+
* @param EntryVO $entry
|
56 |
+
* @param array $updateData
|
57 |
* @return bool
|
58 |
*/
|
59 |
+
public function updateEntry( $entry, $updateData = [] ) :bool {
|
60 |
$success = false;
|
61 |
|
62 |
+
if ( $entry instanceof EntryVO ) {
|
63 |
+
|
64 |
+
foreach ( (array)$entry->getRawData() as $key => $value ) {
|
65 |
+
if ( isset( $updateData[ $key ] ) && $updateData[ $key ] === $value ) {
|
66 |
+
unset( $updateData[ $key ] );
|
67 |
+
}
|
68 |
+
}
|
69 |
+
|
70 |
+
if ( empty( $updateData ) ) {
|
71 |
+
$success = true;
|
72 |
}
|
73 |
+
else {
|
74 |
+
if ( $this->getDbH()->hasColumn( 'updated_at' ) && !isset( $updateData[ 'updated_at' ] ) ) {
|
75 |
+
$updateData[ 'updated_at' ] = Services::Request()->ts();
|
76 |
+
}
|
77 |
+
if ( $this->updateById( $entry->id, $updateData ) ) {
|
78 |
+
$entry->applyFromArray( array_merge( (array)$entry->getRawData(), $updateData ) );
|
79 |
+
$success = true;
|
80 |
}
|
81 |
}
|
82 |
}
|
83 |
+
|
84 |
return $success;
|
85 |
}
|
86 |
|
87 |
/**
|
88 |
+
* @param int $id
|
89 |
+
* @param array $updateData
|
90 |
* @return bool true is success or no update necessary
|
91 |
*/
|
92 |
+
public function updateById( $id, $updateData = [] ) {
|
93 |
+
$success = true;
|
94 |
+
|
95 |
+
if ( !empty( $updateData ) ) {
|
96 |
+
$success = $this->setUpdateId( $id )
|
97 |
+
->setUpdateData( $updateData )
|
98 |
+
->query() === 1;
|
|
|
|
|
99 |
}
|
100 |
+
return $success;
|
101 |
}
|
102 |
|
103 |
/**
|
src/lib/src/Databases/BotSignals/Common.php
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\BotSignals;
|
4 |
+
|
5 |
+
trait Common {
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Will test whether the Binary IP can be converted back before applying filter.
|
9 |
+
* @param mixed $binaryIp - IP has already been converted using inet_pton
|
10 |
+
* @return $this
|
11 |
+
*/
|
12 |
+
public function filterByIP( $binaryIp ) {
|
13 |
+
if ( inet_ntop( $binaryIp ) !== false ) {
|
14 |
+
$this->addWhereEquals( 'ip', $binaryIp );
|
15 |
+
}
|
16 |
+
return $this;
|
17 |
+
}
|
18 |
+
|
19 |
+
public function filterByIPHuman( string $ip ) {
|
20 |
+
return $this->filterByIP( inet_pton( $ip ) );
|
21 |
+
}
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Will test whether the Binary IP can be converted back before applying filter.
|
25 |
+
* @param mixed $bBinaryIp - IP has already been converted using inet_pton
|
26 |
+
* @return $this
|
27 |
+
*/
|
28 |
+
public function filterByNotIp( $bBinaryIp ) {
|
29 |
+
if ( inet_ntop( $bBinaryIp ) !== false ) {
|
30 |
+
$this->addWhere( 'ip', $bBinaryIp, '!=' );
|
31 |
+
}
|
32 |
+
return $this;
|
33 |
+
}
|
34 |
+
}
|
src/lib/src/Databases/BotSignals/Delete.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\BotSignals;
|
4 |
+
|
5 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
|
6 |
+
|
7 |
+
class Delete extends Base\Delete {
|
8 |
+
|
9 |
+
use Common;
|
10 |
+
}
|
src/lib/src/Databases/BotSignals/EntryVO.php
ADDED
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\BotSignals;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Class EntryVO
|
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
|
13 |
+
* @property int $btinvalidscript_at
|
14 |
+
* @property int $btloginfail_at
|
15 |
+
* @property int $btlogininvalid_at
|
16 |
+
* @property int $btua_at
|
17 |
+
* @property int $btxml_at
|
18 |
+
* @property int $cooldown_at
|
19 |
+
* @property int $auth_at
|
20 |
+
* @property int $offense_at
|
21 |
+
* @property int $blocked_at
|
22 |
+
* @property int $unblocked_at
|
23 |
+
* @property int $bypass_at
|
24 |
+
* @property int $humanspam_at
|
25 |
+
* @property int $markspam_at
|
26 |
+
* @property int $unmarkspam_at
|
27 |
+
* @property int $captchapass_at
|
28 |
+
* @property int $captchafail_at
|
29 |
+
* @property int $ratelimit_at
|
30 |
+
* @property int $updated_at
|
31 |
+
*/
|
32 |
+
class EntryVO extends \FernleafSystems\Wordpress\Plugin\Shield\Databases\Base\EntryVO {
|
33 |
+
|
34 |
+
/**
|
35 |
+
* @inheritDoc
|
36 |
+
*/
|
37 |
+
public function __get( string $key ) {
|
38 |
+
switch ( $key ) {
|
39 |
+
|
40 |
+
case 'ip':
|
41 |
+
$value = inet_ntop( parent::__get( $key ) );
|
42 |
+
break;
|
43 |
+
|
44 |
+
default:
|
45 |
+
$value = parent::__get( $key );
|
46 |
+
break;
|
47 |
+
}
|
48 |
+
return $value;
|
49 |
+
}
|
50 |
+
|
51 |
+
/**
|
52 |
+
* @inheritDoc
|
53 |
+
*/
|
54 |
+
public function __set( string $key, $value ) {
|
55 |
+
switch ( $key ) {
|
56 |
+
|
57 |
+
case 'ip':
|
58 |
+
$value = inet_pton( $value );
|
59 |
+
break;
|
60 |
+
|
61 |
+
default:
|
62 |
+
break;
|
63 |
+
}
|
64 |
+
|
65 |
+
parent::__set( $key, $value );
|
66 |
+
}
|
67 |
+
}
|
src/lib/src/Databases/BotSignals/Handler.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\BotSignals;
|
4 |
+
|
5 |
+
class Handler extends \FernleafSystems\Wordpress\Plugin\Shield\Databases\Base\Handler {
|
6 |
+
|
7 |
+
public function autoCleanDb() {
|
8 |
+
$this->tableCleanExpired( (int)$this->getTableSchema()->autoexpire );
|
9 |
+
}
|
10 |
+
}
|
src/lib/src/Databases/BotSignals/Insert.php
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\BotSignals;
|
4 |
+
|
5 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
|
6 |
+
|
7 |
+
class Insert extends Base\Insert {
|
8 |
+
|
9 |
+
}
|
src/lib/src/Databases/BotSignals/Select.php
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\BotSignals;
|
4 |
+
|
5 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
|
6 |
+
|
7 |
+
class Select extends Base\Select {
|
8 |
+
|
9 |
+
use Common;
|
10 |
+
use Base\Traits\Select_IPTable;
|
11 |
+
|
12 |
+
/**
|
13 |
+
* @param string $ip
|
14 |
+
* @return EntryVO
|
15 |
+
*/
|
16 |
+
public function byIp( string $ip ) {
|
17 |
+
return $this->filterByIP( inet_pton( $ip ) )
|
18 |
+
->setResultsAsVo( true )
|
19 |
+
->first();
|
20 |
+
}
|
21 |
+
}
|
src/lib/src/Databases/BotSignals/Update.php
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\BotSignals;
|
4 |
+
|
5 |
+
class Update extends \FernleafSystems\Wordpress\Plugin\Shield\Databases\Base\Update {
|
6 |
+
|
7 |
+
}
|
src/lib/src/Databases/ChangeTracking/EntryVO.php
CHANGED
@@ -6,7 +6,6 @@ use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
|
|
6 |
|
7 |
/**
|
8 |
* Class EntryVO
|
9 |
-
*
|
10 |
* @property string ip
|
11 |
* @property array data
|
12 |
* @property array meta
|
@@ -14,14 +13,14 @@ use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
|
|
14 |
class EntryVO extends Base\EntryVO {
|
15 |
|
16 |
/**
|
17 |
-
* @param string $
|
18 |
* @return mixed
|
19 |
*/
|
20 |
-
public function __get( $
|
21 |
|
22 |
-
$mVal = parent::__get( $
|
23 |
|
24 |
-
switch ( $
|
25 |
|
26 |
case 'data':
|
27 |
$mVal = json_decode( \WP_Http_Encoding::decompress( $mVal ), true );
|
@@ -35,22 +34,20 @@ class EntryVO extends Base\EntryVO {
|
|
35 |
}
|
36 |
|
37 |
/**
|
38 |
-
* @
|
39 |
-
* @param mixed $mValue
|
40 |
-
* @return $this|mixed
|
41 |
*/
|
42 |
-
public function __set( $
|
43 |
|
44 |
-
switch ( $
|
45 |
|
46 |
case 'data':
|
47 |
-
$
|
48 |
break;
|
49 |
|
50 |
default:
|
51 |
break;
|
52 |
}
|
53 |
|
54 |
-
|
55 |
}
|
56 |
}
|
6 |
|
7 |
/**
|
8 |
* Class EntryVO
|
|
|
9 |
* @property string ip
|
10 |
* @property array data
|
11 |
* @property array meta
|
13 |
class EntryVO extends Base\EntryVO {
|
14 |
|
15 |
/**
|
16 |
+
* @param string $key
|
17 |
* @return mixed
|
18 |
*/
|
19 |
+
public function __get(string $key ) {
|
20 |
|
21 |
+
$mVal = parent::__get( $key );
|
22 |
|
23 |
+
switch ( $key ) {
|
24 |
|
25 |
case 'data':
|
26 |
$mVal = json_decode( \WP_Http_Encoding::decompress( $mVal ), true );
|
34 |
}
|
35 |
|
36 |
/**
|
37 |
+
* @inheritDoc
|
|
|
|
|
38 |
*/
|
39 |
+
public function __set( string $key, $value ) {
|
40 |
|
41 |
+
switch ( $key ) {
|
42 |
|
43 |
case 'data':
|
44 |
+
$value = \WP_Http_Encoding::compress( json_encode( $value ) );
|
45 |
break;
|
46 |
|
47 |
default:
|
48 |
break;
|
49 |
}
|
50 |
|
51 |
+
parent::__set( $key, $value );
|
52 |
}
|
53 |
}
|
src/lib/src/Databases/Common/TableSchema.php
CHANGED
@@ -2,22 +2,42 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\Common;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Data\Adapter\
|
6 |
use FernleafSystems\Wordpress\Services\Services;
|
7 |
|
8 |
/**
|
9 |
-
* Class
|
10 |
-
* @package FernleafSystems\Wordpress\Plugin\Shield\Databases\
|
|
|
11 |
* @property string $table
|
12 |
* @property string $primary_key
|
13 |
* @property string[] $cols_ids
|
14 |
* @property string[] $cols_custom
|
15 |
* @property string[] $cols_timestamps
|
|
|
|
|
|
|
|
|
|
|
16 |
*/
|
17 |
-
class TableSchema {
|
18 |
|
19 |
const PRIMARY_KEY = 'id';
|
20 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
|
22 |
public function buildCreate() :string {
|
23 |
$cols = [];
|
@@ -50,7 +70,7 @@ class TableSchema {
|
|
50 |
return array_merge(
|
51 |
$this->getColumn_ID(),
|
52 |
$this->cols_custom ?? [],
|
53 |
-
$this->getColumnns_Timestamps()
|
54 |
);
|
55 |
}
|
56 |
|
@@ -66,17 +86,56 @@ class TableSchema {
|
|
66 |
/**
|
67 |
* @return string[]
|
68 |
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
protected function getColumnns_Timestamps() :array {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
return array_map(
|
71 |
function ( $comment ) {
|
72 |
return $this->getTimestampColDef( $comment );
|
73 |
},
|
74 |
array_merge(
|
75 |
$this->cols_timestamps ?? [],
|
76 |
-
|
77 |
-
'created_at' => 'Created At',
|
78 |
-
'deleted_at' => 'Soft Deleted At',
|
79 |
-
]
|
80 |
)
|
81 |
);
|
82 |
}
|
@@ -92,4 +151,8 @@ class TableSchema {
|
|
92 |
protected function getPrimaryKeyColumnName() :string {
|
93 |
return $this->primary_key ?? static::PRIMARY_KEY;
|
94 |
}
|
95 |
-
|
|
|
|
|
|
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\Common;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
|
6 |
use FernleafSystems\Wordpress\Services\Services;
|
7 |
|
8 |
/**
|
9 |
+
* Class TableSchema
|
10 |
+
* @package FernleafSystems\Wordpress\Plugin\Shield\Databases\Common
|
11 |
+
* @property string $slug
|
12 |
* @property string $table
|
13 |
* @property string $primary_key
|
14 |
* @property string[] $cols_ids
|
15 |
* @property string[] $cols_custom
|
16 |
* @property string[] $cols_timestamps
|
17 |
+
* @property string $col_older_than
|
18 |
+
* @property bool $has_updated_at
|
19 |
+
* @property int $autoexpire
|
20 |
+
* @property bool $has_ip_col
|
21 |
+
* @property bool $is_ip_binary
|
22 |
*/
|
23 |
+
class TableSchema extends DynPropertiesClass {
|
24 |
|
25 |
const PRIMARY_KEY = 'id';
|
26 |
+
|
27 |
+
public function __get( $key ) {
|
28 |
+
switch ( $key ) {
|
29 |
+
case 'has_ip_col':
|
30 |
+
$val = array_key_exists( 'ip', $this->enumerateColumns() );
|
31 |
+
break;
|
32 |
+
case 'is_ip_binary':
|
33 |
+
$val = $this->has_ip_col && ( stripos( $this->cols_custom[ 'ip' ], 'varbinary' ) !== false );
|
34 |
+
break;
|
35 |
+
default:
|
36 |
+
$val = parent::__get( $key );
|
37 |
+
break;
|
38 |
+
}
|
39 |
+
return $val;
|
40 |
+
}
|
41 |
|
42 |
public function buildCreate() :string {
|
43 |
$cols = [];
|
70 |
return array_merge(
|
71 |
$this->getColumn_ID(),
|
72 |
$this->cols_custom ?? [],
|
73 |
+
method_exists( $this, 'getColumns_Timestamps' ) ? $this->getColumns_Timestamps() : $this->getColumnns_Timestamps()
|
74 |
);
|
75 |
}
|
76 |
|
86 |
/**
|
87 |
* @return string[]
|
88 |
*/
|
89 |
+
protected function getColumns_Timestamps() :array {
|
90 |
+
|
91 |
+
$standardTsCols = [
|
92 |
+
'created_at' => 'Created At',
|
93 |
+
'deleted_at' => 'Soft Deleted At',
|
94 |
+
];
|
95 |
+
|
96 |
+
if ( $this->has_updated_at && !array_key_exists( 'updated_at', $this->cols_timestamps ) ) {
|
97 |
+
$standardTsCols = array_merge(
|
98 |
+
[ 'updated_at' => 'Updated At', ],
|
99 |
+
$standardTsCols
|
100 |
+
);
|
101 |
+
}
|
102 |
+
|
103 |
+
return array_map(
|
104 |
+
function ( $comment ) {
|
105 |
+
return $this->getTimestampColDef( $comment );
|
106 |
+
},
|
107 |
+
array_merge(
|
108 |
+
$this->cols_timestamps ?? [],
|
109 |
+
$standardTsCols
|
110 |
+
)
|
111 |
+
);
|
112 |
+
}
|
113 |
+
|
114 |
+
/**
|
115 |
+
* @return string[]
|
116 |
+
* @deprecated 10.3
|
117 |
+
*/
|
118 |
protected function getColumnns_Timestamps() :array {
|
119 |
+
|
120 |
+
$standardTsCols = [
|
121 |
+
'created_at' => 'Created At',
|
122 |
+
'deleted_at' => 'Soft Deleted At',
|
123 |
+
];
|
124 |
+
|
125 |
+
if ( $this->has_updated_at && !array_key_exists( 'updated_at', $this->cols_timestamps ) ) {
|
126 |
+
$standardTsCols = array_merge(
|
127 |
+
[ 'updated_at' => 'Updated At', ],
|
128 |
+
$standardTsCols
|
129 |
+
);
|
130 |
+
}
|
131 |
+
|
132 |
return array_map(
|
133 |
function ( $comment ) {
|
134 |
return $this->getTimestampColDef( $comment );
|
135 |
},
|
136 |
array_merge(
|
137 |
$this->cols_timestamps ?? [],
|
138 |
+
$standardTsCols
|
|
|
|
|
|
|
139 |
)
|
140 |
);
|
141 |
}
|
151 |
protected function getPrimaryKeyColumnName() :string {
|
152 |
return $this->primary_key ?? static::PRIMARY_KEY;
|
153 |
}
|
154 |
+
|
155 |
+
public function hasColumn( string $col ) :bool {
|
156 |
+
return in_array( strtolower( $col ), $this->getColumnNames() );
|
157 |
+
}
|
158 |
+
}
|
src/lib/src/Databases/Events/Select.php
CHANGED
@@ -17,11 +17,11 @@ class Select extends Base\Select {
|
|
17 |
}
|
18 |
|
19 |
/**
|
20 |
-
* @param string[] $
|
21 |
* @return int
|
22 |
*/
|
23 |
-
public function sumEvents( $
|
24 |
-
return (int)$this->filterByEvents( $
|
25 |
->setColumnsToSelect( [ 'count' ] )
|
26 |
->sum();
|
27 |
}
|
17 |
}
|
18 |
|
19 |
/**
|
20 |
+
* @param string[] $events
|
21 |
* @return int
|
22 |
*/
|
23 |
+
public function sumEvents( array $events ) :int {
|
24 |
+
return (int)$this->filterByEvents( $events )
|
25 |
->setColumnsToSelect( [ 'count' ] )
|
26 |
->sum();
|
27 |
}
|
src/lib/src/Databases/Events/Update.php
CHANGED
@@ -1,9 +1,7 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\Events;
|
4 |
|
5 |
-
|
6 |
-
|
7 |
-
class Update extends Base\Update {
|
8 |
|
9 |
}
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\Events;
|
4 |
|
5 |
+
class Update extends \FernleafSystems\Wordpress\Plugin\Shield\Databases\Base\Update {
|
|
|
|
|
6 |
|
7 |
}
|
src/lib/src/Databases/FileLocker/EntryVO.php
CHANGED
@@ -19,44 +19,35 @@ use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
|
|
19 |
class EntryVO extends Base\EntryVO {
|
20 |
|
21 |
/**
|
22 |
-
* @
|
23 |
-
* @return mixed
|
24 |
*/
|
25 |
-
public function __get( $
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
switch ( $sProperty ) {
|
30 |
-
|
31 |
case 'content':
|
32 |
case 'file':
|
33 |
-
$
|
34 |
break;
|
35 |
|
36 |
default:
|
37 |
break;
|
38 |
}
|
39 |
-
return $
|
40 |
}
|
41 |
|
42 |
/**
|
43 |
-
* @
|
44 |
-
* @param mixed $mValue
|
45 |
-
* @return $this
|
46 |
*/
|
47 |
-
public function __set( $
|
48 |
-
|
49 |
-
switch ( $sProperty ) {
|
50 |
-
|
51 |
case 'content':
|
52 |
case 'file':
|
53 |
-
$
|
54 |
break;
|
55 |
|
56 |
default:
|
57 |
break;
|
58 |
}
|
59 |
-
|
60 |
-
return parent::__set( $sProperty, $mValue );
|
61 |
}
|
62 |
}
|
19 |
class EntryVO extends Base\EntryVO {
|
20 |
|
21 |
/**
|
22 |
+
* @inheritDoc
|
|
|
23 |
*/
|
24 |
+
public function __get( string $key ) {
|
25 |
+
$value = parent::__get( $key );
|
26 |
+
switch ( $key ) {
|
|
|
|
|
|
|
27 |
case 'content':
|
28 |
case 'file':
|
29 |
+
$value = base64_decode( $value );
|
30 |
break;
|
31 |
|
32 |
default:
|
33 |
break;
|
34 |
}
|
35 |
+
return $value;
|
36 |
}
|
37 |
|
38 |
/**
|
39 |
+
* @inheritDoc
|
|
|
|
|
40 |
*/
|
41 |
+
public function __set( string $key, $value ) {
|
42 |
+
switch ( $key ) {
|
|
|
|
|
43 |
case 'content':
|
44 |
case 'file':
|
45 |
+
$value = base64_encode( $value);
|
46 |
break;
|
47 |
|
48 |
default:
|
49 |
break;
|
50 |
}
|
51 |
+
parent::__set( $key, $value );
|
|
|
52 |
}
|
53 |
}
|
src/lib/src/Databases/FileLocker/Insert.php
CHANGED
@@ -1,9 +1,7 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\FileLocker;
|
4 |
|
5 |
-
|
6 |
-
|
7 |
-
class Insert extends Base\Insert {
|
8 |
|
9 |
}
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\FileLocker;
|
4 |
|
5 |
+
class Insert extends \FernleafSystems\Wordpress\Plugin\Shield\Databases\Base\Insert {
|
|
|
|
|
6 |
|
7 |
}
|
src/lib/src/Databases/FileLocker/Update.php
CHANGED
@@ -8,47 +8,46 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
8 |
class Update extends Base\Update {
|
9 |
|
10 |
/**
|
11 |
-
* @param EntryVO $
|
12 |
* @return bool
|
13 |
*/
|
14 |
-
public function markNotified( EntryVO $
|
15 |
-
return $this->updateEntry( $
|
16 |
'notified_at' => Services::Request()->ts()
|
17 |
] );
|
18 |
}
|
19 |
|
20 |
/**
|
21 |
-
* @param EntryVO $
|
22 |
* @return bool
|
23 |
*/
|
24 |
-
public function markProblem( EntryVO $
|
25 |
-
return $this->updateEntry( $
|
26 |
'detected_at' => Services::Request()->ts(),
|
27 |
'notified_at' => 0
|
28 |
] );
|
29 |
}
|
30 |
|
31 |
/**
|
32 |
-
* @param EntryVO $
|
33 |
* @return bool
|
34 |
*/
|
35 |
-
public function markReverted( EntryVO $
|
36 |
-
return $this->updateEntry( $
|
37 |
'reverted_at' => Services::Request()->ts()
|
38 |
] );
|
39 |
}
|
40 |
|
41 |
/**
|
42 |
-
* @param EntryVO $
|
43 |
-
* @param string $
|
44 |
* @return bool
|
45 |
*/
|
46 |
-
public function updateCurrentHash( EntryVO $
|
47 |
-
return $this->updateEntry( $
|
48 |
-
'hash_current' => $
|
49 |
-
'detected_at' => empty( $
|
50 |
'notified_at' => 0,
|
51 |
-
'updated_at' => Services::Request()->ts(),
|
52 |
] );
|
53 |
}
|
54 |
}
|
8 |
class Update extends Base\Update {
|
9 |
|
10 |
/**
|
11 |
+
* @param EntryVO $entry
|
12 |
* @return bool
|
13 |
*/
|
14 |
+
public function markNotified( EntryVO $entry ) {
|
15 |
+
return $this->updateEntry( $entry, [
|
16 |
'notified_at' => Services::Request()->ts()
|
17 |
] );
|
18 |
}
|
19 |
|
20 |
/**
|
21 |
+
* @param EntryVO $entry
|
22 |
* @return bool
|
23 |
*/
|
24 |
+
public function markProblem( EntryVO $entry ) {
|
25 |
+
return $this->updateEntry( $entry, [
|
26 |
'detected_at' => Services::Request()->ts(),
|
27 |
'notified_at' => 0
|
28 |
] );
|
29 |
}
|
30 |
|
31 |
/**
|
32 |
+
* @param EntryVO $entry
|
33 |
* @return bool
|
34 |
*/
|
35 |
+
public function markReverted( EntryVO $entry ) {
|
36 |
+
return $this->updateEntry( $entry, [
|
37 |
'reverted_at' => Services::Request()->ts()
|
38 |
] );
|
39 |
}
|
40 |
|
41 |
/**
|
42 |
+
* @param EntryVO $entry
|
43 |
+
* @param string $hash
|
44 |
* @return bool
|
45 |
*/
|
46 |
+
public function updateCurrentHash( EntryVO $entry, $hash = '' ) {
|
47 |
+
return $this->updateEntry( $entry, [
|
48 |
+
'hash_current' => $hash,
|
49 |
+
'detected_at' => empty( $hash ) ? 0 : Services::Request()->ts(),
|
50 |
'notified_at' => 0,
|
|
|
51 |
] );
|
52 |
}
|
53 |
}
|
src/lib/src/Databases/GeoIp/EntryVO.php
CHANGED
@@ -53,39 +53,36 @@ class EntryVO extends Base\EntryVO {
|
|
53 |
}
|
54 |
|
55 |
/**
|
56 |
-
* @param string $
|
57 |
* @return mixed
|
58 |
*/
|
59 |
-
public function __get( $
|
60 |
-
switch ( $
|
61 |
-
|
62 |
case 'ip':
|
63 |
-
$
|
64 |
break;
|
65 |
|
66 |
default:
|
67 |
-
$
|
68 |
}
|
69 |
-
return $
|
70 |
}
|
71 |
|
72 |
/**
|
73 |
-
* @
|
74 |
-
* @param mixed $mValue
|
75 |
-
* @return $this
|
76 |
*/
|
77 |
-
public function __set( $
|
78 |
|
79 |
-
switch ( $
|
80 |
|
81 |
case 'ip':
|
82 |
-
$
|
83 |
break;
|
84 |
|
85 |
default:
|
86 |
break;
|
87 |
}
|
88 |
|
89 |
-
|
90 |
}
|
91 |
}
|
53 |
}
|
54 |
|
55 |
/**
|
56 |
+
* @param string $key
|
57 |
* @return mixed
|
58 |
*/
|
59 |
+
public function __get( string $key ) {
|
60 |
+
switch ( $key ) {
|
|
|
61 |
case 'ip':
|
62 |
+
$value = inet_ntop( parent::__get( $key ) );
|
63 |
break;
|
64 |
|
65 |
default:
|
66 |
+
$value = parent::__get( $key );
|
67 |
}
|
68 |
+
return $value;
|
69 |
}
|
70 |
|
71 |
/**
|
72 |
+
* @inheritDoc
|
|
|
|
|
73 |
*/
|
74 |
+
public function __set( string $key, $value ) {
|
75 |
|
76 |
+
switch ( $key ) {
|
77 |
|
78 |
case 'ip':
|
79 |
+
$value = inet_pton( $value );
|
80 |
break;
|
81 |
|
82 |
default:
|
83 |
break;
|
84 |
}
|
85 |
|
86 |
+
parent::__set( $key, $value );
|
87 |
}
|
88 |
}
|
src/lib/src/Databases/GeoIp/Handler.php
CHANGED
@@ -2,19 +2,9 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\GeoIp;
|
4 |
|
5 |
-
|
6 |
-
|
7 |
-
class Handler extends Base\Handler {
|
8 |
|
9 |
public function autoCleanDb() {
|
10 |
-
$this->tableCleanExpired( $this->
|
11 |
-
}
|
12 |
-
|
13 |
-
public function getCustomColumns() :array {
|
14 |
-
return $this->getOptions()->getDef( 'geoip_table_columns' );
|
15 |
-
}
|
16 |
-
|
17 |
-
protected function getDefaultTableName() :string {
|
18 |
-
return $this->getOptions()->getDef( 'geoip_table_name' );
|
19 |
}
|
20 |
}
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\GeoIp;
|
4 |
|
5 |
+
class Handler extends \FernleafSystems\Wordpress\Plugin\Shield\Databases\Base\Handler {
|
|
|
|
|
6 |
|
7 |
public function autoCleanDb() {
|
8 |
+
$this->tableCleanExpired( (int)$this->getTableSchema()->autoexpire );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
}
|
10 |
}
|
src/lib/src/Databases/GeoIp/Select.php
CHANGED
@@ -8,6 +8,7 @@ use FernleafSystems\Wordpress\Plugin\Shield\Utilities\Tool\IpListSort;
|
|
8 |
class Select extends Base\Select {
|
9 |
|
10 |
use BaseGeoIp;
|
|
|
11 |
|
12 |
/**
|
13 |
* @param string $sIp
|
@@ -18,16 +19,4 @@ class Select extends Base\Select {
|
|
18 |
->setResultsAsVo( true )
|
19 |
->first();
|
20 |
}
|
21 |
-
|
22 |
-
/**
|
23 |
-
* @return string[]
|
24 |
-
*/
|
25 |
-
public function getDistinctIps() {
|
26 |
-
return IpListSort::Sort( array_map(
|
27 |
-
function ( $sIp ) {
|
28 |
-
return inet_ntop( $sIp );
|
29 |
-
},
|
30 |
-
$this->getDistinctForColumn( 'ip' )
|
31 |
-
) );
|
32 |
-
}
|
33 |
}
|
8 |
class Select extends Base\Select {
|
9 |
|
10 |
use BaseGeoIp;
|
11 |
+
use Base\Traits\Select_IPTable;
|
12 |
|
13 |
/**
|
14 |
* @param string $sIp
|
19 |
->setResultsAsVo( true )
|
20 |
->first();
|
21 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
}
|
src/lib/src/Databases/IPs/EntryVO.php
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\IPs;
|
4 |
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\IPs;
|
4 |
|
src/lib/src/Databases/IPs/Handler.php
CHANGED
@@ -20,24 +20,36 @@ class Handler extends Base\Handler {
|
|
20 |
}
|
21 |
|
22 |
/**
|
23 |
-
* @param int $
|
24 |
* @return bool
|
25 |
*/
|
26 |
-
public function deleteRowsOlderThan( $
|
27 |
return $this->getQueryDeleter()
|
28 |
-
->addWhereOlderThan( $
|
29 |
->addWhere( 'list', ModCon::LIST_MANUAL_WHITE, '!=' )
|
30 |
->query();
|
31 |
}
|
32 |
|
|
|
|
|
|
|
|
|
33 |
protected function getCustomColumns() :array {
|
34 |
return $this->getOptions()->getDef( 'ip_list_table_columns' );
|
35 |
}
|
36 |
|
|
|
|
|
|
|
|
|
37 |
protected function getDefaultTableName() :string {
|
38 |
return $this->getOptions()->getDef( 'ip_lists_table_name' );
|
39 |
}
|
40 |
|
|
|
|
|
|
|
|
|
41 |
protected function getTimestampColumns() :array {
|
42 |
return $this->getOptions()->getDef( 'ip_list_table_timestamp_columns' );
|
43 |
}
|
20 |
}
|
21 |
|
22 |
/**
|
23 |
+
* @param int $timestamp
|
24 |
* @return bool
|
25 |
*/
|
26 |
+
public function deleteRowsOlderThan( $timestamp ) :bool {
|
27 |
return $this->getQueryDeleter()
|
28 |
+
->addWhereOlderThan( $timestamp, 'last_access_at' )
|
29 |
->addWhere( 'list', ModCon::LIST_MANUAL_WHITE, '!=' )
|
30 |
->query();
|
31 |
}
|
32 |
|
33 |
+
/**
|
34 |
+
* @return string[]
|
35 |
+
* @deprecated 10.3
|
36 |
+
*/
|
37 |
protected function getCustomColumns() :array {
|
38 |
return $this->getOptions()->getDef( 'ip_list_table_columns' );
|
39 |
}
|
40 |
|
41 |
+
/**
|
42 |
+
* @return string[]
|
43 |
+
* @deprecated 10.3
|
44 |
+
*/
|
45 |
protected function getDefaultTableName() :string {
|
46 |
return $this->getOptions()->getDef( 'ip_lists_table_name' );
|
47 |
}
|
48 |
|
49 |
+
/**
|
50 |
+
* @return string[]
|
51 |
+
* @deprecated 10.3
|
52 |
+
*/
|
53 |
protected function getTimestampColumns() :array {
|
54 |
return $this->getOptions()->getDef( 'ip_list_table_timestamp_columns' );
|
55 |
}
|
src/lib/src/Databases/IPs/Insert.php
CHANGED
@@ -13,19 +13,19 @@ class Insert extends Base\Insert {
|
|
13 |
*/
|
14 |
protected function verifyInsertData() {
|
15 |
parent::verifyInsertData();
|
16 |
-
$
|
17 |
|
18 |
-
if ( !Services::IP()->isValidIpOrRange( $
|
19 |
throw new \Exception( 'IP address provided is not valid' );
|
20 |
}
|
21 |
-
if ( empty( $
|
22 |
throw new \Exception( 'An IP address must be assigned to a list' );
|
23 |
}
|
24 |
|
25 |
-
if ( strpos( $
|
26 |
-
$
|
27 |
}
|
28 |
|
29 |
-
return $this->setInsertData( $
|
30 |
}
|
31 |
}
|
13 |
*/
|
14 |
protected function verifyInsertData() {
|
15 |
parent::verifyInsertData();
|
16 |
+
$data = $this->getInsertData();
|
17 |
|
18 |
+
if ( !Services::IP()->isValidIpOrRange( $data[ 'ip' ] ) ) {
|
19 |
throw new \Exception( 'IP address provided is not valid' );
|
20 |
}
|
21 |
+
if ( empty( $data[ 'list' ] ) ) {
|
22 |
throw new \Exception( 'An IP address must be assigned to a list' );
|
23 |
}
|
24 |
|
25 |
+
if ( strpos( $data[ 'ip' ], '/' ) !== false ) {
|
26 |
+
$data[ 'is_range' ] = true;
|
27 |
}
|
28 |
|
29 |
+
return $this->setInsertData( $data );
|
30 |
}
|
31 |
}
|
src/lib/src/Databases/IPs/Update.php
CHANGED
@@ -18,43 +18,40 @@ class Update extends Base\Update {
|
|
18 |
}
|
19 |
|
20 |
/**
|
21 |
-
* @param EntryVO $
|
22 |
-
* @param int $
|
23 |
* @return bool
|
24 |
*/
|
25 |
-
public function updateTransgressions( $
|
26 |
-
return $this->updateEntry(
|
27 |
-
$
|
28 |
-
|
29 |
-
|
30 |
-
'last_access_at' => Services::Request()->ts()
|
31 |
-
]
|
32 |
-
);
|
33 |
}
|
34 |
|
35 |
/**
|
36 |
-
* @param EntryVO $
|
37 |
-
* @param string $
|
38 |
* @return bool
|
39 |
*/
|
40 |
-
public function updateLabel( $
|
41 |
-
return $this->updateEntry( $
|
42 |
}
|
43 |
|
44 |
/**
|
45 |
* Also updates last access at
|
46 |
-
* @param EntryVO $
|
47 |
* @return bool
|
48 |
*/
|
49 |
-
public function updateLastAccessAt( $
|
50 |
-
return $this->updateEntry( $
|
51 |
}
|
52 |
|
53 |
/**
|
54 |
-
* @param EntryVO $
|
55 |
* @return bool
|
56 |
*/
|
57 |
-
public function setBlocked( $
|
58 |
-
return $this->updateEntry( $
|
59 |
}
|
60 |
}
|
18 |
}
|
19 |
|
20 |
/**
|
21 |
+
* @param EntryVO $IP
|
22 |
+
* @param int $offenseCount
|
23 |
* @return bool
|
24 |
*/
|
25 |
+
public function updateTransgressions( $IP, $offenseCount ) {
|
26 |
+
return $this->updateEntry( $IP, [
|
27 |
+
'transgressions' => max( 0, $offenseCount ),
|
28 |
+
'last_access_at' => Services::Request()->ts()
|
29 |
+
] );
|
|
|
|
|
|
|
30 |
}
|
31 |
|
32 |
/**
|
33 |
+
* @param EntryVO $IP
|
34 |
+
* @param string $label
|
35 |
* @return bool
|
36 |
*/
|
37 |
+
public function updateLabel( $IP, $label ) {
|
38 |
+
return $this->updateEntry( $IP, [ 'label' => trim( $label ) ] );
|
39 |
}
|
40 |
|
41 |
/**
|
42 |
* Also updates last access at
|
43 |
+
* @param EntryVO $IP
|
44 |
* @return bool
|
45 |
*/
|
46 |
+
public function updateLastAccessAt( $IP ) {
|
47 |
+
return $this->updateEntry( $IP, [ 'last_access_at' => Services::Request()->ts() ] );
|
48 |
}
|
49 |
|
50 |
/**
|
51 |
+
* @param EntryVO $IP
|
52 |
* @return bool
|
53 |
*/
|
54 |
+
public function setBlocked( $IP ) {
|
55 |
+
return $this->updateEntry( $IP, [ 'blocked_at' => Services::Request()->ts() ] );
|
56 |
}
|
57 |
}
|
src/lib/src/Databases/Reports/Handler.php
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\Reports;
|
4 |
|
@@ -10,18 +10,6 @@ class Handler extends Base\Handler {
|
|
10 |
const TYPE_INFO = 'nfo';
|
11 |
|
12 |
public function autoCleanDb() {
|
13 |
-
$this->tableCleanExpired(
|
14 |
-
}
|
15 |
-
|
16 |
-
protected function getCustomColumns() :array {
|
17 |
-
return $this->getOptions()->getDef( 'reports_table_columns' );
|
18 |
-
}
|
19 |
-
|
20 |
-
protected function getDefaultTableName() :string {
|
21 |
-
return $this->getOptions()->getDef( 'reports_table_name' );
|
22 |
-
}
|
23 |
-
|
24 |
-
protected function getTimestampColumns() :array {
|
25 |
-
return $this->getOptions()->getDef( 'reports_table_timestamp_columns' );
|
26 |
}
|
27 |
}
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\Reports;
|
4 |
|
10 |
const TYPE_INFO = 'nfo';
|
11 |
|
12 |
public function autoCleanDb() {
|
13 |
+
$this->tableCleanExpired( $this->getTableSchema()->autoexpire );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
}
|
15 |
}
|
src/lib/src/Databases/ScanQueue/EntryVO.php
CHANGED
@@ -15,56 +15,53 @@ use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
|
|
15 |
class EntryVO extends Base\EntryVO {
|
16 |
|
17 |
/**
|
18 |
-
* @
|
19 |
-
* @return mixed
|
20 |
*/
|
21 |
-
public function __get( $
|
22 |
|
23 |
-
$
|
24 |
|
25 |
-
switch ( $
|
26 |
|
27 |
case 'items':
|
28 |
case 'results':
|
29 |
-
if ( is_string( $
|
30 |
-
$
|
31 |
-
if ( !empty( $
|
32 |
-
$
|
33 |
}
|
34 |
}
|
35 |
|
36 |
-
if ( !is_array( $
|
37 |
-
$
|
38 |
}
|
39 |
break;
|
40 |
|
41 |
default:
|
42 |
break;
|
43 |
}
|
44 |
-
return $
|
45 |
}
|
46 |
|
47 |
/**
|
48 |
-
* @
|
49 |
-
* @param mixed $mValue
|
50 |
-
* @return $this
|
51 |
*/
|
52 |
-
public function __set( $
|
53 |
|
54 |
-
switch ( $
|
55 |
|
56 |
case 'items':
|
57 |
case 'results':
|
58 |
-
if ( !is_array( $
|
59 |
-
$
|
60 |
}
|
61 |
-
$
|
62 |
break;
|
63 |
|
64 |
default:
|
65 |
break;
|
66 |
}
|
67 |
|
68 |
-
|
69 |
}
|
70 |
}
|
15 |
class EntryVO extends Base\EntryVO {
|
16 |
|
17 |
/**
|
18 |
+
* @inheritDoc
|
|
|
19 |
*/
|
20 |
+
public function __get( string $key ) {
|
21 |
|
22 |
+
$value = parent::__get( $key );
|
23 |
|
24 |
+
switch ( $key ) {
|
25 |
|
26 |
case 'items':
|
27 |
case 'results':
|
28 |
+
if ( is_string( $value ) && !empty( $value ) ) {
|
29 |
+
$value = base64_decode( $value );
|
30 |
+
if ( !empty( $value ) ) {
|
31 |
+
$value = @json_decode( $value, true );
|
32 |
}
|
33 |
}
|
34 |
|
35 |
+
if ( !is_array( $value ) ) {
|
36 |
+
$value = [];
|
37 |
}
|
38 |
break;
|
39 |
|
40 |
default:
|
41 |
break;
|
42 |
}
|
43 |
+
return $value;
|
44 |
}
|
45 |
|
46 |
/**
|
47 |
+
* @inheritDoc
|
|
|
|
|
48 |
*/
|
49 |
+
public function __set( string $key, $value ) {
|
50 |
|
51 |
+
switch ( $key ) {
|
52 |
|
53 |
case 'items':
|
54 |
case 'results':
|
55 |
+
if ( !is_array( $value ) ) {
|
56 |
+
$value = [];
|
57 |
}
|
58 |
+
$value = base64_encode( json_encode( $value ) );
|
59 |
break;
|
60 |
|
61 |
default:
|
62 |
break;
|
63 |
}
|
64 |
|
65 |
+
parent::__set( $key, $value );
|
66 |
}
|
67 |
}
|
src/lib/src/Databases/ScanQueue/Handler.php
CHANGED
@@ -2,19 +2,6 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\ScanQueue;
|
4 |
|
5 |
-
|
6 |
|
7 |
-
class Handler extends Base\Handler {
|
8 |
-
|
9 |
-
public function getCustomColumns() :array {
|
10 |
-
return $this->getOptions()->getDef( 'table_columns_scanqueue' );
|
11 |
-
}
|
12 |
-
|
13 |
-
protected function getDefaultTableName() :string {
|
14 |
-
return $this->getOptions()->getDef( 'table_name_scanqueue' );
|
15 |
-
}
|
16 |
-
|
17 |
-
protected function getTimestampColumns() :array {
|
18 |
-
return $this->getOptions()->getDef( 'scanqueue_table_timestamp_columns' );
|
19 |
-
}
|
20 |
}
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\ScanQueue;
|
4 |
|
5 |
+
class Handler extends \FernleafSystems\Wordpress\Plugin\Shield\Databases\Base\Handler {
|
6 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
}
|
src/lib/src/Databases/ScanQueue/Update.php
CHANGED
@@ -8,27 +8,27 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
8 |
class Update extends Base\Update {
|
9 |
|
10 |
/**
|
11 |
-
* @param EntryVO $
|
12 |
* @return bool
|
13 |
*/
|
14 |
-
public function storeResults( $
|
15 |
-
return isset( $
|
16 |
-
$this->updateEntry( $
|
17 |
}
|
18 |
|
19 |
/**
|
20 |
-
* @param EntryVO $
|
21 |
* @return bool
|
22 |
*/
|
23 |
-
public function setFinished( $
|
24 |
-
return $this->updateEntry( $
|
25 |
}
|
26 |
|
27 |
/**
|
28 |
-
* @param EntryVO $
|
29 |
* @return bool
|
30 |
*/
|
31 |
-
public function setStarted( $
|
32 |
-
return $this->updateEntry( $
|
33 |
}
|
34 |
}
|
8 |
class Update extends Base\Update {
|
9 |
|
10 |
/**
|
11 |
+
* @param EntryVO $entry
|
12 |
* @return bool
|
13 |
*/
|
14 |
+
public function storeResults( $entry ) {
|
15 |
+
return isset( $entry->results ) &&
|
16 |
+
$this->updateEntry( $entry, [ 'results' => gzcompress( $entry->getRawData()[ 'results' ] ) ] );
|
17 |
}
|
18 |
|
19 |
/**
|
20 |
+
* @param EntryVO $entry
|
21 |
* @return bool
|
22 |
*/
|
23 |
+
public function setFinished( $entry ) {
|
24 |
+
return $this->updateEntry( $entry, [ 'finished_at' => Services::Request()->ts() ] );
|
25 |
}
|
26 |
|
27 |
/**
|
28 |
+
* @param EntryVO $entry
|
29 |
* @return bool
|
30 |
*/
|
31 |
+
public function setStarted( $entry ) {
|
32 |
+
return $this->updateEntry( $entry, [ 'started_at' => Services::Request()->ts() ] );
|
33 |
}
|
34 |
}
|
src/lib/src/Databases/Scanner/Handler.php
CHANGED
@@ -2,19 +2,6 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\Scanner;
|
4 |
|
5 |
-
|
6 |
|
7 |
-
class Handler extends Base\Handler {
|
8 |
-
|
9 |
-
public function getCustomColumns() :array {
|
10 |
-
return $this->getOptions()->getDef( 'table_columns_scanner' );
|
11 |
-
}
|
12 |
-
|
13 |
-
protected function getDefaultTableName() :string {
|
14 |
-
return $this->getOptions()->getDef( 'table_name_scanner' );
|
15 |
-
}
|
16 |
-
|
17 |
-
protected function getTimestampColumns() :array {
|
18 |
-
return $this->getOptions()->getDef( 'scanresults_table_timestamp_columns' );
|
19 |
-
}
|
20 |
}
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\Scanner;
|
4 |
|
5 |
+
class Handler extends \FernleafSystems\Wordpress\Plugin\Shield\Databases\Base\Handler {
|
6 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
}
|
src/lib/src/Databases/Scanner/Update.php
CHANGED
@@ -46,34 +46,34 @@ class Update extends Base\Update {
|
|
46 |
}
|
47 |
|
48 |
/**
|
49 |
-
* @param EntryVO $
|
50 |
* @return bool
|
51 |
*/
|
52 |
-
public function setIgnored( $
|
53 |
-
return $this->updateEntry( $
|
54 |
}
|
55 |
|
56 |
/**
|
57 |
-
* @param EntryVO $
|
58 |
* @return bool
|
59 |
*/
|
60 |
-
public function setNotified( $
|
61 |
-
return $this->updateEntry( $
|
62 |
}
|
63 |
|
64 |
/**
|
65 |
-
* @param EntryVO $
|
66 |
* @return bool
|
67 |
*/
|
68 |
-
public function setNotIgnored( $
|
69 |
-
return $this->updateEntry( $
|
70 |
}
|
71 |
|
72 |
/**
|
73 |
-
* @param EntryVO $
|
74 |
* @return bool
|
75 |
*/
|
76 |
-
public function setNotNotified( $
|
77 |
-
return $this->updateEntry( $
|
78 |
}
|
79 |
}
|
46 |
}
|
47 |
|
48 |
/**
|
49 |
+
* @param EntryVO $entry
|
50 |
* @return bool
|
51 |
*/
|
52 |
+
public function setIgnored( $entry ) {
|
53 |
+
return $this->updateEntry( $entry, [ 'ignored_at' => Services::Request()->ts() ] );
|
54 |
}
|
55 |
|
56 |
/**
|
57 |
+
* @param EntryVO $entry
|
58 |
* @return bool
|
59 |
*/
|
60 |
+
public function setNotified( $entry ) {
|
61 |
+
return $this->updateEntry( $entry, [ 'notified_at' => Services::Request()->ts() ] );
|
62 |
}
|
63 |
|
64 |
/**
|
65 |
+
* @param EntryVO $entry
|
66 |
* @return bool
|
67 |
*/
|
68 |
+
public function setNotIgnored( $entry ) {
|
69 |
+
return $this->updateEntry( $entry, [ 'ignored_at' => 0 ] );
|
70 |
}
|
71 |
|
72 |
/**
|
73 |
+
* @param EntryVO $entry
|
74 |
* @return bool
|
75 |
*/
|
76 |
+
public function setNotNotified( $entry ) {
|
77 |
+
return $this->updateEntry( $entry, [ 'notified_at' => 0 ] );
|
78 |
}
|
79 |
}
|
src/lib/src/Databases/Session/Insert.php
CHANGED
@@ -8,12 +8,11 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
8 |
class Insert extends Base\Insert {
|
9 |
|
10 |
public function create( string $ID, string $username ) :bool {
|
11 |
-
$
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
return $this->setInsertData( $aData )->query() === 1;
|
17 |
}
|
18 |
|
19 |
/**
|
@@ -23,22 +22,22 @@ class Insert extends Base\Insert {
|
|
23 |
protected function verifyInsertData() {
|
24 |
parent::verifyInsertData();
|
25 |
|
26 |
-
$
|
27 |
-
if ( empty( $
|
28 |
throw new \Exception( 'Session ID not provided.' );
|
29 |
}
|
30 |
-
if ( empty( $
|
31 |
throw new \Exception( 'WP Username not provided' );
|
32 |
}
|
33 |
|
34 |
-
$
|
35 |
-
if ( empty( $
|
36 |
-
$
|
37 |
-
$
|
38 |
}
|
39 |
|
40 |
$req = Services::Request();
|
41 |
-
$
|
42 |
[
|
43 |
'browser' => md5( $req->getUserAgent() ),
|
44 |
'logged_in_at' => $req->ts(),
|
@@ -47,9 +46,7 @@ class Insert extends Base\Insert {
|
|
47 |
'login_intent_expires_at' => 0,
|
48 |
'secadmin_at' => 0,
|
49 |
],
|
50 |
-
$
|
51 |
-
);
|
52 |
-
|
53 |
-
return $this->setInsertData( $aData );
|
54 |
}
|
55 |
}
|
8 |
class Insert extends Base\Insert {
|
9 |
|
10 |
public function create( string $ID, string $username ) :bool {
|
11 |
+
return $this->setInsertData( [
|
12 |
+
'session_id' => $ID,
|
13 |
+
'wp_username' => $username,
|
14 |
+
'ip' => Services::IP()->getRequestIp()
|
15 |
+
] )->query() === 1;
|
|
|
16 |
}
|
17 |
|
18 |
/**
|
22 |
protected function verifyInsertData() {
|
23 |
parent::verifyInsertData();
|
24 |
|
25 |
+
$data = $this->getInsertData();
|
26 |
+
if ( empty( $data[ 'session_id' ] ) ) {
|
27 |
throw new \Exception( 'Session ID not provided.' );
|
28 |
}
|
29 |
+
if ( empty( $data[ 'wp_username' ] ) ) {
|
30 |
throw new \Exception( 'WP Username not provided' );
|
31 |
}
|
32 |
|
33 |
+
$srvIP = Services::IP();
|
34 |
+
if ( empty( $data[ 'ip' ] ) || !$srvIP->isValidIp( $data[ 'ip' ] ) ) {
|
35 |
+
$reqIP = $srvIP->getRequestIp();
|
36 |
+
$data[ 'ip' ] = $srvIP->isValidIp( $reqIP ) ? $reqIP: '';
|
37 |
}
|
38 |
|
39 |
$req = Services::Request();
|
40 |
+
return $this->setInsertData( array_merge(
|
41 |
[
|
42 |
'browser' => md5( $req->getUserAgent() ),
|
43 |
'logged_in_at' => $req->ts(),
|
46 |
'login_intent_expires_at' => 0,
|
47 |
'secadmin_at' => 0,
|
48 |
],
|
49 |
+
$data
|
50 |
+
) );
|
|
|
|
|
51 |
}
|
52 |
}
|
src/lib/src/Databases/Session/Select.php
CHANGED
@@ -8,12 +8,7 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
8 |
|
9 |
class Select extends Base\Select {
|
10 |
|
11 |
-
|
12 |
-
* @return string[]
|
13 |
-
*/
|
14 |
-
public function getDistinctIps() :array {
|
15 |
-
return IpListSort::Sort( $this->getDistinctForColumn( 'ip' ) );
|
16 |
-
}
|
17 |
|
18 |
/**
|
19 |
* @return string[]
|
8 |
|
9 |
class Select extends Base\Select {
|
10 |
|
11 |
+
use Base\Traits\Select_IPTable;
|
|
|
|
|
|
|
|
|
|
|
12 |
|
13 |
/**
|
14 |
* @return string[]
|
src/lib/src/Databases/Session/Update.php
CHANGED
@@ -52,10 +52,10 @@ class Update extends Base\Update {
|
|
52 |
|
53 |
/**
|
54 |
* @param EntryVO $session
|
55 |
-
* @param array $
|
56 |
* @return bool
|
57 |
*/
|
58 |
-
public function updateSession( $session, $
|
59 |
-
return parent::updateEntry( $session, $
|
60 |
}
|
61 |
}
|
52 |
|
53 |
/**
|
54 |
* @param EntryVO $session
|
55 |
+
* @param array $updateData
|
56 |
* @return bool
|
57 |
*/
|
58 |
+
public function updateSession( $session, $updateData = [] ) {
|
59 |
+
return parent::updateEntry( $session, $updateData );
|
60 |
}
|
61 |
}
|
src/lib/src/Databases/Tally/Delete.php
DELETED
@@ -1,9 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\Tally;
|
4 |
-
|
5 |
-
use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
|
6 |
-
|
7 |
-
class Delete extends Base\Delete {
|
8 |
-
|
9 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/lib/src/Databases/Tally/EntryVO.php
DELETED
@@ -1,16 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\Tally;
|
4 |
-
|
5 |
-
use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
|
6 |
-
|
7 |
-
/**
|
8 |
-
* Class EntryVO
|
9 |
-
* @property string stat_key
|
10 |
-
* @property string parent_stat_key
|
11 |
-
* @property int tally
|
12 |
-
* @property int modified_at
|
13 |
-
*/
|
14 |
-
class EntryVO extends Base\EntryVO {
|
15 |
-
|
16 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/lib/src/Databases/Tally/Handler.php
DELETED
@@ -1,32 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\Tally;
|
4 |
-
|
5 |
-
use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
|
6 |
-
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Statistics\Options;
|
7 |
-
|
8 |
-
class Handler extends Base\Handler {
|
9 |
-
|
10 |
-
public function getColumns() :array {
|
11 |
-
return $this->getOptions()->getDef( 'statistics_table_columns' );
|
12 |
-
}
|
13 |
-
|
14 |
-
protected function getDefaultTableName() :string {
|
15 |
-
/** @var Options $opts */
|
16 |
-
$opts = $this->getOptions();
|
17 |
-
return $opts->getDbTable_Tallys();
|
18 |
-
}
|
19 |
-
|
20 |
-
protected function getDefaultCreateTableSql() :string {
|
21 |
-
return "CREATE TABLE %s (
|
22 |
-
id int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
23 |
-
stat_key varchar(100) NOT NULL DEFAULT 0,
|
24 |
-
parent_stat_key varchar(100) NOT NULL DEFAULT '',
|
25 |
-
tally int(11) UNSIGNED NOT NULL DEFAULT 0,
|
26 |
-
created_at int(15) UNSIGNED NOT NULL DEFAULT 0,
|
27 |
-
modified_at int(15) UNSIGNED NOT NULL DEFAULT 0,
|
28 |
-
deleted_at int(15) UNSIGNED NOT NULL DEFAULT 0,
|
29 |
-
PRIMARY KEY (id)
|
30 |
-
) %s;";
|
31 |
-
}
|
32 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/lib/src/Databases/Tally/Insert.php
DELETED
@@ -1,45 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\Tally;
|
4 |
-
|
5 |
-
use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
|
6 |
-
use FernleafSystems\Wordpress\Services\Services;
|
7 |
-
|
8 |
-
class Insert extends Base\Insert {
|
9 |
-
|
10 |
-
/**
|
11 |
-
* @param EntryVO $oEntry
|
12 |
-
* @return bool
|
13 |
-
*/
|
14 |
-
public function insert( $oEntry ) :bool {
|
15 |
-
$bSuccess = false;
|
16 |
-
if ( preg_match( '#[a-z]+\.[a-z]+#i', $oEntry->stat_key )
|
17 |
-
&& is_numeric( $oEntry->tally ) && $oEntry->tally > 0 ) {
|
18 |
-
$bSuccess = parent::insert( $oEntry );
|
19 |
-
}
|
20 |
-
return $bSuccess;
|
21 |
-
}
|
22 |
-
|
23 |
-
/**
|
24 |
-
* @param string sStatKey
|
25 |
-
* @param string $sParent
|
26 |
-
* @param int $nTally
|
27 |
-
* @return bool
|
28 |
-
*/
|
29 |
-
public function create( $sStatKey, $nTally, $sParent = '' ) {
|
30 |
-
if ( !preg_match( '#[a-z]{1,}\.[a-z]{1,}#i', $sStatKey ) || empty( $nTally )
|
31 |
-
|| !is_numeric( $nTally ) || $nTally < 0 ) {
|
32 |
-
return false;
|
33 |
-
}
|
34 |
-
|
35 |
-
$nTimeStamp = Services::Request()->ts();
|
36 |
-
$aData = [
|
37 |
-
'stat_key' => $sStatKey,
|
38 |
-
'parent_stat_key' => $sParent,
|
39 |
-
'tally' => $nTally,
|
40 |
-
'modified_at' => $nTimeStamp,
|
41 |
-
'created_at' => $nTimeStamp,
|
42 |
-
];
|
43 |
-
return $this->setInsertData( $aData )->query() === 1;
|
44 |
-
}
|
45 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/lib/src/Databases/Tally/Select.php
DELETED
@@ -1,39 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\Tally;
|
4 |
-
|
5 |
-
use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
|
6 |
-
|
7 |
-
class Select extends Base\Select {
|
8 |
-
|
9 |
-
/**
|
10 |
-
* @param string $sKey
|
11 |
-
* @return $this
|
12 |
-
*/
|
13 |
-
public function filterByParentStatKey( $sKey ) {
|
14 |
-
return $this->addWhereEquals( 'parent_stat_key', $sKey );
|
15 |
-
}
|
16 |
-
|
17 |
-
/**
|
18 |
-
* @param string $sKey
|
19 |
-
* @return $this
|
20 |
-
*/
|
21 |
-
public function filterByStatKey( $sKey ) {
|
22 |
-
return $this->addWhereEquals( 'stat_key', $sKey );
|
23 |
-
}
|
24 |
-
|
25 |
-
/**
|
26 |
-
* @param string $sStatKey
|
27 |
-
* @param string $sParentStatKey
|
28 |
-
* @return EntryVO|\stdClass|null
|
29 |
-
*/
|
30 |
-
public function retrieveStat( $sStatKey, $sParentStatKey = '' ) {
|
31 |
-
if ( !empty( $sParentStatKey ) ) {
|
32 |
-
$this->filterByParentStatKey( $sParentStatKey );
|
33 |
-
}
|
34 |
-
$oR = $this->filterByStatKey( $sStatKey )
|
35 |
-
->setOrderBy( 'created_at', 'DESC' )
|
36 |
-
->first();
|
37 |
-
return $oR;
|
38 |
-
}
|
39 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/lib/src/Databases/Tally/Update.php
DELETED
@@ -1,17 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace FernleafSystems\Wordpress\Plugin\Shield\Databases\Tally;
|
4 |
-
|
5 |
-
use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
|
6 |
-
|
7 |
-
class Update extends Base\Update {
|
8 |
-
|
9 |
-
/**
|
10 |
-
* @param EntryVO $oStat
|
11 |
-
* @param int $nAdditional
|
12 |
-
* @return bool
|
13 |
-
*/
|
14 |
-
public function incrementTally( $oStat, $nAdditional ) {
|
15 |
-
return $this->updateEntry( $oStat, [ 'tally' => $oStat->tally + $nAdditional, ] );
|
16 |
-
}
|
17 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/lib/src/Databases/Traffic/EntryVO.php
CHANGED
@@ -18,39 +18,38 @@ use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base;
|
|
18 |
class EntryVO extends Base\EntryVO {
|
19 |
|
20 |
/**
|
21 |
-
* @param string $
|
22 |
* @return mixed
|
23 |
*/
|
24 |
-
public function __get( $
|
25 |
-
switch ( $
|
26 |
|
27 |
case 'ip':
|
28 |
-
$
|
29 |
break;
|
30 |
|
31 |
default:
|
32 |
-
$
|
|
|
33 |
}
|
34 |
-
return $
|
35 |
}
|
36 |
|
37 |
/**
|
38 |
-
* @
|
39 |
-
* @param mixed $mValue
|
40 |
-
* @return $this
|
41 |
*/
|
42 |
-
public function __set( $
|
43 |
|
44 |
-
switch ( $
|
45 |
|
46 |
case 'ip':
|
47 |
-
$
|
48 |
break;
|
49 |
|
50 |
default:
|
51 |
break;
|
52 |
}
|
53 |
|
54 |
-
|
55 |
}
|
56 |
}
|
18 |
class EntryVO extends Base\EntryVO {
|
19 |
|
20 |
/**
|
21 |
+
* @param string $key
|
22 |
* @return mixed
|
23 |
*/
|
24 |
+
public function __get( string $key ) {
|
25 |
+
switch ( $key ) {
|
26 |
|
27 |
case 'ip':
|
28 |
+
$value = inet_ntop( parent::__get( $key ) );
|
29 |
break;
|
30 |
|
31 |
default:
|
32 |
+
$value = parent::__get( $key );
|
33 |
+
break;
|
34 |
}
|
35 |
+
return $value;
|
36 |
}
|
37 |
|
38 |
/**
|
39 |
+
* @inheritDoc
|
|
|
|
|
40 |
*/
|
41 |
+
public function __set( string $key, $value ) {
|
42 |
|
43 |
+
switch ( $key ) {
|
44 |
|
45 |
case 'ip':
|
46 |
+
$value = inet_pton( $value );
|
47 |
break;
|
48 |
|
49 |
default:
|
50 |
break;
|
51 |
}
|
52 |
|
53 |
+
parent::__set( $key, $value );
|
54 |
}
|
55 |
}
|
src/lib/src/Databases/Traffic/Insert.php
CHANGED
@@ -12,12 +12,12 @@ class Insert extends Base\Insert {
|
|
12 |
*/
|
13 |
protected function verifyInsertData() {
|
14 |
parent::verifyInsertData();
|
15 |
-
$aData = $this->getInsertData();
|
16 |
|
17 |
-
|
|
|
18 |
throw new \Exception( 'IP address provided is not valid' );
|
19 |
}
|
20 |
|
21 |
-
return $this->setInsertData( $
|
22 |
}
|
23 |
}
|
12 |
*/
|
13 |
protected function verifyInsertData() {
|
14 |
parent::verifyInsertData();
|
|
|
15 |
|
16 |
+
$data = $this->getInsertData();
|
17 |
+
if ( empty( $data[ 'ip' ] ) ) {
|
18 |
throw new \Exception( 'IP address provided is not valid' );
|
19 |
}
|
20 |
|
21 |
+
return $this->setInsertData( $data );
|
22 |
}
|
23 |
}
|
src/lib/src/Databases/Traffic/Select.php
CHANGED
@@ -9,18 +9,7 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
9 |
class Select extends Base\Select {
|
10 |
|
11 |
use BaseTraffic;
|
12 |
-
|
13 |
-
/**
|
14 |
-
* @return string[]
|
15 |
-
*/
|
16 |
-
public function getDistinctIps() {
|
17 |
-
return IpListSort::Sort( array_map(
|
18 |
-
function ( $sIpBinary ) {
|
19 |
-
return inet_ntop( $sIpBinary );
|
20 |
-
},
|
21 |
-
$this->getDistinctForColumn( 'ip' )
|
22 |
-
) );
|
23 |
-
}
|
24 |
|
25 |
/**
|
26 |
* @return string[]
|
9 |
class Select extends Base\Select {
|
10 |
|
11 |
use BaseTraffic;
|
12 |
+
use Base\Traits\Select_IPTable;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
|
14 |
/**
|
15 |
* @return string[]
|
src/lib/src/Modules/AuditTrail/AjaxHandler.php
CHANGED
@@ -28,41 +28,27 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
|
|
28 |
protected function ajaxExec_AddParamToFirewallWhitelist() :array {
|
29 |
/** @var ModCon $mod */
|
30 |
$mod = $this->getMod();
|
31 |
-
$
|
32 |
|
33 |
-
$
|
34 |
-
if ( empty( $
|
35 |
-
$
|
36 |
}
|
37 |
else {
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
if ( empty( $oEntry ) ) {
|
44 |
-
$sMessage = __( 'Audit entry could not be loaded.', 'wp-simple-firewall' );
|
45 |
}
|
46 |
-
|
47 |
-
$
|
48 |
-
$sParam = isset( $aData[ 'param' ] ) ? $aData[ 'param' ] : '';
|
49 |
-
$sUri = isset( $aData[ 'uri' ] ) ? $aData[ 'uri' ] : '*';
|
50 |
-
if ( empty( $sParam ) ) {
|
51 |
-
$sMessage = __( 'Parameter associated with this audit entry could not be found.', 'wp-simple-firewall' );
|
52 |
-
}
|
53 |
-
else {
|
54 |
-
/** @var Shield\Modules\Firewall\ModCon $oModFire */
|
55 |
-
$oModFire = $this->getCon()->getModule( 'firewall' );
|
56 |
-
$oModFire->addParamToWhitelist( $sParam, $sUri );
|
57 |
-
$sMessage = sprintf( __( 'Parameter "%s" whitelisted successfully', 'wp-simple-firewall' ), $sParam );
|
58 |
-
$bSuccess = true;
|
59 |
-
}
|
60 |
}
|
61 |
}
|
62 |
|
63 |
return [
|
64 |
-
'success' => $
|
65 |
-
'message' => $
|
66 |
];
|
67 |
}
|
68 |
|
28 |
protected function ajaxExec_AddParamToFirewallWhitelist() :array {
|
29 |
/** @var ModCon $mod */
|
30 |
$mod = $this->getMod();
|
31 |
+
$success = false;
|
32 |
|
33 |
+
$entryID = Services::Request()->post( 'rid' );
|
34 |
+
if ( empty( $entryID ) || !is_numeric( $entryID ) || $entryID < 1 ) {
|
35 |
+
$msg = __( 'Invalid audit entry selected for this action', 'wp-simple-firewall' );
|
36 |
}
|
37 |
else {
|
38 |
+
try {
|
39 |
+
$msg = ( new Lib\Utility\AutoWhitelistParamFromAuditEntry() )
|
40 |
+
->setMod( $mod )
|
41 |
+
->run( (int)$entryID );
|
42 |
+
$success = true;
|
|
|
|
|
43 |
}
|
44 |
+
catch ( \Exception $e ) {
|
45 |
+
$msg = $e->getMessage();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
}
|
47 |
}
|
48 |
|
49 |
return [
|
50 |
+
'success' => $success,
|
51 |
+
'message' => $msg
|
52 |
];
|
53 |
}
|
54 |
|
src/lib/src/Modules/AuditTrail/Lib/AuditMessageBuilder.php
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\Lib;
|
4 |
+
|
5 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Databases\AuditTrail\EntryVO;
|
6 |
+
|
7 |
+
class AuditMessageBuilder {
|
8 |
+
|
9 |
+
public static function Build( EntryVO $entry, array $msgStructure ) :string {
|
10 |
+
|
11 |
+
$substitutions = $entry->meta;
|
12 |
+
$rawString = implode( "\n", $msgStructure );
|
13 |
+
|
14 |
+
// In-case we're working with an older audit message without as much data substitutions
|
15 |
+
$missingCount = substr_count( $rawString, '%s' ) - count( $substitutions );
|
16 |
+
|
17 |
+
if ( $missingCount > 0 ) {
|
18 |
+
$substitutions = array_merge(
|
19 |
+
$substitutions,
|
20 |
+
array_fill( 0, $missingCount, 'data missing for older audit logs' )
|
21 |
+
);
|
22 |
+
}
|
23 |
+
return stripslashes( sanitize_textarea_field( vsprintf( $rawString, $substitutions ) ) );
|
24 |
+
}
|
25 |
+
}
|
src/lib/src/Modules/AuditTrail/Lib/Ops/Commit.php
CHANGED
@@ -15,54 +15,51 @@ class Commit {
|
|
15 |
*/
|
16 |
public function commitAudits( $aEvents ) {
|
17 |
if ( is_array( $aEvents ) ) {
|
18 |
-
foreach ( $aEvents as $
|
19 |
-
if ( $
|
20 |
-
$this->commitAudit( $
|
21 |
}
|
22 |
}
|
23 |
}
|
24 |
}
|
25 |
|
26 |
/**
|
27 |
-
* @param AuditTrail\EntryVO $
|
28 |
*/
|
29 |
-
public function commitAudit( $
|
30 |
-
$
|
31 |
-
$
|
32 |
|
33 |
-
if ( empty( $
|
34 |
-
$
|
35 |
}
|
36 |
-
if ( empty( $
|
37 |
-
$
|
38 |
-
|
39 |
-
if ( empty( $oEntry->wp_username ) ) {
|
40 |
-
if ( $oWpUsers->isUserLoggedIn() ) {
|
41 |
-
$sUser = $oWpUsers->getCurrentWpUsername();
|
42 |
}
|
43 |
-
elseif ( $
|
44 |
$sUser = 'WP Cron';
|
45 |
}
|
46 |
-
elseif ( $
|
47 |
$sUser = 'WP CLI';
|
48 |
}
|
49 |
else {
|
50 |
$sUser = '-';
|
51 |
}
|
52 |
-
$
|
53 |
}
|
54 |
|
55 |
$oLatest = null;
|
56 |
-
$bCanCount = in_array( $
|
57 |
if ( $bCanCount ) {
|
58 |
/** @var AuditTrail\Select $oSel */
|
59 |
$oSel = $this->getDbHandler()->getQuerySelector();
|
60 |
-
$oLatest = $oSel->filterByEvent( $
|
61 |
-
->filterByIp( $
|
62 |
->filterByCreatedAt( Services::Request()->carbon()->subDay()->timestamp, '>' )
|
63 |
->first();
|
64 |
$bCanCount = ( $oLatest instanceof AuditTrail\EntryVO )
|
65 |
-
&& ( $oLatest->event === $
|
66 |
}
|
67 |
|
68 |
if ( $bCanCount ) {
|
@@ -73,7 +70,7 @@ class Commit {
|
|
73 |
else {
|
74 |
/** @var AuditTrail\Insert $oQI */
|
75 |
$oQI = $this->getDbHandler()->getQueryInserter();
|
76 |
-
$oQI->insert( $
|
77 |
}
|
78 |
}
|
79 |
|
15 |
*/
|
16 |
public function commitAudits( $aEvents ) {
|
17 |
if ( is_array( $aEvents ) ) {
|
18 |
+
foreach ( $aEvents as $entry ) {
|
19 |
+
if ( $entry instanceof AuditTrail\EntryVO ) {
|
20 |
+
$this->commitAudit( $entry );
|
21 |
}
|
22 |
}
|
23 |
}
|
24 |
}
|
25 |
|
26 |
/**
|
27 |
+
* @param AuditTrail\EntryVO $entry
|
28 |
*/
|
29 |
+
public function commitAudit( $entry ) {
|
30 |
+
$WP = Services::WpGeneral();
|
31 |
+
$WPU = Services::WpUsers();
|
32 |
|
33 |
+
if ( empty( $entry->ip ) ) {
|
34 |
+
$entry->ip = Services::IP()->getRequestIp();
|
35 |
}
|
36 |
+
if ( empty( $entry->wp_username ) ) {
|
37 |
+
if ( $WPU->isUserLoggedIn() ) {
|
38 |
+
$sUser = $WPU->getCurrentWpUsername();
|
|
|
|
|
|
|
39 |
}
|
40 |
+
elseif ( $WP->isCron() ) {
|
41 |
$sUser = 'WP Cron';
|
42 |
}
|
43 |
+
elseif ( $WP->isWpCli() ) {
|
44 |
$sUser = 'WP CLI';
|
45 |
}
|
46 |
else {
|
47 |
$sUser = '-';
|
48 |
}
|
49 |
+
$entry->wp_username = $sUser;
|
50 |
}
|
51 |
|
52 |
$oLatest = null;
|
53 |
+
$bCanCount = in_array( $entry->event, $this->getCanCountEvents() );
|
54 |
if ( $bCanCount ) {
|
55 |
/** @var AuditTrail\Select $oSel */
|
56 |
$oSel = $this->getDbHandler()->getQuerySelector();
|
57 |
+
$oLatest = $oSel->filterByEvent( $entry->event )
|
58 |
+
->filterByIp( $entry->ip )
|
59 |
->filterByCreatedAt( Services::Request()->carbon()->subDay()->timestamp, '>' )
|
60 |
->first();
|
61 |
$bCanCount = ( $oLatest instanceof AuditTrail\EntryVO )
|
62 |
+
&& ( $oLatest->event === $entry->event && $oLatest->ip === $entry->ip );
|
63 |
}
|
64 |
|
65 |
if ( $bCanCount ) {
|
70 |
else {
|
71 |
/** @var AuditTrail\Insert $oQI */
|
72 |
$oQI = $this->getDbHandler()->getQueryInserter();
|
73 |
+
$oQI->insert( $entry );
|
74 |
}
|
75 |
}
|
76 |
|
src/lib/src/Modules/AuditTrail/Lib/Utility/AutoWhitelistParamFromAuditEntry.php
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\Lib\Utility;
|
4 |
+
|
5 |
+
use FernleafSystems\Wordpress\Plugin\Shield;
|
6 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Databases\AuditTrail\EntryVO;
|
7 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Databases\AuditTrail\Select;
|
8 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\ModCon;
|
9 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
10 |
+
|
11 |
+
class AutoWhitelistParamFromAuditEntry {
|
12 |
+
|
13 |
+
use ModConsumer;
|
14 |
+
|
15 |
+
/**
|
16 |
+
* @param int $entryID
|
17 |
+
* @return string
|
18 |
+
* @throws \Exception
|
19 |
+
*/
|
20 |
+
public function run( int $entryID ) :string {
|
21 |
+
/** @var ModCon $mod */
|
22 |
+
$mod = $this->getMod();
|
23 |
+
|
24 |
+
/** @var Select $selector */
|
25 |
+
$selector = $mod->getDbHandler_AuditTrail()->getQuerySelector();
|
26 |
+
|
27 |
+
/** @var EntryVO $entry */
|
28 |
+
$entry = $selector->byId( $entryID );
|
29 |
+
if ( !$entry instanceof EntryVO ) {
|
30 |
+
throw new \Exception( __( 'Audit entry could not be loaded.', 'wp-simple-firewall' ) );
|
31 |
+
}
|
32 |
+
|
33 |
+
$uri = '';
|
34 |
+
foreach ( $selector->filterByRequestID( (int)$entry->rid )->all() as $entry ) {
|
35 |
+
$param = $this->extractParameter( $entry );
|
36 |
+
if ( !empty( $param ) ) {
|
37 |
+
$uri = $entry->meta[ 'uri' ] ?? '*';
|
38 |
+
break;
|
39 |
+
}
|
40 |
+
}
|
41 |
+
|
42 |
+
if ( empty( $param ) ) {
|
43 |
+
throw new \Exception( __( 'Parameter associated with this audit entry could not be found.', 'wp-simple-firewall' ) );
|
44 |
+
}
|
45 |
+
|
46 |
+
/** @var Shield\Modules\Firewall\ModCon $modFW */
|
47 |
+
$modFW = $this->getCon()->modules[ 'firewall' ];
|
48 |
+
$modFW->addParamToWhitelist( $param, $uri );
|
49 |
+
return sprintf( __( 'Parameter "%s" whitelisted successfully', 'wp-simple-firewall' ), $param );
|
50 |
+
}
|
51 |
+
|
52 |
+
private function extractParameter( EntryVO $entry ) :string {
|
53 |
+
return $entry->meta[ 'param' ] ?? '';
|
54 |
+
}
|
55 |
+
}
|
src/lib/src/Modules/AuditTrail/ModCon.php
CHANGED
@@ -4,12 +4,24 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail;
|
|
4 |
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
|
|
|
7 |
use FernleafSystems\Wordpress\Services\Services;
|
8 |
|
9 |
class ModCon extends BaseShield\ModCon {
|
10 |
|
11 |
public function getDbHandler_AuditTrail() :Shield\Databases\AuditTrail\Handler {
|
12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
}
|
14 |
|
15 |
/**
|
@@ -62,12 +74,12 @@ class ModCon extends BaseShield\ModCon {
|
|
62 |
$oFinder->filterByUsername( $oUser->user_login );
|
63 |
|
64 |
$WP = Services::WpGeneral();
|
65 |
-
/** @var Shield\Databases\AuditTrail\EntryVO $
|
66 |
-
foreach ( $oFinder->query() as $
|
67 |
$aExportItem[ 'data' ][] = [
|
68 |
-
$sTimeStamp = $WP->getTimeStringForDisplay( $
|
69 |
'name' => sprintf( '[%s] Audit Trail Entry', $sTimeStamp ),
|
70 |
-
'value' => sprintf( '[IP:%s] %s', $
|
71 |
];
|
72 |
}
|
73 |
|
4 |
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
|
7 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Utilities\Tool\DbTableExport;
|
8 |
use FernleafSystems\Wordpress\Services\Services;
|
9 |
|
10 |
class ModCon extends BaseShield\ModCon {
|
11 |
|
12 |
public function getDbHandler_AuditTrail() :Shield\Databases\AuditTrail\Handler {
|
13 |
+
$new = $this->getDbH( 'audit_trail' );
|
14 |
+
return empty( $new ) ? $this->getDbH( 'audit' ) : $new;
|
15 |
+
}
|
16 |
+
|
17 |
+
protected function handleFileDownload( string $downloadID ) {
|
18 |
+
switch ( $downloadID ) {
|
19 |
+
case 'db_audit':
|
20 |
+
( new DbTableExport() )
|
21 |
+
->setDbHandler( $this->getDbHandler_AuditTrail() )
|
22 |
+
->toCSV();
|
23 |
+
break;
|
24 |
+
}
|
25 |
}
|
26 |
|
27 |
/**
|
74 |
$oFinder->filterByUsername( $oUser->user_login );
|
75 |
|
76 |
$WP = Services::WpGeneral();
|
77 |
+
/** @var Shield\Databases\AuditTrail\EntryVO $entry */
|
78 |
+
foreach ( $oFinder->query() as $entry ) {
|
79 |
$aExportItem[ 'data' ][] = [
|
80 |
+
$sTimeStamp = $WP->getTimeStringForDisplay( $entry->getCreatedAt() ),
|
81 |
'name' => sprintf( '[%s] Audit Trail Entry', $sTimeStamp ),
|
82 |
+
'value' => sprintf( '[IP:%s] %s', $entry->ip, $entry->message )
|
83 |
];
|
84 |
}
|
85 |
|
src/lib/src/Modules/Base/AjaxHandler.php
CHANGED
@@ -18,7 +18,7 @@ abstract class AjaxHandler {
|
|
18 |
add_filter( $this->getCon()->prefix( 'ajaxNonAuthAction' ), [ $this, 'handleAjaxNonAuth' ], 10, 2 );
|
19 |
}
|
20 |
|
21 |
-
public function handleAjaxAuth( array $ajaxResponse, string $ajaxAction ) {
|
22 |
if ( !empty( $ajaxAction ) && ( empty( $ajaxResponse ) || !is_array( $ajaxResponse ) ) ) {
|
23 |
$ajaxResponse = $this->normaliseAjaxResponse( $this->processAjaxAction( $ajaxAction ) );
|
24 |
}
|
@@ -27,7 +27,7 @@ abstract class AjaxHandler {
|
|
27 |
|
28 |
public function handleAjaxNonAuth( array $ajaxResponse, string $ajaxAction ) :array {
|
29 |
if ( !empty( $ajaxAction ) && ( empty( $ajaxResponse ) || !is_array( $ajaxResponse ) ) ) {
|
30 |
-
$ajaxResponse = $this->normaliseAjaxResponse( $this->
|
31 |
}
|
32 |
return $ajaxResponse;
|
33 |
}
|
@@ -71,6 +71,10 @@ abstract class AjaxHandler {
|
|
71 |
return [];
|
72 |
}
|
73 |
|
|
|
|
|
|
|
|
|
74 |
/**
|
75 |
* We check for empty since if it's empty, there's nothing to normalize. It's a filter,
|
76 |
* so if we send something back non-empty, it'll be treated like a "handled" response and
|
@@ -78,7 +82,7 @@ abstract class AjaxHandler {
|
|
78 |
* @param array $ajaxResponse
|
79 |
* @return array
|
80 |
*/
|
81 |
-
protected function normaliseAjaxResponse( array $ajaxResponse ) {
|
82 |
if ( !empty( $ajaxResponse ) ) {
|
83 |
$ajaxResponse = array_merge(
|
84 |
[
|
18 |
add_filter( $this->getCon()->prefix( 'ajaxNonAuthAction' ), [ $this, 'handleAjaxNonAuth' ], 10, 2 );
|
19 |
}
|
20 |
|
21 |
+
public function handleAjaxAuth( array $ajaxResponse, string $ajaxAction ) :array {
|
22 |
if ( !empty( $ajaxAction ) && ( empty( $ajaxResponse ) || !is_array( $ajaxResponse ) ) ) {
|
23 |
$ajaxResponse = $this->normaliseAjaxResponse( $this->processAjaxAction( $ajaxAction ) );
|
24 |
}
|
27 |
|
28 |
public function handleAjaxNonAuth( array $ajaxResponse, string $ajaxAction ) :array {
|
29 |
if ( !empty( $ajaxAction ) && ( empty( $ajaxResponse ) || !is_array( $ajaxResponse ) ) ) {
|
30 |
+
$ajaxResponse = $this->normaliseAjaxResponse( $this->processNonAuthAjaxAction( $ajaxAction ) );
|
31 |
}
|
32 |
return $ajaxResponse;
|
33 |
}
|
71 |
return [];
|
72 |
}
|
73 |
|
74 |
+
protected function processNonAuthAjaxAction( string $action ) :array {
|
75 |
+
return [];
|
76 |
+
}
|
77 |
+
|
78 |
/**
|
79 |
* We check for empty since if it's empty, there's nothing to normalize. It's a filter,
|
80 |
* so if we send something back non-empty, it'll be treated like a "handled" response and
|
82 |
* @param array $ajaxResponse
|
83 |
* @return array
|
84 |
*/
|
85 |
+
protected function normaliseAjaxResponse( array $ajaxResponse ) :array {
|
86 |
if ( !empty( $ajaxResponse ) ) {
|
87 |
$ajaxResponse = array_merge(
|
88 |
[
|
src/lib/src/Modules/Base/BaseProcessor.php
DELETED
@@ -1,183 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
|
4 |
-
|
5 |
-
use FernleafSystems\Wordpress\Plugin\Shield\Modules;
|
6 |
-
use FernleafSystems\Wordpress\Services\Services;
|
7 |
-
|
8 |
-
/**
|
9 |
-
* Class BaseProcessor
|
10 |
-
* @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Base
|
11 |
-
* @deprecated 10.2
|
12 |
-
*/
|
13 |
-
class BaseProcessor {
|
14 |
-
|
15 |
-
use Modules\ModConsumer;
|
16 |
-
|
17 |
-
/**
|
18 |
-
* @var BaseProcessor[]
|
19 |
-
*/
|
20 |
-
protected $aSubPros;
|
21 |
-
|
22 |
-
/**
|
23 |
-
* @var bool
|
24 |
-
*/
|
25 |
-
private $bLoginCaptured;
|
26 |
-
|
27 |
-
/**
|
28 |
-
* @var bool
|
29 |
-
*/
|
30 |
-
private $bHasExecuted;
|
31 |
-
|
32 |
-
/**
|
33 |
-
* @param ModCon $mod
|
34 |
-
*/
|
35 |
-
public function __construct( $mod ) {
|
36 |
-
$this->setMod( $mod );
|
37 |
-
|
38 |
-
add_action( 'init', [ $this, 'onWpInit' ], 9 );
|
39 |
-
add_action( 'wp_loaded', [ $this, 'onWpLoaded' ] );
|
40 |
-
{ // Capture Logins
|
41 |
-
add_action( 'wp_login', [ $this, 'onWpLogin' ], 10, 2 );
|
42 |
-
if ( !Services::WpUsers()->isProfilePage() ) { // This can be fired during profile update.
|
43 |
-
add_action( 'set_logged_in_cookie', [ $this, 'onWpSetLoggedInCookie' ], 5, 4 );
|
44 |
-
}
|
45 |
-
}
|
46 |
-
add_action( $mod->prefix( 'plugin_shutdown' ), [ $this, 'onModuleShutdown' ] );
|
47 |
-
add_action( $mod->prefix( 'daily_cron' ), [ $this, 'runDailyCron' ] );
|
48 |
-
add_action( $mod->prefix( 'hourly_cron' ), [ $this, 'runHourlyCron' ] );
|
49 |
-
add_action( $mod->prefix( 'deactivate_plugin' ), [ $this, 'deactivatePlugin' ] );
|
50 |
-
|
51 |
-
/**
|
52 |
-
* 2019-04-19:
|
53 |
-
* wp_service_worker: added to prevent infinite page reloads triggered by an error with the PWA plugin.
|
54 |
-
* It seems that using wp_localize_script() on a request with wp_service_worker=1 causes the worker
|
55 |
-
* reload the page. Why exactly this happens hasn't been investigated, so we just skip any FRONTend
|
56 |
-
* enqueues that might call wp_localize_script() for these requests.
|
57 |
-
*/
|
58 |
-
if ( Services::Request()->query( 'wp_service_worker', 0 ) != 1 ) {
|
59 |
-
add_action( 'wp_enqueue_scripts', [ $this, 'onWpEnqueueJs' ] );
|
60 |
-
add_action( 'login_enqueue_scripts', [ $this, 'onWpEnqueueJs' ] );
|
61 |
-
}
|
62 |
-
|
63 |
-
$this->bHasExecuted = false;
|
64 |
-
$this->init();
|
65 |
-
}
|
66 |
-
|
67 |
-
public function onWpInit() {
|
68 |
-
}
|
69 |
-
|
70 |
-
public function onWpLoaded() {
|
71 |
-
}
|
72 |
-
|
73 |
-
public function onWpEnqueueJs() {
|
74 |
-
}
|
75 |
-
|
76 |
-
/**
|
77 |
-
* @param string $sUsername
|
78 |
-
* @param \WP_User $user
|
79 |
-
*/
|
80 |
-
public function onWpLogin( $sUsername, $user ) {
|
81 |
-
}
|
82 |
-
|
83 |
-
/**
|
84 |
-
* @param string $sCookie
|
85 |
-
* @param int $nExpire
|
86 |
-
* @param int $nExpiration
|
87 |
-
* @param int $nUserId
|
88 |
-
*/
|
89 |
-
public function onWpSetLoggedInCookie( $sCookie, $nExpire, $nExpiration, $nUserId ) {
|
90 |
-
}
|
91 |
-
|
92 |
-
/**
|
93 |
-
* @return bool
|
94 |
-
*/
|
95 |
-
protected function isLoginCaptured() {
|
96 |
-
return (bool)$this->bLoginCaptured;
|
97 |
-
}
|
98 |
-
|
99 |
-
public function runDailyCron() {
|
100 |
-
}
|
101 |
-
|
102 |
-
public function runHourlyCron() {
|
103 |
-
}
|
104 |
-
|
105 |
-
/**
|
106 |
-
* @return $this
|
107 |
-
*/
|
108 |
-
protected function setLoginCaptured() {
|
109 |
-
$this->bLoginCaptured = true;
|
110 |
-
return $this;
|
111 |
-
}
|
112 |
-
|
113 |
-
public function onModuleShutdown() {
|
114 |
-
}
|
115 |
-
|
116 |
-
public function init() {
|
117 |
-
}
|
118 |
-
|
119 |
-
/**
|
120 |
-
* @return bool
|
121 |
-
*/
|
122 |
-
public function isReadyToRun() {
|
123 |
-
return true;
|
124 |
-
}
|
125 |
-
|
126 |
-
/**
|
127 |
-
* @return $this
|
128 |
-
*/
|
129 |
-
public function execute() {
|
130 |
-
if ( !$this->bHasExecuted ) {
|
131 |
-
$this->run();
|
132 |
-
$this->bHasExecuted;
|
133 |
-
}
|
134 |
-
return $this;
|
135 |
-
}
|
136 |
-
|
137 |
-
/**
|
138 |
-
* Override to set what this processor does when it's "run"
|
139 |
-
*/
|
140 |
-
public function run() {
|
141 |
-
}
|
142 |
-
|
143 |
-
/**
|
144 |
-
* We don't handle locale derivatives (yet)
|
145 |
-
* @return string
|
146 |
-
*/
|
147 |
-
protected function getGoogleRecaptchaLocale() {
|
148 |
-
return Services::WpGeneral()->getLocale( '-' );
|
149 |
-
}
|
150 |
-
|
151 |
-
/**
|
152 |
-
* @param string $key
|
153 |
-
* @return BaseProcessor|mixed|null
|
154 |
-
*/
|
155 |
-
protected function getSubPro( string $key ) {
|
156 |
-
$aProcessors = $this->getSubProcessors();
|
157 |
-
if ( !isset( $aProcessors[ $key ] ) ) {
|
158 |
-
$aMap = $this->getSubProMap();
|
159 |
-
if ( !isset( $aMap[ $key ] ) ) {
|
160 |
-
error_log( 'Sub processor key not set: '.$key );
|
161 |
-
}
|
162 |
-
$aProcessors[ $key ] = new $aMap[ $key ]( $this->getMod() );
|
163 |
-
}
|
164 |
-
return $aProcessors[ $key ];
|
165 |
-
}
|
166 |
-
|
167 |
-
protected function getSubProMap() :array {
|
168 |
-
return [];
|
169 |
-
}
|
170 |
-
|
171 |
-
public function deactivatePlugin() {
|
172 |
-
}
|
173 |
-
|
174 |
-
/**
|
175 |
-
* @return BaseProcessor[]
|
176 |
-
*/
|
177 |
-
protected function getSubProcessors() {
|
178 |
-
if ( !isset( $this->aSubPros ) ) {
|
179 |
-
$this->aSubPros = [];
|
180 |
-
}
|
181 |
-
return $this->aSubPros;
|
182 |
-
}
|
183 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/lib/src/Modules/Base/ModCon.php
CHANGED
@@ -31,7 +31,7 @@ abstract class ModCon {
|
|
31 |
protected $bImportExportWhitelistNotify = false;
|
32 |
|
33 |
/**
|
34 |
-
* @var Shield\Modules\Base\
|
35 |
*/
|
36 |
private $oProcessor;
|
37 |
|
@@ -146,8 +146,8 @@ abstract class ModCon {
|
|
146 |
*/
|
147 |
protected function getDbHandlers( $bInitAll = false ) {
|
148 |
if ( $bInitAll ) {
|
149 |
-
foreach ( $this->getAllDbClasses() as $
|
150 |
-
$this->getDbH( $
|
151 |
}
|
152 |
}
|
153 |
return is_array( $this->aDbHandlers ) ? $this->aDbHandlers : [];
|
@@ -171,9 +171,15 @@ abstract class ModCon {
|
|
171 |
$aDbClasses = $this->getAllDbClasses();
|
172 |
if ( isset( $aDbClasses[ $dbhKey ] ) ) {
|
173 |
/** @var Shield\Databases\Base\Handler $dbh */
|
174 |
-
$dbh = new $aDbClasses[ $dbhKey ]();
|
175 |
try {
|
176 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
177 |
}
|
178 |
catch ( \Exception $e ) {
|
179 |
}
|
@@ -410,7 +416,7 @@ abstract class ModCon {
|
|
410 |
}
|
411 |
|
412 |
/**
|
413 |
-
* @return Shield\Modules\Base\
|
414 |
*/
|
415 |
public function getProcessor() {
|
416 |
return $this->loadProcessor();
|
@@ -424,14 +430,10 @@ abstract class ModCon {
|
|
424 |
);
|
425 |
}
|
426 |
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
public function buildAdminActionNonceUrl( $sAction ) {
|
432 |
-
$aActionNonce = $this->getNonceActionData( $sAction );
|
433 |
-
$aActionNonce[ 'ts' ] = Services::Request()->ts();
|
434 |
-
return add_query_arg( $aActionNonce, $this->getUrl_AdminPage() );
|
435 |
}
|
436 |
|
437 |
protected function getModActionParams( string $action ) :array {
|
@@ -442,8 +444,8 @@ abstract class ModCon {
|
|
442 |
'mod_slug' => $this->getModSlug(),
|
443 |
'ts' => Services::Request()->ts(),
|
444 |
'exec_nonce' => substr(
|
445 |
-
hash_hmac( 'md5', $action.Services::Request()->ts(), $con->getSiteInstallationId() )
|
446 |
-
|
447 |
];
|
448 |
}
|
449 |
|
@@ -452,28 +454,28 @@ abstract class ModCon {
|
|
452 |
* @throws \Exception
|
453 |
*/
|
454 |
protected function verifyModActionRequest() :bool {
|
455 |
-
$
|
456 |
|
457 |
$con = $this->getCon();
|
458 |
$req = Services::Request();
|
459 |
|
460 |
-
$
|
461 |
-
if ( !empty( $
|
462 |
|
463 |
|
464 |
-
if ( wp_verify_nonce( $req->request( 'exec_nonce' ), $
|
465 |
-
$
|
466 |
}
|
467 |
else {
|
468 |
-
$
|
469 |
-
|
470 |
}
|
471 |
-
if ( !$
|
472 |
throw new \Exception( 'Invalid request' );
|
473 |
}
|
474 |
}
|
475 |
|
476 |
-
return $
|
477 |
}
|
478 |
|
479 |
public function getUrl_DirectLinkToOption( string $key ) :string {
|
@@ -572,46 +574,48 @@ abstract class ModCon {
|
|
572 |
}
|
573 |
|
574 |
/**
|
575 |
-
* @param array $
|
576 |
* @return array
|
577 |
*/
|
578 |
-
public function supplySubMenuItem( $
|
579 |
-
|
580 |
-
$sTitle = $this->getOptions()->getFeatureProperty( 'menu_title' );
|
581 |
-
$sTitle = empty( $sTitle ) ? $this->getMainFeatureName() : __( $sTitle, 'wp-simple-firewall' );
|
582 |
|
583 |
-
|
|
|
584 |
|
585 |
-
|
|
|
|
|
586 |
|
587 |
-
|
588 |
-
|
589 |
-
$sTitle = sprintf( '<span class="icwp_highlighted">%s</span>', $sTitle );
|
590 |
}
|
591 |
|
592 |
-
$
|
593 |
-
$
|
594 |
-
$
|
595 |
$this->getModSlug(),
|
596 |
[ $this, 'displayModuleAdminPage' ],
|
597 |
$this->getIfShowModuleMenuItem()
|
598 |
];
|
599 |
|
600 |
-
|
601 |
-
if ( !empty( $aAdditionalItems ) && is_array( $aAdditionalItems ) ) {
|
602 |
|
603 |
-
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
-
|
608 |
-
|
|
|
|
|
|
|
|
|
609 |
true
|
610 |
];
|
611 |
}
|
612 |
}
|
613 |
}
|
614 |
-
return $
|
615 |
}
|
616 |
|
617 |
/**
|
@@ -620,13 +624,13 @@ abstract class ModCon {
|
|
620 |
* This can of course be extended for any other types of redirect.
|
621 |
*/
|
622 |
public function handleAutoPageRedirects() {
|
623 |
-
$
|
624 |
-
if ( !empty( $
|
625 |
-
foreach ( $
|
626 |
-
if ( Services::Request()->query( 'page' ) == $this->prefix( $
|
627 |
Services::Response()->redirect(
|
628 |
-
$this->getCon()->getModule( $
|
629 |
-
$
|
630 |
true,
|
631 |
false
|
632 |
);
|
@@ -635,13 +639,6 @@ abstract class ModCon {
|
|
635 |
}
|
636 |
}
|
637 |
|
638 |
-
/**
|
639 |
-
* @return array
|
640 |
-
*/
|
641 |
-
protected function getAdditionalMenuItem() {
|
642 |
-
return [];
|
643 |
-
}
|
644 |
-
|
645 |
/**
|
646 |
* TODO: not the place for this method.
|
647 |
* @return array[]
|
@@ -922,6 +919,28 @@ abstract class ModCon {
|
|
922 |
}
|
923 |
|
924 |
protected function handleModAction( string $action ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
925 |
}
|
926 |
|
927 |
/**
|
@@ -1065,7 +1084,7 @@ abstract class ModCon {
|
|
1065 |
}
|
1066 |
|
1067 |
protected function isWizardPage() :bool {
|
1068 |
-
return
|
1069 |
}
|
1070 |
|
1071 |
/**
|
@@ -1087,13 +1106,13 @@ abstract class ModCon {
|
|
1087 |
|
1088 |
/**
|
1089 |
* Override this to customize anything with the display of the page
|
1090 |
-
* @param array $
|
1091 |
* @return string
|
1092 |
*/
|
1093 |
-
protected function renderModulePage( array $
|
1094 |
return $this->renderTemplate(
|
1095 |
'index.php',
|
1096 |
-
Services::DataManipulation()->mergeArraysRecursive( $this->getUIHandler()->getBaseDisplayData(), $
|
1097 |
);
|
1098 |
}
|
1099 |
|
@@ -1129,27 +1148,27 @@ abstract class ModCon {
|
|
1129 |
}
|
1130 |
|
1131 |
/**
|
1132 |
-
* @param string $
|
1133 |
* @return string
|
1134 |
* @uses nonce
|
1135 |
*/
|
1136 |
-
public function getUrl_Wizard( $
|
1137 |
-
$
|
1138 |
-
if ( empty( $
|
1139 |
-
$
|
1140 |
}
|
1141 |
else {
|
1142 |
-
$
|
1143 |
}
|
1144 |
|
1145 |
return add_query_arg(
|
1146 |
[
|
1147 |
'page' => $this->getModSlug(),
|
1148 |
'shield_action' => 'wizard',
|
1149 |
-
'wizard' => $
|
1150 |
-
'nonwizard' => wp_create_nonce( 'wizard'.$
|
1151 |
],
|
1152 |
-
$
|
1153 |
);
|
1154 |
}
|
1155 |
|
@@ -1161,44 +1180,31 @@ abstract class ModCon {
|
|
1161 |
}
|
1162 |
|
1163 |
/**
|
1164 |
-
* @param string $
|
1165 |
* @return array
|
1166 |
*/
|
1167 |
-
public function getWizardDefinition( $
|
1168 |
-
$
|
1169 |
-
if ( $this->hasWizardDefinition( $
|
1170 |
-
$
|
1171 |
-
$aDef = $aW[ $sWizardSlug ];
|
1172 |
}
|
1173 |
-
return $
|
1174 |
}
|
1175 |
|
1176 |
-
|
1177 |
-
|
1178 |
-
*/
|
1179 |
-
public function getWizardDefinitions() {
|
1180 |
-
$aW = $this->getDef( 'wizards' );
|
1181 |
-
return is_array( $aW ) ? $aW : [];
|
1182 |
}
|
1183 |
|
1184 |
public function hasWizard() :bool {
|
1185 |
return count( $this->getWizardDefinitions() ) > 0;
|
1186 |
}
|
1187 |
|
1188 |
-
|
1189 |
-
|
1190 |
-
* @return bool
|
1191 |
-
*/
|
1192 |
-
public function hasWizardDefinition( $sWizardSlug ) {
|
1193 |
-
$aW = $this->getWizardDefinitions();
|
1194 |
-
return !empty( $aW[ $sWizardSlug ] );
|
1195 |
}
|
1196 |
|
1197 |
-
|
1198 |
-
|
1199 |
-
*/
|
1200 |
-
public function getIsShowMarketing() {
|
1201 |
-
return apply_filters( $this->prefix( 'show_marketing' ), !$this->isPremium() );
|
1202 |
}
|
1203 |
|
1204 |
/**
|
31 |
protected $bImportExportWhitelistNotify = false;
|
32 |
|
33 |
/**
|
34 |
+
* @var Shield\Modules\Base\Processor
|
35 |
*/
|
36 |
private $oProcessor;
|
37 |
|
146 |
*/
|
147 |
protected function getDbHandlers( $bInitAll = false ) {
|
148 |
if ( $bInitAll ) {
|
149 |
+
foreach ( $this->getAllDbClasses() as $dbSlug => $dbClass ) {
|
150 |
+
$this->getDbH( $dbSlug );
|
151 |
}
|
152 |
}
|
153 |
return is_array( $this->aDbHandlers ) ? $this->aDbHandlers : [];
|
171 |
$aDbClasses = $this->getAllDbClasses();
|
172 |
if ( isset( $aDbClasses[ $dbhKey ] ) ) {
|
173 |
/** @var Shield\Databases\Base\Handler $dbh */
|
174 |
+
$dbh = new $aDbClasses[ $dbhKey ]( $dbhKey );
|
175 |
try {
|
176 |
+
// TODO remove 10.3: method_exists + table init
|
177 |
+
if ( method_exists( $dbh, 'execute' ) ) {
|
178 |
+
$dbh->setMod( $this )->execute();
|
179 |
+
}
|
180 |
+
else {
|
181 |
+
$dbh->setMod( $this )->tableInit();
|
182 |
+
}
|
183 |
}
|
184 |
catch ( \Exception $e ) {
|
185 |
}
|
416 |
}
|
417 |
|
418 |
/**
|
419 |
+
* @return Shield\Modules\Base\Processor|\FernleafSystems\Utilities\Logic\ExecOnce|mixed
|
420 |
*/
|
421 |
public function getProcessor() {
|
422 |
return $this->loadProcessor();
|
430 |
);
|
431 |
}
|
432 |
|
433 |
+
public function buildAdminActionNonceUrl( string $action ) :string {
|
434 |
+
$nonce = $this->getNonceActionData( $action );
|
435 |
+
$nonce[ 'ts' ] = Services::Request()->ts();
|
436 |
+
return add_query_arg( $nonce, $this->getUrl_AdminPage() );
|
|
|
|
|
|
|
|
|
437 |
}
|
438 |
|
439 |
protected function getModActionParams( string $action ) :array {
|
444 |
'mod_slug' => $this->getModSlug(),
|
445 |
'ts' => Services::Request()->ts(),
|
446 |
'exec_nonce' => substr(
|
447 |
+
hash_hmac( 'md5', $action.Services::Request()->ts(), $con->getSiteInstallationId() ), 0, 6
|
448 |
+
)
|
449 |
];
|
450 |
}
|
451 |
|
454 |
* @throws \Exception
|
455 |
*/
|
456 |
protected function verifyModActionRequest() :bool {
|
457 |
+
$valid = false;
|
458 |
|
459 |
$con = $this->getCon();
|
460 |
$req = Services::Request();
|
461 |
|
462 |
+
$exec = $req->request( 'exec' );
|
463 |
+
if ( !empty( $exec ) && $req->request( 'action' ) == $con->prefix() ) {
|
464 |
|
465 |
|
466 |
+
if ( wp_verify_nonce( $req->request( 'exec_nonce' ), $exec ) && $con->getMeetsBasePermissions() ) {
|
467 |
+
$valid = true;
|
468 |
}
|
469 |
else {
|
470 |
+
$valid = $req->request( 'exec_nonce' ) ===
|
471 |
+
substr( hash_hmac( 'md5', $exec.$req->request( 'ts' ), $con->getSiteInstallationId() ), 0, 6 );
|
472 |
}
|
473 |
+
if ( !$valid ) {
|
474 |
throw new \Exception( 'Invalid request' );
|
475 |
}
|
476 |
}
|
477 |
|
478 |
+
return $valid;
|
479 |
}
|
480 |
|
481 |
public function getUrl_DirectLinkToOption( string $key ) :string {
|
574 |
}
|
575 |
|
576 |
/**
|
577 |
+
* @param array $items
|
578 |
* @return array
|
579 |
*/
|
580 |
+
public function supplySubMenuItem( $items ) {
|
|
|
|
|
|
|
581 |
|
582 |
+
$title = $this->getOptions()->getFeatureProperty( 'menu_title' );
|
583 |
+
$title = empty( $title ) ? $this->getMainFeatureName() : __( $title, 'wp-simple-firewall' );
|
584 |
|
585 |
+
if ( !empty( $title ) ) {
|
586 |
+
$highlightedTemplate = '<span class="icwp_highlighted">%s</span>';
|
587 |
+
$humanName = $this->getCon()->getHumanName();
|
588 |
|
589 |
+
if ( $this->getOptions()->getFeatureProperty( 'highlight_menu_item' ) ) {
|
590 |
+
$title = sprintf( $highlightedTemplate, $title );
|
|
|
591 |
}
|
592 |
|
593 |
+
$menuPageTitle = $title.' - '.$humanName;
|
594 |
+
$items[ $menuPageTitle ] = [
|
595 |
+
$title,
|
596 |
$this->getModSlug(),
|
597 |
[ $this, 'displayModuleAdminPage' ],
|
598 |
$this->getIfShowModuleMenuItem()
|
599 |
];
|
600 |
|
601 |
+
foreach ( $this->getOptions()->getAdditionalMenuItems() as $menuItem ) {
|
|
|
602 |
|
603 |
+
// special case: don't show go pro if you're pro.
|
604 |
+
if ( $menuItem[ 'slug' ] !== 'pro-redirect' || !$this->isPremium() ) {
|
605 |
+
|
606 |
+
$title = __( $menuItem[ 'title' ], 'wp-simple-firewall' );
|
607 |
+
$menuPageTitle = $humanName.' - '.$title;
|
608 |
+
$isHighlighted = $menuItem[ 'highlight' ] ?? false;
|
609 |
+
$items[ $menuPageTitle ] = [
|
610 |
+
$isHighlighted ? sprintf( $highlightedTemplate, $title ) : $title,
|
611 |
+
$this->prefix( $menuItem[ 'slug' ] ),
|
612 |
+
[ $this, $menuItem[ 'callback' ] ?? '' ],
|
613 |
true
|
614 |
];
|
615 |
}
|
616 |
}
|
617 |
}
|
618 |
+
return $items;
|
619 |
}
|
620 |
|
621 |
/**
|
624 |
* This can of course be extended for any other types of redirect.
|
625 |
*/
|
626 |
public function handleAutoPageRedirects() {
|
627 |
+
$cfg = $this->getOptions()->getRawData_FullFeatureConfig();
|
628 |
+
if ( !empty( $cfg[ 'custom_redirects' ] ) && $this->getCon()->isValidAdminArea() ) {
|
629 |
+
foreach ( $cfg[ 'custom_redirects' ] as $redirect ) {
|
630 |
+
if ( Services::Request()->query( 'page' ) == $this->prefix( $redirect[ 'source_mod_page' ] ) ) {
|
631 |
Services::Response()->redirect(
|
632 |
+
$this->getCon()->getModule( $redirect[ 'target_mod_page' ] )->getUrl_AdminPage(),
|
633 |
+
$redirect[ 'query_args' ],
|
634 |
true,
|
635 |
false
|
636 |
);
|
639 |
}
|
640 |
}
|
641 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
642 |
/**
|
643 |
* TODO: not the place for this method.
|
644 |
* @return array[]
|
919 |
}
|
920 |
|
921 |
protected function handleModAction( string $action ) {
|
922 |
+
switch ( $action ) {
|
923 |
+
case 'file_download':
|
924 |
+
$id = Services::Request()->query( 'download_id', '' );
|
925 |
+
if ( !empty( $id ) ) {
|
926 |
+
header( 'Set-Cookie: fileDownload=true; path=/' );
|
927 |
+
$this->handleFileDownload( $id );
|
928 |
+
}
|
929 |
+
break;
|
930 |
+
default:
|
931 |
+
break;
|
932 |
+
}
|
933 |
+
}
|
934 |
+
|
935 |
+
protected function handleFileDownload( string $downloadID ) {
|
936 |
+
}
|
937 |
+
|
938 |
+
public function createFileDownloadLink( string $downloadID, array $additionalParams = [] ) :string {
|
939 |
+
$additionalParams[ 'download_id' ] = $downloadID;
|
940 |
+
return add_query_arg(
|
941 |
+
array_merge( $this->getNonceActionData( 'file_download' ), $additionalParams ),
|
942 |
+
$this->getUrl_AdminPage()
|
943 |
+
);
|
944 |
}
|
945 |
|
946 |
/**
|
1084 |
}
|
1085 |
|
1086 |
protected function isWizardPage() :bool {
|
1087 |
+
return $this->getCon()->getShieldAction() == 'wizard' && $this->isThisModulePage();
|
1088 |
}
|
1089 |
|
1090 |
/**
|
1106 |
|
1107 |
/**
|
1108 |
* Override this to customize anything with the display of the page
|
1109 |
+
* @param array $data
|
1110 |
* @return string
|
1111 |
*/
|
1112 |
+
protected function renderModulePage( array $data = [] ) :string {
|
1113 |
return $this->renderTemplate(
|
1114 |
'index.php',
|
1115 |
+
Services::DataManipulation()->mergeArraysRecursive( $this->getUIHandler()->getBaseDisplayData(), $data )
|
1116 |
);
|
1117 |
}
|
1118 |
|
1148 |
}
|
1149 |
|
1150 |
/**
|
1151 |
+
* @param string $wizardSlug
|
1152 |
* @return string
|
1153 |
* @uses nonce
|
1154 |
*/
|
1155 |
+
public function getUrl_Wizard( string $wizardSlug ) :string {
|
1156 |
+
$def = $this->getWizardDefinition( $wizardSlug );
|
1157 |
+
if ( empty( $def[ 'min_user_permissions' ] ) ) { // i.e. no login/minimum perms
|
1158 |
+
$url = Services::WpGeneral()->getHomeUrl();
|
1159 |
}
|
1160 |
else {
|
1161 |
+
$url = Services::WpGeneral()->getAdminUrl( 'admin.php' );
|
1162 |
}
|
1163 |
|
1164 |
return add_query_arg(
|
1165 |
[
|
1166 |
'page' => $this->getModSlug(),
|
1167 |
'shield_action' => 'wizard',
|
1168 |
+
'wizard' => $wizardSlug,
|
1169 |
+
'nonwizard' => wp_create_nonce( 'wizard'.$wizardSlug )
|
1170 |
],
|
1171 |
+
$url
|
1172 |
);
|
1173 |
}
|
1174 |
|
1180 |
}
|
1181 |
|
1182 |
/**
|
1183 |
+
* @param string $wizardSlug
|
1184 |
* @return array
|
1185 |
*/
|
1186 |
+
public function getWizardDefinition( string $wizardSlug ) {
|
1187 |
+
$def = null;
|
1188 |
+
if ( $this->hasWizardDefinition( $wizardSlug ) ) {
|
1189 |
+
$def = $this->getWizardDefinitions()[ $wizardSlug ];
|
|
|
1190 |
}
|
1191 |
+
return $def;
|
1192 |
}
|
1193 |
|
1194 |
+
public function getWizardDefinitions() :array {
|
1195 |
+
return is_array( $this->getDef( 'wizards' ) ) ? $this->getDef( 'wizards' ) : [];
|
|
|
|
|
|
|
|
|
1196 |
}
|
1197 |
|
1198 |
public function hasWizard() :bool {
|
1199 |
return count( $this->getWizardDefinitions() ) > 0;
|
1200 |
}
|
1201 |
|
1202 |
+
public function hasWizardDefinition( string $wizardSlug ) :bool {
|
1203 |
+
return !empty( $this->getWizardDefinitions()[ $wizardSlug ] );
|
|
|
|
|
|
|
|
|
|
|
1204 |
}
|
1205 |
|
1206 |
+
public function getIsShowMarketing() :bool {
|
1207 |
+
return (bool)apply_filters( $this->prefix( 'show_marketing' ), !$this->isPremium() );
|
|
|
|
|
|
|
1208 |
}
|
1209 |
|
1210 |
/**
|
src/lib/src/Modules/Base/Options.php
CHANGED
@@ -179,9 +179,6 @@ class Options {
|
|
179 |
return ( isset( $raw[ 'properties' ] ) && isset( $raw[ 'properties' ][ $sProperty ] ) ) ? $raw[ 'properties' ][ $sProperty ] : null;
|
180 |
}
|
181 |
|
182 |
-
/**
|
183 |
-
* @return array
|
184 |
-
*/
|
185 |
public function getWpCliCfg() :array {
|
186 |
$cfg = $this->getRawData_FullFeatureConfig();
|
187 |
return array_merge(
|
@@ -428,7 +425,7 @@ class Options {
|
|
428 |
}
|
429 |
|
430 |
public function getAdditionalMenuItems() :array {
|
431 |
-
return $this->
|
432 |
}
|
433 |
|
434 |
public function getNeedSave() :bool {
|
@@ -588,9 +585,11 @@ class Options {
|
|
588 |
return $raw[ 'requirements' ] ?? [];
|
589 |
}
|
590 |
|
|
|
|
|
|
|
591 |
protected function getRawData_MenuItems() :array {
|
592 |
-
|
593 |
-
return $raw[ 'menu_items' ] ?? [];
|
594 |
}
|
595 |
|
596 |
public function getRawData_SingleOption( string $key ) :array {
|
179 |
return ( isset( $raw[ 'properties' ] ) && isset( $raw[ 'properties' ][ $sProperty ] ) ) ? $raw[ 'properties' ][ $sProperty ] : null;
|
180 |
}
|
181 |
|
|
|
|
|
|
|
182 |
public function getWpCliCfg() :array {
|
183 |
$cfg = $this->getRawData_FullFeatureConfig();
|
184 |
return array_merge(
|
425 |
}
|
426 |
|
427 |
public function getAdditionalMenuItems() :array {
|
428 |
+
return $this->getRawData_FullFeatureConfig()[ 'menu_items' ] ?? [];
|
429 |
}
|
430 |
|
431 |
public function getNeedSave() :bool {
|
585 |
return $raw[ 'requirements' ] ?? [];
|
586 |
}
|
587 |
|
588 |
+
/**
|
589 |
+
* @deprecated 11.0
|
590 |
+
*/
|
591 |
protected function getRawData_MenuItems() :array {
|
592 |
+
return $this->getRawData_FullFeatureConfig()[ 'menu_items' ] ?? [];
|
|
|
593 |
}
|
594 |
|
595 |
public function getRawData_SingleOption( string $key ) :array {
|
src/lib/src/Modules/Base/Processor.php
CHANGED
@@ -2,14 +2,14 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Logic\
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield;
|
7 |
|
8 |
abstract class Processor {
|
9 |
|
10 |
use Shield\Crons\PluginCronsConsumer;
|
11 |
use Shield\Modules\ModConsumer;
|
12 |
-
use
|
13 |
|
14 |
/**
|
15 |
* @param ModCon $mod
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Logic\ExecOnce;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield;
|
7 |
|
8 |
abstract class Processor {
|
9 |
|
10 |
use Shield\Crons\PluginCronsConsumer;
|
11 |
use Shield\Modules\ModConsumer;
|
12 |
+
use ExecOnce;
|
13 |
|
14 |
/**
|
15 |
* @param ModCon $mod
|
src/lib/src/Modules/Base/UI.php
CHANGED
@@ -171,8 +171,8 @@ class UI {
|
|
171 |
$con = $this->getCon();
|
172 |
$urlBuilder = $con->urls;
|
173 |
|
174 |
-
/** @var Shield\Modules\Plugin\Options $
|
175 |
-
$
|
176 |
|
177 |
return [
|
178 |
'sPluginName' => $con->getHumanName(),
|
@@ -217,16 +217,16 @@ class UI {
|
|
217 |
],
|
218 |
'strings' => $mod->getStrings()->getDisplayStrings(),
|
219 |
'flags' => [
|
220 |
-
'access_restricted'
|
221 |
-
'show_ads'
|
222 |
-
'wrap_page_content'
|
223 |
-
'show_standard_options'
|
224 |
-
'show_content_help'
|
225 |
-
'show_alt_content'
|
226 |
-
'has_wizard'
|
227 |
-
'is_premium'
|
228 |
-
'show_transfer_switch'
|
229 |
-
'is_wpcli'
|
230 |
],
|
231 |
'hrefs' => [
|
232 |
'go_pro' => 'https://shsec.io/shieldgoprofeature',
|
@@ -235,18 +235,17 @@ class UI {
|
|
235 |
'wizard_landing' => $mod->getUrl_WizardLanding(),
|
236 |
|
237 |
'form_action' => Services::Request()->getUri(),
|
238 |
-
'css_bootstrap' => $urlBuilder->forCss( '
|
239 |
'css_pages' => $urlBuilder->forCss( 'pages' ),
|
240 |
'css_steps' => $urlBuilder->forCss( 'jquery.steps' ),
|
241 |
'css_fancybox' => $urlBuilder->forCss( 'jquery.fancybox.min' ),
|
242 |
'css_globalplugin' => $urlBuilder->forCss( 'global-plugin' ),
|
243 |
'css_wizard' => $urlBuilder->forCss( 'wizard' ),
|
244 |
'js_jquery' => Services::Includes()->getUrl_Jquery(),
|
245 |
-
'js_bootstrap' => $urlBuilder->forJs( '
|
246 |
'js_fancybox' => $urlBuilder->forJs( 'jquery.fancybox.min' ),
|
247 |
'js_globalplugin' => $urlBuilder->forJs( 'global-plugin' ),
|
248 |
'js_steps' => $urlBuilder->forJs( 'jquery.steps.min' ),
|
249 |
-
'js_wizard' => $urlBuilder->forJs( 'wizard' ),
|
250 |
],
|
251 |
'imgs' => [
|
252 |
'favicon' => $urlBuilder->forImage( 'pluginlogo_24x24.png' ),
|
171 |
$con = $this->getCon();
|
172 |
$urlBuilder = $con->urls;
|
173 |
|
174 |
+
/** @var Shield\Modules\Plugin\Options $pluginOptions */
|
175 |
+
$pluginOptions = $con->getModule_Plugin()->getOptions();
|
176 |
|
177 |
return [
|
178 |
'sPluginName' => $con->getHumanName(),
|
217 |
],
|
218 |
'strings' => $mod->getStrings()->getDisplayStrings(),
|
219 |
'flags' => [
|
220 |
+
'access_restricted' => !$mod->canDisplayOptionsForm(),
|
221 |
+
'show_ads' => $mod->getIsShowMarketing(),
|
222 |
+
'wrap_page_content' => true,
|
223 |
+
'show_standard_options' => true,
|
224 |
+
'show_content_help' => true,
|
225 |
+
'show_alt_content' => false,
|
226 |
+
'has_wizard' => $mod->hasWizard(),
|
227 |
+
'is_premium' => $con->isPremiumActive(),
|
228 |
+
'show_transfer_switch' => $con->isPremiumActive(),
|
229 |
+
'is_wpcli' => $pluginOptions->isEnabledWpcli(),
|
230 |
],
|
231 |
'hrefs' => [
|
232 |
'go_pro' => 'https://shsec.io/shieldgoprofeature',
|
235 |
'wizard_landing' => $mod->getUrl_WizardLanding(),
|
236 |
|
237 |
'form_action' => Services::Request()->getUri(),
|
238 |
+
'css_bootstrap' => $urlBuilder->forCss( 'bootstrap' ),
|
239 |
'css_pages' => $urlBuilder->forCss( 'pages' ),
|
240 |
'css_steps' => $urlBuilder->forCss( 'jquery.steps' ),
|
241 |
'css_fancybox' => $urlBuilder->forCss( 'jquery.fancybox.min' ),
|
242 |
'css_globalplugin' => $urlBuilder->forCss( 'global-plugin' ),
|
243 |
'css_wizard' => $urlBuilder->forCss( 'wizard' ),
|
244 |
'js_jquery' => Services::Includes()->getUrl_Jquery(),
|
245 |
+
'js_bootstrap' => $urlBuilder->forJs( 'bootstrap' ),
|
246 |
'js_fancybox' => $urlBuilder->forJs( 'jquery.fancybox.min' ),
|
247 |
'js_globalplugin' => $urlBuilder->forJs( 'global-plugin' ),
|
248 |
'js_steps' => $urlBuilder->forJs( 'jquery.steps.min' ),
|
|
|
249 |
],
|
250 |
'imgs' => [
|
251 |
'favicon' => $urlBuilder->forImage( 'pluginlogo_24x24.png' ),
|
src/lib/src/Modules/Base/Upgrade.php
CHANGED
@@ -2,12 +2,13 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
|
4 |
|
|
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
6 |
|
7 |
class Upgrade {
|
8 |
|
9 |
use ModConsumer;
|
10 |
-
use
|
11 |
|
12 |
protected function run() {
|
13 |
$this->upgradeModule();
|
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();
|
src/lib/src/Modules/Base/WpCli.php
CHANGED
@@ -2,18 +2,19 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
|
4 |
|
|
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\WpCli\ModuleStandard;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
7 |
|
8 |
class WpCli {
|
9 |
|
10 |
use ModConsumer;
|
11 |
-
use
|
12 |
|
13 |
protected function run() {
|
14 |
try {
|
15 |
-
foreach ( $this->getAllCmdHandlers() as $
|
16 |
-
$
|
17 |
}
|
18 |
}
|
19 |
catch ( \Exception $e ) {
|
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 ) {
|
src/lib/src/Modules/Base/WpCli/BaseWpCliCmd.php
CHANGED
@@ -9,7 +9,15 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
9 |
abstract class BaseWpCliCmd {
|
10 |
|
11 |
use ModConsumer;
|
12 |
-
use \FernleafSystems\Utilities\Logic\
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
|
14 |
/**
|
15 |
* @throws \Exception
|
@@ -25,58 +33,29 @@ abstract class BaseWpCliCmd {
|
|
25 |
}
|
26 |
}
|
27 |
|
28 |
-
|
29 |
-
* @param array $aParts
|
30 |
-
* @return string
|
31 |
-
*/
|
32 |
-
protected function buildCmd( array $aParts ) {
|
33 |
return implode( ' ',
|
34 |
-
array_filter( array_merge( $this->getBaseCmdParts(), $
|
35 |
);
|
36 |
}
|
37 |
|
38 |
-
/**
|
39 |
-
* @return bool
|
40 |
-
*/
|
41 |
-
protected function canRun() {
|
42 |
-
/** @var Options $oOpts */
|
43 |
-
$oOpts = $this->getCon()
|
44 |
-
->getModule_Plugin()
|
45 |
-
->getOptions();
|
46 |
-
return $this->getOptions()->getWpCliCfg()[ 'enabled' ]
|
47 |
-
&& $oOpts->isEnabledWpcli();
|
48 |
-
}
|
49 |
-
|
50 |
/**
|
51 |
* @return string[]
|
52 |
*/
|
53 |
-
protected function getBaseCmdParts() {
|
54 |
return [ 'shield', $this->getBaseCmdKey() ];
|
55 |
}
|
56 |
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
protected function getBaseCmdKey() {
|
61 |
-
$sRoot = $this->getOptions()->getWpCliCfg()[ 'root' ];
|
62 |
-
return empty( $sRoot ) ? $this->getMod()->getModSlug( false ) : $sRoot;
|
63 |
}
|
64 |
|
65 |
-
|
66 |
-
|
67 |
-
* @return array
|
68 |
-
*/
|
69 |
-
protected function mergeCommonCmdArgs( array $aArgs ) {
|
70 |
-
return array_merge(
|
71 |
-
$this->getCommonCmdArgs(),
|
72 |
-
$aArgs
|
73 |
-
);
|
74 |
}
|
75 |
|
76 |
-
|
77 |
-
* @return array
|
78 |
-
*/
|
79 |
-
protected function getCommonCmdArgs() {
|
80 |
return [
|
81 |
'before_invoke' => function () {
|
82 |
$this->beforeInvokeCmd();
|
@@ -95,36 +74,32 @@ abstract class BaseWpCliCmd {
|
|
95 |
}
|
96 |
|
97 |
/**
|
98 |
-
* @param array $
|
99 |
* @return \WP_User
|
100 |
* @throws \WP_CLI\ExitException
|
101 |
*/
|
102 |
-
protected function loadUserFromArgs( array $
|
103 |
$oWpUsers = Services::WpUsers();
|
104 |
|
105 |
-
$
|
106 |
-
if ( isset( $
|
107 |
-
$
|
108 |
}
|
109 |
-
elseif ( isset( $
|
110 |
-
$
|
111 |
}
|
112 |
-
elseif ( isset( $
|
113 |
-
$
|
114 |
}
|
115 |
|
116 |
-
if ( !$
|
117 |
\WP_CLI::error( "Couldn't find that user." );
|
118 |
}
|
119 |
|
120 |
-
return $
|
121 |
}
|
122 |
|
123 |
-
|
124 |
-
|
125 |
-
* @return bool
|
126 |
-
*/
|
127 |
-
protected function isForceFlag( array $aA ) {
|
128 |
-
return (bool)\WP_CLI\Utils\get_flag_value( $aA, 'force', false );
|
129 |
}
|
130 |
}
|
9 |
abstract class BaseWpCliCmd {
|
10 |
|
11 |
use ModConsumer;
|
12 |
+
use \FernleafSystems\Utilities\Logic\ExecOnce;
|
13 |
+
|
14 |
+
protected function canRun() :bool {
|
15 |
+
/** @var Options $pluginModOpts */
|
16 |
+
$pluginModOpts = $this->getCon()
|
17 |
+
->getModule_Plugin()
|
18 |
+
->getOptions();
|
19 |
+
return $this->getOptions()->getWpCliCfg()[ 'enabled' ] && $pluginModOpts->isEnabledWpcli();
|
20 |
+
}
|
21 |
|
22 |
/**
|
23 |
* @throws \Exception
|
33 |
}
|
34 |
}
|
35 |
|
36 |
+
protected function buildCmd( array $parts ) :string {
|
|
|
|
|
|
|
|
|
37 |
return implode( ' ',
|
38 |
+
array_filter( array_merge( $this->getBaseCmdParts(), $parts ) )
|
39 |
);
|
40 |
}
|
41 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
/**
|
43 |
* @return string[]
|
44 |
*/
|
45 |
+
protected function getBaseCmdParts() :array {
|
46 |
return [ 'shield', $this->getBaseCmdKey() ];
|
47 |
}
|
48 |
|
49 |
+
protected function getBaseCmdKey() :string {
|
50 |
+
$root = $this->getOptions()->getWpCliCfg()[ 'root' ];
|
51 |
+
return empty( $root ) ? $this->getMod()->getModSlug( false ) : $root;
|
|
|
|
|
|
|
52 |
}
|
53 |
|
54 |
+
protected function mergeCommonCmdArgs( array $args ) :array {
|
55 |
+
return array_merge( $this->getCommonCmdArgs(), $args );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
}
|
57 |
|
58 |
+
protected function getCommonCmdArgs() :array {
|
|
|
|
|
|
|
59 |
return [
|
60 |
'before_invoke' => function () {
|
61 |
$this->beforeInvokeCmd();
|
74 |
}
|
75 |
|
76 |
/**
|
77 |
+
* @param array $args
|
78 |
* @return \WP_User
|
79 |
* @throws \WP_CLI\ExitException
|
80 |
*/
|
81 |
+
protected function loadUserFromArgs( array $args ) :\WP_User {
|
82 |
$oWpUsers = Services::WpUsers();
|
83 |
|
84 |
+
$user = null;
|
85 |
+
if ( isset( $args[ 'uid' ] ) ) {
|
86 |
+
$user = $oWpUsers->getUserById( $args[ 'uid' ] );
|
87 |
}
|
88 |
+
elseif ( isset( $args[ 'email' ] ) ) {
|
89 |
+
$user = $oWpUsers->getUserByEmail( $args[ 'email' ] );
|
90 |
}
|
91 |
+
elseif ( isset( $args[ 'username' ] ) ) {
|
92 |
+
$user = $oWpUsers->getUserByUsername( $args[ 'username' ] );
|
93 |
}
|
94 |
|
95 |
+
if ( !$user instanceof \WP_User || $user->ID < 1 ) {
|
96 |
\WP_CLI::error( "Couldn't find that user." );
|
97 |
}
|
98 |
|
99 |
+
return $user;
|
100 |
}
|
101 |
|
102 |
+
protected function isForceFlag( array $args ) :bool {
|
103 |
+
return (bool)\WP_CLI\Utils\get_flag_value( $args, 'force', false );
|
|
|
|
|
|
|
|
|
104 |
}
|
105 |
}
|
src/lib/src/Modules/Base/WpCli/ModuleStandard.php
CHANGED
@@ -92,10 +92,10 @@ class ModuleStandard extends BaseWpCliCmd {
|
|
92 |
] ) );
|
93 |
}
|
94 |
|
95 |
-
public function cmdModAction( $null, $
|
96 |
$oMod = $this->getMod();
|
97 |
|
98 |
-
switch ( $
|
99 |
|
100 |
case 'status':
|
101 |
$oMod->isModOptEnabled() ?
|
@@ -121,13 +121,13 @@ class ModuleStandard extends BaseWpCliCmd {
|
|
121 |
|
122 |
/**
|
123 |
* @param array $null
|
124 |
-
* @param array $
|
125 |
*/
|
126 |
-
public function cmdOptGet( array $null, array $
|
127 |
$oOpts = $this->getOptions();
|
128 |
|
129 |
-
$mVal = $oOpts->getOpt( $
|
130 |
-
$aOpt = $oOpts->getRawData_SingleOption( $
|
131 |
if ( !is_numeric( $mVal ) && empty( $mVal ) ) {
|
132 |
\WP_CLI::log( __( 'No value set.', 'wp-simple-firewall' ) );
|
133 |
}
|
@@ -151,20 +151,20 @@ class ModuleStandard extends BaseWpCliCmd {
|
|
151 |
|
152 |
/**
|
153 |
* @param array $null
|
154 |
-
* @param array $
|
155 |
*/
|
156 |
-
public function cmdOptSet( array $null, array $
|
157 |
-
$this->getOptions()->setOpt( $
|
158 |
\WP_CLI::success( 'Option updated.' );
|
159 |
}
|
160 |
|
161 |
-
public function cmdOptList( array $null, array $
|
162 |
$oOpts = $this->getOptions();
|
163 |
$oStrings = $this->getMod()->getStrings();
|
164 |
-
$
|
165 |
foreach ( $oOpts->getOptionsForWpCli() as $sKey ) {
|
166 |
try {
|
167 |
-
$
|
168 |
'key' => $sKey,
|
169 |
'name' => $oStrings->getOptionStrings( $sKey )[ 'name' ],
|
170 |
'type' => $oOpts->getOptionType( $sKey ),
|
@@ -176,11 +176,11 @@ class ModuleStandard extends BaseWpCliCmd {
|
|
176 |
}
|
177 |
}
|
178 |
|
179 |
-
if ( empty( $
|
180 |
\WP_CLI::log( "This module doesn't have any configurable options." );
|
181 |
}
|
182 |
else {
|
183 |
-
if ( !\WP_CLI\Utils\get_flag_value( $
|
184 |
$aKeys = [
|
185 |
'key',
|
186 |
'name',
|
@@ -188,12 +188,12 @@ class ModuleStandard extends BaseWpCliCmd {
|
|
188 |
];
|
189 |
}
|
190 |
else {
|
191 |
-
$aKeys = array_keys( $
|
192 |
}
|
193 |
|
194 |
\WP_CLI\Utils\format_items(
|
195 |
-
$
|
196 |
-
$
|
197 |
$aKeys
|
198 |
);
|
199 |
}
|
92 |
] ) );
|
93 |
}
|
94 |
|
95 |
+
public function cmdModAction( $null, $args ) {
|
96 |
$oMod = $this->getMod();
|
97 |
|
98 |
+
switch ( $args[ 'action' ] ) {
|
99 |
|
100 |
case 'status':
|
101 |
$oMod->isModOptEnabled() ?
|
121 |
|
122 |
/**
|
123 |
* @param array $null
|
124 |
+
* @param array $args
|
125 |
*/
|
126 |
+
public function cmdOptGet( array $null, array $args ) {
|
127 |
$oOpts = $this->getOptions();
|
128 |
|
129 |
+
$mVal = $oOpts->getOpt( $args[ 'key' ], $null );
|
130 |
+
$aOpt = $oOpts->getRawData_SingleOption( $args[ 'key' ] );
|
131 |
if ( !is_numeric( $mVal ) && empty( $mVal ) ) {
|
132 |
\WP_CLI::log( __( 'No value set.', 'wp-simple-firewall' ) );
|
133 |
}
|
151 |
|
152 |
/**
|
153 |
* @param array $null
|
154 |
+
* @param array $args
|
155 |
*/
|
156 |
+
public function cmdOptSet( array $null, array $args ) {
|
157 |
+
$this->getOptions()->setOpt( $args[ 'key' ], $args[ 'value' ] );
|
158 |
\WP_CLI::success( 'Option updated.' );
|
159 |
}
|
160 |
|
161 |
+
public function cmdOptList( array $null, array $args ) {
|
162 |
$oOpts = $this->getOptions();
|
163 |
$oStrings = $this->getMod()->getStrings();
|
164 |
+
$opts = [];
|
165 |
foreach ( $oOpts->getOptionsForWpCli() as $sKey ) {
|
166 |
try {
|
167 |
+
$opts[] = [
|
168 |
'key' => $sKey,
|
169 |
'name' => $oStrings->getOptionStrings( $sKey )[ 'name' ],
|
170 |
'type' => $oOpts->getOptionType( $sKey ),
|
176 |
}
|
177 |
}
|
178 |
|
179 |
+
if ( empty( $opts ) ) {
|
180 |
\WP_CLI::log( "This module doesn't have any configurable options." );
|
181 |
}
|
182 |
else {
|
183 |
+
if ( !\WP_CLI\Utils\get_flag_value( $args, 'full', false ) ) {
|
184 |
$aKeys = [
|
185 |
'key',
|
186 |
'name',
|
188 |
];
|
189 |
}
|
190 |
else {
|
191 |
+
$aKeys = array_keys( $opts[ 0 ] );
|
192 |
}
|
193 |
|
194 |
\WP_CLI\Utils\format_items(
|
195 |
+
$args[ 'format' ],
|
196 |
+
$opts,
|
197 |
$aKeys
|
198 |
);
|
199 |
}
|
src/lib/src/Modules/BaseShield/ModCon.php
CHANGED
@@ -5,9 +5,9 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
|
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin;
|
|
|
8 |
use FernleafSystems\Wordpress\Services\Services;
|
9 |
use FernleafSystems\Wordpress\Services\Utilities;
|
10 |
-
use FernleafSystems\Wordpress\Services\Utilities\Net\IpIdentify;
|
11 |
|
12 |
class ModCon extends Base\ModCon {
|
13 |
|
@@ -21,20 +21,13 @@ class ModCon extends Base\ModCon {
|
|
21 |
*/
|
22 |
private static $bVisitorIsWhitelisted;
|
23 |
|
24 |
-
/**
|
25 |
-
* @return bool
|
26 |
-
* @deprecated 10.2
|
27 |
-
*/
|
28 |
public function canCacheDirWrite() :bool {
|
29 |
return ( new Shield\Modules\Plugin\Lib\TestCacheDirWrite() )
|
30 |
->setMod( $this->getCon()->getModule_Plugin() )
|
31 |
->canWrite();
|
32 |
}
|
33 |
|
34 |
-
|
35 |
-
* @return Shield\Databases\Session\Handler
|
36 |
-
*/
|
37 |
-
public function getDbHandler_Sessions() {
|
38 |
return $this->getCon()
|
39 |
->getModule_Sessions()
|
40 |
->getDbHandler_Sessions();
|
@@ -50,11 +43,8 @@ class ModCon extends Base\ModCon {
|
|
50 |
->getCurrent();
|
51 |
}
|
52 |
|
53 |
-
|
54 |
-
|
55 |
-
*/
|
56 |
-
public function hasValidRequestIP() {
|
57 |
-
return Services::IP()->isValidIp( Services::IP()->getRequestIp() );
|
58 |
}
|
59 |
|
60 |
public function onWpInit() {
|
@@ -97,11 +87,14 @@ class ModCon extends Base\ModCon {
|
|
97 |
return $cfg;
|
98 |
}
|
99 |
|
|
|
|
|
|
|
100 |
public function getSecAdminLoginAjaxData() :array {
|
101 |
// We set a custom mod_slug so that this module handles the ajax request
|
102 |
-
$
|
103 |
-
$
|
104 |
-
return $
|
105 |
}
|
106 |
|
107 |
protected function getSecAdminCheckAjaxData() :array {
|
@@ -156,10 +149,7 @@ class ModCon extends Base\ModCon {
|
|
156 |
return $this->renderTemplate( '/wpadmin_pages/security_admin/index.twig', $aData, true );
|
157 |
}
|
158 |
|
159 |
-
|
160 |
-
* @return bool
|
161 |
-
*/
|
162 |
-
public function getIfSupport3rdParty() {
|
163 |
return $this->isPremium();
|
164 |
}
|
165 |
|
@@ -177,42 +167,48 @@ class ModCon extends Base\ModCon {
|
|
177 |
|
178 |
public function isVisitorWhitelisted() :bool {
|
179 |
if ( !isset( self::$bVisitorIsWhitelisted ) ) {
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
|
|
186 |
}
|
187 |
-
|
188 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
189 |
}
|
190 |
-
|
191 |
-
self::$bVisitorIsWhitelisted =
|
192 |
-
in_array( $ipID, [ IpIdentify::ICONTROLWP, IpIdentify::MANAGEWP ] )
|
193 |
-
|| ( new Shield\Modules\IPs\Lib\Ops\LookupIpOnList() )
|
194 |
-
->setDbHandler( $this->getCon()->getModule_IPs()->getDbHandler_IPs() )
|
195 |
-
->setIP( Services::IP()->getRequestIp() )
|
196 |
-
->setListTypeWhite()
|
197 |
-
->lookup()
|
198 |
-
instanceof Shield\Databases\IPs\EntryVO;
|
199 |
}
|
200 |
return self::$bVisitorIsWhitelisted;
|
201 |
}
|
202 |
|
203 |
public function isVerifiedBot() :bool {
|
204 |
if ( !isset( self::$bIsVerifiedBot ) ) {
|
205 |
-
$
|
206 |
-
self::$bIsVerifiedBot =
|
207 |
-
!in_array( $
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
] );
|
212 |
}
|
213 |
return self::$bIsVerifiedBot;
|
214 |
}
|
215 |
|
|
|
|
|
|
|
|
|
|
|
|
|
216 |
public function isXmlrpcBypass() :bool {
|
217 |
return $this->getCon()
|
218 |
->getModule_Plugin()
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin;
|
8 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin;
|
9 |
use FernleafSystems\Wordpress\Services\Services;
|
10 |
use FernleafSystems\Wordpress\Services\Utilities;
|
|
|
11 |
|
12 |
class ModCon extends Base\ModCon {
|
13 |
|
21 |
*/
|
22 |
private static $bVisitorIsWhitelisted;
|
23 |
|
|
|
|
|
|
|
|
|
24 |
public function canCacheDirWrite() :bool {
|
25 |
return ( new Shield\Modules\Plugin\Lib\TestCacheDirWrite() )
|
26 |
->setMod( $this->getCon()->getModule_Plugin() )
|
27 |
->canWrite();
|
28 |
}
|
29 |
|
30 |
+
public function getDbHandler_Sessions() :Shield\Databases\Session\Handler {
|
|
|
|
|
|
|
31 |
return $this->getCon()
|
32 |
->getModule_Sessions()
|
33 |
->getDbHandler_Sessions();
|
43 |
->getCurrent();
|
44 |
}
|
45 |
|
46 |
+
public function hasValidRequestIP() :bool {
|
47 |
+
return !empty( Services::IP()->isValidIp( Services::IP()->getRequestIp() ) );
|
|
|
|
|
|
|
48 |
}
|
49 |
|
50 |
public function onWpInit() {
|
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 |
protected function getSecAdminCheckAjaxData() :array {
|
149 |
return $this->renderTemplate( '/wpadmin_pages/security_admin/index.twig', $aData, true );
|
150 |
}
|
151 |
|
152 |
+
public function getIfSupport3rdParty() :bool {
|
|
|
|
|
|
|
153 |
return $this->isPremium();
|
154 |
}
|
155 |
|
167 |
|
168 |
public function isVisitorWhitelisted() :bool {
|
169 |
if ( !isset( self::$bVisitorIsWhitelisted ) ) {
|
170 |
+
|
171 |
+
$ipID = Services::IP()->getIpDetector()->getIPIdentity();
|
172 |
+
|
173 |
+
$untrustedProviders = apply_filters( 'shield/untrusted_service_providers', [] );
|
174 |
+
|
175 |
+
if ( is_array( $untrustedProviders ) && in_array( $ipID, $untrustedProviders ) ) {
|
176 |
+
self::$bVisitorIsWhitelisted = false;
|
177 |
}
|
178 |
+
elseif ( in_array( $ipID, Services::ServiceProviders()->getWpSiteManagementProviders() ) ) {
|
179 |
+
self::$bVisitorIsWhitelisted = true; // iControlWP / ManageWP
|
180 |
+
}
|
181 |
+
else {
|
182 |
+
self::$bVisitorIsWhitelisted =
|
183 |
+
( new Shield\Modules\IPs\Lib\Ops\LookupIpOnList() )
|
184 |
+
->setDbHandler( $this->getCon()->getModule_IPs()->getDbHandler_IPs() )
|
185 |
+
->setIP( Services::IP()->getRequestIp() )
|
186 |
+
->setListTypeWhite()
|
187 |
+
->lookup() instanceof Shield\Databases\IPs\EntryVO;
|
188 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
189 |
}
|
190 |
return self::$bVisitorIsWhitelisted;
|
191 |
}
|
192 |
|
193 |
public function isVerifiedBot() :bool {
|
194 |
if ( !isset( self::$bIsVerifiedBot ) ) {
|
195 |
+
$ipID = Services::IP()->getIpDetector()->getIPIdentity();
|
196 |
+
self::$bIsVerifiedBot = !Services::IP()->isLoopback() &&
|
197 |
+
!in_array( $ipID, [
|
198 |
+
Utilities\Net\IpID::UNKNOWN,
|
199 |
+
Utilities\Net\IpID::THIS_SERVER,
|
200 |
+
Utilities\Net\IpID::VISITOR,
|
201 |
] );
|
202 |
}
|
203 |
return self::$bIsVerifiedBot;
|
204 |
}
|
205 |
|
206 |
+
public function isEnabledWhitelabel() :bool {
|
207 |
+
/** @var SecurityAdmin\Options $opts */
|
208 |
+
$opts = $this->getCon()->getModule_SecAdmin()->getOptions();
|
209 |
+
return $opts->isEnabledWhitelabel();
|
210 |
+
}
|
211 |
+
|
212 |
public function isXmlrpcBypass() :bool {
|
213 |
return $this->getCon()
|
214 |
->getModule_Plugin()
|
src/lib/src/Modules/BaseShield/ShieldProcessor.php
DELETED
@@ -1,14 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
|
4 |
-
|
5 |
-
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
|
6 |
-
|
7 |
-
/**
|
8 |
-
* Class ShieldProcessor
|
9 |
-
* @package FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield
|
10 |
-
* @deprecated 10.2
|
11 |
-
*/
|
12 |
-
class ShieldProcessor extends Base\BaseProcessor {
|
13 |
-
|
14 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/lib/src/Modules/BaseShield/UI.php
CHANGED
@@ -36,15 +36,16 @@ class UI extends Base\UI {
|
|
36 |
'scripts' => []
|
37 |
],
|
38 |
'ajax' => [
|
39 |
-
'sec_admin_login' => $
|
40 |
],
|
41 |
'flags' => [
|
42 |
-
'has_session'
|
43 |
-
|
44 |
-
|
|
|
45 |
],
|
46 |
'hrefs' => [
|
47 |
-
'aar_forget_key' => $con->getModule_SecAdmin()->
|
48 |
$this->getCon()->getLabels()[ 'AuthorURI' ] : 'https://shsec.io/gc'
|
49 |
],
|
50 |
'classes' => [
|
36 |
'scripts' => []
|
37 |
],
|
38 |
'ajax' => [
|
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' => [
|
src/lib/src/Modules/CommentsFilter/AjaxHandler.php
CHANGED
@@ -7,32 +7,27 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
7 |
|
8 |
class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
|
9 |
|
10 |
-
protected function
|
11 |
|
12 |
switch ( $action ) {
|
13 |
case 'comment_token'.Services::IP()->getRequestIp():
|
14 |
-
$
|
15 |
break;
|
16 |
|
17 |
default:
|
18 |
-
$
|
19 |
}
|
20 |
|
21 |
-
return $
|
22 |
}
|
23 |
|
24 |
-
|
25 |
-
|
26 |
-
*/
|
27 |
-
private function ajaxExec_GenCommentToken() {
|
28 |
-
$oReq = Services::Request();
|
29 |
-
$sToken = ( new Shield\Modules\CommentsFilter\Token\Create() )
|
30 |
-
->setMod( $this->getMod() )
|
31 |
-
->run( $oReq->post( 'ts' ), $oReq->post( 'post_id' ) );
|
32 |
-
|
33 |
return [
|
34 |
'success' => true,
|
35 |
-
'token' =>
|
|
|
|
|
36 |
];
|
37 |
}
|
38 |
}
|
7 |
|
8 |
class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
|
9 |
|
10 |
+
protected function processNonAuthAjaxAction( string $action ) :array {
|
11 |
|
12 |
switch ( $action ) {
|
13 |
case 'comment_token'.Services::IP()->getRequestIp():
|
14 |
+
$response = $this->ajaxExec_GenCommentToken();
|
15 |
break;
|
16 |
|
17 |
default:
|
18 |
+
$response = parent::processAjaxAction( $action );
|
19 |
}
|
20 |
|
21 |
+
return $response;
|
22 |
}
|
23 |
|
24 |
+
private function ajaxExec_GenCommentToken() :array {
|
25 |
+
$req = Services::Request();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
return [
|
27 |
'success' => true,
|
28 |
+
'token' => ( new Shield\Modules\CommentsFilter\Token\Create() )
|
29 |
+
->setMod( $this->getMod() )
|
30 |
+
->run( $req->post( 'ts' ), $req->post( 'post_id' ) ),
|
31 |
];
|
32 |
}
|
33 |
}
|
src/lib/src/Modules/CommentsFilter/Forms/Gasp.php
CHANGED
@@ -2,7 +2,8 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter\Forms;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Logic\
|
|
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
8 |
use FernleafSystems\Wordpress\Services\Services;
|
@@ -10,7 +11,7 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
10 |
class Gasp {
|
11 |
|
12 |
use ModConsumer;
|
13 |
-
use
|
14 |
|
15 |
/**
|
16 |
* The unique comment token assigned to this page
|
@@ -21,9 +22,9 @@ class Gasp {
|
|
21 |
/**
|
22 |
* @var bool
|
23 |
*/
|
24 |
-
private $
|
25 |
|
26 |
-
protected function canRun() {
|
27 |
/** @var CommentsFilter\Options $opts */
|
28 |
$opts = $this->getOptions();
|
29 |
return !Services::Request()->isPost() && $opts->isEnabledGaspCheck() && !Services::WpUsers()->isUserLoggedIn();
|
@@ -32,76 +33,73 @@ class Gasp {
|
|
32 |
protected function run() {
|
33 |
add_action( 'wp', [ $this, 'onWP' ] );
|
34 |
add_action( 'wp_footer', [ $this, 'maybeDequeueScript' ] );
|
35 |
-
add_action( 'wp_enqueue_scripts', [ $this, 'onWpEnqueueJs' ] );
|
36 |
}
|
37 |
|
38 |
public function onWP() {
|
|
|
39 |
add_action( 'comment_form', [ $this, 'printGaspFormItems' ], 1 );
|
40 |
}
|
41 |
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
]
|
90 |
-
]
|
91 |
-
);
|
92 |
}
|
93 |
|
94 |
/**
|
95 |
* If the comment form component hasn't been printed, there's no comment form to protect.
|
96 |
*/
|
97 |
public function maybeDequeueScript() {
|
98 |
-
if ( empty( $this->
|
99 |
-
wp_dequeue_script( $this->getCon()->prefix( 'shield
|
100 |
}
|
101 |
}
|
102 |
|
103 |
public function printGaspFormItems() {
|
104 |
-
$this->
|
105 |
echo $this->getMod()
|
106 |
->renderTemplate(
|
107 |
'snippets/comment_form_botbox.twig',
|
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;
|
11 |
class Gasp {
|
12 |
|
13 |
use ModConsumer;
|
14 |
+
use ExecOnce;
|
15 |
|
16 |
/**
|
17 |
* The unique comment token assigned to this page
|
22 |
/**
|
23 |
* @var bool
|
24 |
*/
|
25 |
+
private $formItemsPrinted = false;
|
26 |
|
27 |
+
protected function canRun() :bool {
|
28 |
/** @var CommentsFilter\Options $opts */
|
29 |
$opts = $this->getOptions();
|
30 |
return !Services::Request()->isPost() && $opts->isEnabledGaspCheck() && !Services::WpUsers()->isUserLoggedIn();
|
33 |
protected function run() {
|
34 |
add_action( 'wp', [ $this, 'onWP' ] );
|
35 |
add_action( 'wp_footer', [ $this, 'maybeDequeueScript' ] );
|
|
|
36 |
}
|
37 |
|
38 |
public function onWP() {
|
39 |
+
$this->enqueueJS();
|
40 |
add_action( 'comment_form', [ $this, 'printGaspFormItems' ], 1 );
|
41 |
}
|
42 |
|
43 |
+
protected function enqueueJS() {
|
44 |
+
add_filter( 'shield/custom_enqueues', function ( array $enqueues ) {
|
45 |
+
$enqueues[ Enqueue::JS ][] = 'shield/comments';
|
46 |
+
|
47 |
+
add_filter( 'shield/custom_localisations', function ( array $localz ) {
|
48 |
+
/** @var CommentsFilter\ModCon $mod */
|
49 |
+
$mod = $this->getMod();
|
50 |
+
/** @var CommentsFilter\Options $opts */
|
51 |
+
$opts = $this->getOptions();
|
52 |
+
|
53 |
+
$ts = Services::Request()->ts();
|
54 |
+
$nonce = $mod->getAjaxActionData( 'comment_token'.Services::IP()->getRequestIp() );
|
55 |
+
$nonce[ 'ts' ] = $ts;
|
56 |
+
$nonce[ 'post_id' ] = Services::WpPost()->getCurrentPostId();
|
57 |
+
|
58 |
+
$localz[] = [
|
59 |
+
'shield/comments',
|
60 |
+
'shield_comments',
|
61 |
+
[
|
62 |
+
'ajax' => [
|
63 |
+
'comment_token' => $nonce,
|
64 |
+
],
|
65 |
+
'vars' => [
|
66 |
+
'cbname' => 'cb_nombre'.rand(),
|
67 |
+
'botts' => $ts,
|
68 |
+
'token' => 'not created',
|
69 |
+
'uniq' => $this->getUniqueFormId(),
|
70 |
+
'cooldown' => $opts->getTokenCooldown(),
|
71 |
+
'expires' => $opts->getTokenExpireInterval(),
|
72 |
+
],
|
73 |
+
'strings' => [
|
74 |
+
'label' => $mod->getTextOpt( 'custom_message_checkbox' ),
|
75 |
+
'alert' => $mod->getTextOpt( 'custom_message_alert' ),
|
76 |
+
'comment_reload' => $mod->getTextOpt( 'custom_message_comment_reload' ),
|
77 |
+
'js_comment_wait' => $mod->getTextOpt( 'custom_message_comment_wait' ),
|
78 |
+
],
|
79 |
+
'flags' => [
|
80 |
+
'gasp' => true,
|
81 |
+
'recap' => $opts->isEnabledCaptcha() && $mod->getCaptchaCfg()->ready,
|
82 |
+
]
|
83 |
+
]
|
84 |
+
];
|
85 |
+
return $localz;
|
86 |
+
} );
|
87 |
+
|
88 |
+
return $enqueues;
|
89 |
+
} );
|
|
|
|
|
|
|
90 |
}
|
91 |
|
92 |
/**
|
93 |
* If the comment form component hasn't been printed, there's no comment form to protect.
|
94 |
*/
|
95 |
public function maybeDequeueScript() {
|
96 |
+
if ( empty( $this->formItemsPrinted ) ) {
|
97 |
+
wp_dequeue_script( $this->getCon()->prefix( 'shield/comments' ) );
|
98 |
}
|
99 |
}
|
100 |
|
101 |
public function printGaspFormItems() {
|
102 |
+
$this->formItemsPrinted = true;
|
103 |
echo $this->getMod()
|
104 |
->renderTemplate(
|
105 |
'snippets/comment_form_botbox.twig',
|
src/lib/src/Modules/CommentsFilter/Forms/GoogleRecaptcha.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter\Forms;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Logic\
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
8 |
use FernleafSystems\Wordpress\Services\Services;
|
@@ -10,9 +10,9 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
10 |
class GoogleRecaptcha {
|
11 |
|
12 |
use ModConsumer;
|
13 |
-
use
|
14 |
|
15 |
-
protected function canRun() {
|
16 |
/** @var CommentsFilter\ModCon $mod */
|
17 |
$mod = $this->getMod();
|
18 |
/** @var CommentsFilter\Options $opts */
|
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;
|
10 |
class GoogleRecaptcha {
|
11 |
|
12 |
use ModConsumer;
|
13 |
+
use ExecOnce;
|
14 |
|
15 |
+
protected function canRun() :bool {
|
16 |
/** @var CommentsFilter\ModCon $mod */
|
17 |
$mod = $this->getMod();
|
18 |
/** @var CommentsFilter\Options $opts */
|
src/lib/src/Modules/CommentsFilter/Insights/OverviewCards.php
CHANGED
@@ -25,10 +25,11 @@ class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
|
|
25 |
$cards[ 'mod' ] = $this->getModDisabledCard();
|
26 |
}
|
27 |
else {
|
|
|
28 |
$cards[ 'bot' ] = [
|
29 |
'name' => __( 'Bot SPAM', 'wp-simple-firewall' ),
|
30 |
-
'state' =>
|
31 |
-
'summary' =>
|
32 |
__( 'Bot SPAM comments are blocked', 'wp-simple-firewall' )
|
33 |
: __( 'There is no protection against Bot SPAM comments', 'wp-simple-firewall' ),
|
34 |
'href' => $mod->getUrl_DirectLinkToSection( 'section_bot_comment_spam_protection_filter' ),
|
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' ),
|
31 |
+
'state' => $botSpamOn ? 1 : -1,
|
32 |
+
'summary' => $botSpamOn ?
|
33 |
__( 'Bot SPAM comments are blocked', 'wp-simple-firewall' )
|
34 |
: __( 'There is no protection against Bot SPAM comments', 'wp-simple-firewall' ),
|
35 |
'href' => $mod->getUrl_DirectLinkToSection( 'section_bot_comment_spam_protection_filter' ),
|
src/lib/src/Modules/CommentsFilter/ModCon.php
CHANGED
@@ -73,6 +73,11 @@ class ModCon extends BaseShield\ModCon {
|
|
73 |
);
|
74 |
|
75 |
$this->ensureCorrectCaptchaConfig();
|
|
|
|
|
|
|
|
|
|
|
76 |
}
|
77 |
|
78 |
public function isEnabledCaptcha() :bool {
|
73 |
);
|
74 |
|
75 |
$this->ensureCorrectCaptchaConfig();
|
76 |
+
|
77 |
+
if ( $opts->isEnabledAntiBot() ) {
|
78 |
+
$opts->setOpt( 'google_recaptcha_style_comments', 'disabled' );
|
79 |
+
$opts->setOpt( 'enable_comments_gasp_protection', 'N' );
|
80 |
+
}
|
81 |
}
|
82 |
|
83 |
public function isEnabledCaptcha() :bool {
|
src/lib/src/Modules/CommentsFilter/Options.php
CHANGED
@@ -53,11 +53,16 @@ class Options extends BaseShield\Options {
|
|
53 |
|
54 |
public function isEnabledGaspCheck() :bool {
|
55 |
return $this->isOpt( 'enable_comments_gasp_protection', 'Y' )
|
56 |
-
&& ( $this->getTokenExpireInterval() > $this->getTokenCooldown() )
|
|
|
|
|
|
|
|
|
|
|
57 |
}
|
58 |
|
59 |
public function isEnabledCaptcha() :bool {
|
60 |
-
return !$this->isOpt( 'google_recaptcha_style_comments', 'disabled' );
|
61 |
}
|
62 |
|
63 |
public function isEnabledHumanCheck() :bool {
|
53 |
|
54 |
public function isEnabledGaspCheck() :bool {
|
55 |
return $this->isOpt( 'enable_comments_gasp_protection', 'Y' )
|
56 |
+
&& ( $this->getTokenExpireInterval() > $this->getTokenCooldown() )
|
57 |
+
&& !$this->isEnabledAntiBot();
|
58 |
+
}
|
59 |
+
|
60 |
+
public function isEnabledAntiBot() :bool {
|
61 |
+
return $this->isOpt( 'enable_antibot_check', 'Y' );
|
62 |
}
|
63 |
|
64 |
public function isEnabledCaptcha() :bool {
|
65 |
+
return !$this->isOpt( 'google_recaptcha_style_comments', 'disabled' ) && !$this->isEnabledAntiBot();
|
66 |
}
|
67 |
|
68 |
public function isEnabledHumanCheck() :bool {
|
src/lib/src/Modules/CommentsFilter/Processor.php
CHANGED
@@ -10,16 +10,20 @@ class Processor extends BaseShield\Processor {
|
|
10 |
public function onWpInit() {
|
11 |
/** @var Options $opts */
|
12 |
$opts = $this->getOptions();
|
13 |
-
$
|
14 |
|
15 |
-
$
|
16 |
!( new Scan\IsEmailTrusted() )->trusted(
|
17 |
-
$
|
18 |
$opts->getApprovedMinimum(),
|
19 |
$opts->getTrustedRoles()
|
20 |
);
|
21 |
|
22 |
-
|
|
|
|
|
|
|
|
|
23 |
|
24 |
( new Forms\GoogleRecaptcha() )
|
25 |
->setMod( $this->getMod() )
|
10 |
public function onWpInit() {
|
11 |
/** @var Options $opts */
|
12 |
$opts = $this->getOptions();
|
13 |
+
$WPU = Services::WpUsers();
|
14 |
|
15 |
+
$loadCommentFilter = !$WPU->isUserLoggedIn() ||
|
16 |
!( new Scan\IsEmailTrusted() )->trusted(
|
17 |
+
$WPU->getCurrentWpUser()->user_email,
|
18 |
$opts->getApprovedMinimum(),
|
19 |
$opts->getTrustedRoles()
|
20 |
);
|
21 |
|
22 |
+
( new Scan\CommentAdditiveCleaner() )
|
23 |
+
->setMod( $this->getMod() )
|
24 |
+
->execute();
|
25 |
+
|
26 |
+
if ( $loadCommentFilter ) {
|
27 |
|
28 |
( new Forms\GoogleRecaptcha() )
|
29 |
->setMod( $this->getMod() )
|
src/lib/src/Modules/CommentsFilter/Scan/AntiBot.php
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter\Scan;
|
4 |
+
|
5 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
6 |
+
|
7 |
+
class AntiBot {
|
8 |
+
|
9 |
+
use ModConsumer;
|
10 |
+
|
11 |
+
/**
|
12 |
+
* @return bool
|
13 |
+
* @throws \Exception
|
14 |
+
*/
|
15 |
+
public function scan() :bool {
|
16 |
+
$isBot = $this->getCon()
|
17 |
+
->getModule_IPs()
|
18 |
+
->getBotSignalsController()
|
19 |
+
->isBot();
|
20 |
+
if ( $isBot ) {
|
21 |
+
throw new \Exception( __( 'Failed AntiBot Verification', 'wp-simple-firewall' ) );
|
22 |
+
}
|
23 |
+
return true;
|
24 |
+
}
|
25 |
+
}
|
src/lib/src/Modules/CommentsFilter/Scan/Bot.php
CHANGED
@@ -15,46 +15,46 @@ class Bot {
|
|
15 |
* @return true|\WP_Error
|
16 |
*/
|
17 |
public function scan( $nPostId ) {
|
18 |
-
/** @var CommentsFilter\Options $
|
19 |
-
$
|
|
|
20 |
|
21 |
-
$
|
22 |
-
$
|
23 |
-
$
|
24 |
-
$
|
25 |
-
$sCommentToken = $oReq->post( 'comment_token' );
|
26 |
|
27 |
-
$
|
28 |
-
$
|
29 |
|
30 |
-
$
|
31 |
-
$
|
32 |
-
if ( !$sFieldCheckboxName || !$
|
33 |
-
$
|
34 |
-
$
|
35 |
}
|
36 |
// honeypot check
|
37 |
elseif ( !empty( $sFieldHoney ) ) {
|
38 |
-
$
|
39 |
-
$
|
40 |
}
|
41 |
-
elseif ( $
|
42 |
|
43 |
-
if ( $
|
44 |
-
$
|
45 |
-
$
|
46 |
}
|
47 |
-
elseif ( $
|
48 |
-
$
|
49 |
-
$
|
50 |
}
|
51 |
elseif ( !$this->checkTokenHash( $sCommentToken, $nCommentTs, $nPostId ) ) {
|
52 |
-
$
|
53 |
-
$
|
54 |
}
|
55 |
}
|
56 |
|
57 |
-
return empty( $
|
58 |
}
|
59 |
|
60 |
/**
|
15 |
* @return true|\WP_Error
|
16 |
*/
|
17 |
public function scan( $nPostId ) {
|
18 |
+
/** @var CommentsFilter\Options $opts */
|
19 |
+
$opts = $this->getOptions();
|
20 |
+
$req = Services::Request();
|
21 |
|
22 |
+
$sFieldCheckboxName = $req->post( 'cb_nombre' );
|
23 |
+
$sFieldHoney = $req->post( 'sugar_sweet_email' );
|
24 |
+
$nCommentTs = (int)$req->post( 'botts' );
|
25 |
+
$sCommentToken = $req->post( 'comment_token' );
|
|
|
26 |
|
27 |
+
$cooldown = $opts->getTokenCooldown();
|
28 |
+
$expire = $opts->getTokenExpireInterval();
|
29 |
|
30 |
+
$key = null;
|
31 |
+
$explanation = null;
|
32 |
+
if ( !$sFieldCheckboxName || !$req->post( $sFieldCheckboxName ) ) {
|
33 |
+
$explanation = sprintf( __( 'Failed Bot Test (%s)', 'wp-simple-firewall' ), __( 'checkbox', 'wp-simple-firewall' ) );
|
34 |
+
$key = 'checkbox';
|
35 |
}
|
36 |
// honeypot check
|
37 |
elseif ( !empty( $sFieldHoney ) ) {
|
38 |
+
$explanation = sprintf( __( 'Failed Bot Test (%s)', 'wp-simple-firewall' ), __( 'honeypot', 'wp-simple-firewall' ) );
|
39 |
+
$key = 'honeypot';
|
40 |
}
|
41 |
+
elseif ( $cooldown > 0 || $expire > 0 ) {
|
42 |
|
43 |
+
if ( $cooldown > 0 && $req->ts() < ( $nCommentTs + $cooldown ) ) {
|
44 |
+
$explanation = sprintf( __( 'Failed Bot Test (%s)', 'wp-simple-firewall' ), __( 'cooldown', 'wp-simple-firewall' ) );
|
45 |
+
$key = 'cooldown';
|
46 |
}
|
47 |
+
elseif ( $expire > 0 && $req->ts() > ( $nCommentTs + $expire ) ) {
|
48 |
+
$explanation = sprintf( __( 'Failed Bot Test (%s)', 'wp-simple-firewall' ), __( 'expired', 'wp-simple-firewall' ) );
|
49 |
+
$key = 'expired';
|
50 |
}
|
51 |
elseif ( !$this->checkTokenHash( $sCommentToken, $nCommentTs, $nPostId ) ) {
|
52 |
+
$explanation = sprintf( __( 'Failed Bot Test (%s)', 'wp-simple-firewall' ), __( 'token', 'wp-simple-firewall' ) );
|
53 |
+
$key = 'token';
|
54 |
}
|
55 |
}
|
56 |
|
57 |
+
return empty( $key ) ? true : new \WP_Error( 'bot', $explanation, [ 'type' => $key ] );
|
58 |
}
|
59 |
|
60 |
/**
|
src/lib/src/Modules/CommentsFilter/Scan/CommentAdditiveCleaner.php
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
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 ) {
|
16 |
+
if ( in_array( $newStatus, [ '0', 'hold', '1', 'approve' ], true ) ) {
|
17 |
+
wp_update_comment(
|
18 |
+
[
|
19 |
+
'comment_ID' => $commentID,
|
20 |
+
'comment_content' => preg_replace( '/## Comment SPAM Protection:.*\s##/m', '', get_comment( $commentID )->comment_content ),
|
21 |
+
]
|
22 |
+
);
|
23 |
+
}
|
24 |
+
}, 10, 2 );
|
25 |
+
}
|
26 |
+
}
|
src/lib/src/Modules/CommentsFilter/Scan/Human.php
CHANGED
@@ -1,9 +1,10 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter\Scan;
|
4 |
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
|
|
7 |
use FernleafSystems\Wordpress\Services\Services;
|
8 |
|
9 |
class Human {
|
@@ -21,7 +22,9 @@ class Human {
|
|
21 |
/** @var CommentsFilter\Options $opts */
|
22 |
$opts = $this->getOptions();
|
23 |
|
24 |
-
$
|
|
|
|
|
25 |
[
|
26 |
'comment_content' => $aCommData[ 'comment_content' ],
|
27 |
'url' => $aCommData[ 'comment_author_url' ],
|
@@ -33,67 +36,24 @@ class Human {
|
|
33 |
array_flip( $opts->getHumanSpamFilterItems() )
|
34 |
);
|
35 |
|
36 |
-
$
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
}
|
53 |
|
54 |
return $mResult;
|
55 |
}
|
56 |
-
|
57 |
-
/**
|
58 |
-
* @return string[]
|
59 |
-
*/
|
60 |
-
private function getSpamBlacklist() {
|
61 |
-
/** @var CommentsFilter\ModCon $mod */
|
62 |
-
$mod = $this->getMod();
|
63 |
-
$aList = [];
|
64 |
-
$oFs = Services::WpFs();
|
65 |
-
$sBLFile = $mod->getSpamBlacklistFile();
|
66 |
-
|
67 |
-
// Download if doesn't exist or expired.
|
68 |
-
if ( !$oFs->exists( $sBLFile )
|
69 |
-
|| ( Services::Request()->ts() - $oFs->getModifiedTime( $sBLFile ) > WEEK_IN_SECONDS ) ) {
|
70 |
-
Services::WpFs()->deleteFile( $sBLFile );
|
71 |
-
$this->importBlacklist();
|
72 |
-
}
|
73 |
-
|
74 |
-
if ( $oFs->exists( $sBLFile ) ) {
|
75 |
-
$sList = $oFs->getFileContent( $sBLFile, true );
|
76 |
-
if ( !empty( $sList ) ) {
|
77 |
-
$aList = array_map( 'base64_decode', explode( "\n", $sList ) );
|
78 |
-
}
|
79 |
-
}
|
80 |
-
return $aList;
|
81 |
-
}
|
82 |
-
|
83 |
-
private function importBlacklist() {
|
84 |
-
/** @var CommentsFilter\ModCon $mod */
|
85 |
-
$mod = $this->getMod();
|
86 |
-
$FS = Services::WpFs();
|
87 |
-
$sBLFile = $mod->getSpamBlacklistFile();
|
88 |
-
if ( !$FS->exists( $sBLFile ) ) {
|
89 |
-
$sRawList = Services::HttpRequest()->getContent( $this->getOptions()
|
90 |
-
->getDef( 'url_spam_blacklist_terms' ) );
|
91 |
-
$sList = '';
|
92 |
-
if ( !empty( $sRawList ) ) {
|
93 |
-
$sList = implode( "\n", array_map( 'base64_encode', array_filter( array_map( 'trim', explode( "\n", $sRawList ) ) ) ) );
|
94 |
-
}
|
95 |
-
// save the list to disk for the future.
|
96 |
-
$FS->putFileContent( $sBLFile, $sList, true );
|
97 |
-
}
|
98 |
-
}
|
99 |
}
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter\Scan;
|
4 |
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
7 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Utilities\HumanSpam\TestContent;
|
8 |
use FernleafSystems\Wordpress\Services\Services;
|
9 |
|
10 |
class Human {
|
22 |
/** @var CommentsFilter\Options $opts */
|
23 |
$opts = $this->getOptions();
|
24 |
|
25 |
+
$mResult = true;
|
26 |
+
|
27 |
+
$items = array_intersect_key(
|
28 |
[
|
29 |
'comment_content' => $aCommData[ 'comment_content' ],
|
30 |
'url' => $aCommData[ 'comment_author_url' ],
|
36 |
array_flip( $opts->getHumanSpamFilterItems() )
|
37 |
);
|
38 |
|
39 |
+
$spam = ( new TestContent() )
|
40 |
+
->setCon( $this->getCon() )
|
41 |
+
->findSpam( $items, true );
|
42 |
+
|
43 |
+
if ( !empty( $spam ) ) {
|
44 |
+
$key = key( reset( $spam ) );
|
45 |
+
$word = key( $spam );
|
46 |
+
|
47 |
+
$mResult = new \WP_Error(
|
48 |
+
'human',
|
49 |
+
sprintf( __( 'Human SPAM filter found "%s" in "%s"', 'wp-simple-firewall' ), $word, $key ),
|
50 |
+
[
|
51 |
+
'word' => $word,
|
52 |
+
'key' => $key
|
53 |
+
]
|
54 |
+
);
|
55 |
}
|
56 |
|
57 |
return $mResult;
|
58 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
}
|
src/lib/src/Modules/CommentsFilter/Scan/Scanner.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter\Scan;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Logic\
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\CommentsFilter;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
8 |
use FernleafSystems\Wordpress\Plugin\Shield\Utilities;
|
@@ -11,19 +11,19 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
11 |
class Scanner {
|
12 |
|
13 |
use ModConsumer;
|
14 |
-
use
|
15 |
|
16 |
/**
|
17 |
* @var string|int|null
|
18 |
*/
|
19 |
-
private $
|
20 |
|
21 |
/**
|
22 |
* @var string
|
23 |
*/
|
24 |
-
private $
|
25 |
|
26 |
-
protected function canRun() {
|
27 |
return Services::Request()->isPost();
|
28 |
}
|
29 |
|
@@ -40,44 +40,48 @@ class Scanner {
|
|
40 |
* @return int|string|null
|
41 |
*/
|
42 |
public function setStatus( $mStatus ) {
|
43 |
-
if ( !is_null( $this->
|
44 |
-
$mStatus = $this->
|
45 |
}
|
46 |
return $mStatus;
|
47 |
}
|
48 |
|
49 |
/**
|
50 |
-
* @param string $
|
51 |
* @return string
|
52 |
*/
|
53 |
-
public function insertStatusExplanation( $
|
54 |
|
55 |
-
if ( !is_null( $this->
|
56 |
-
|
|
|
57 |
case 'spam':
|
58 |
-
$
|
59 |
break;
|
60 |
case 'trash':
|
61 |
-
$
|
62 |
break;
|
63 |
default:
|
64 |
case '0':
|
65 |
-
$
|
66 |
break;
|
67 |
}
|
68 |
|
69 |
-
$
|
70 |
-
'
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
)
|
77 |
-
|
|
|
|
|
|
|
78 |
}
|
79 |
|
80 |
-
return $
|
81 |
}
|
82 |
|
83 |
/**
|
@@ -100,18 +104,18 @@ class Scanner {
|
|
100 |
);
|
101 |
|
102 |
if ( $mResult->get_error_code() == 'human' ) {
|
103 |
-
$
|
104 |
}
|
105 |
else {
|
106 |
-
$
|
107 |
}
|
108 |
|
109 |
-
if ( $
|
110 |
Services::Response()->redirectToHome();
|
111 |
}
|
112 |
|
113 |
-
$this->
|
114 |
-
$this->
|
115 |
}
|
116 |
}
|
117 |
|
@@ -130,28 +134,41 @@ class Scanner {
|
|
130 |
|
131 |
$mResult = true;
|
132 |
|
133 |
-
if (
|
134 |
-
|
135 |
-
|
136 |
-
|
|
|
|
|
|
|
|
|
|
|
137 |
}
|
|
|
138 |
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
(
|
143 |
-
|
144 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
145 |
}
|
146 |
-
|
147 |
-
|
148 |
-
->setMod( $this->getMod() )
|
149 |
-
->test();
|
150 |
}
|
151 |
}
|
152 |
-
catch ( \Exception $e ) {
|
153 |
-
$mResult = new \WP_Error( 'recaptcha', $e->getMessage(), [] );
|
154 |
-
}
|
155 |
}
|
156 |
|
157 |
if ( !is_wp_error( $mResult ) && $opts->isEnabledHumanCheck() ) {
|
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;
|
11 |
class Scanner {
|
12 |
|
13 |
use ModConsumer;
|
14 |
+
use ExecOnce;
|
15 |
|
16 |
/**
|
17 |
* @var string|int|null
|
18 |
*/
|
19 |
+
private $spamStatus;
|
20 |
|
21 |
/**
|
22 |
* @var string
|
23 |
*/
|
24 |
+
private $spamReason;
|
25 |
|
26 |
+
protected function canRun() :bool {
|
27 |
return Services::Request()->isPost();
|
28 |
}
|
29 |
|
40 |
* @return int|string|null
|
41 |
*/
|
42 |
public function setStatus( $mStatus ) {
|
43 |
+
if ( !is_null( $this->spamStatus ) && in_array( $this->spamStatus, [ '0', 'spam', 'trash' ] ) ) {
|
44 |
+
$mStatus = $this->spamStatus;
|
45 |
}
|
46 |
return $mStatus;
|
47 |
}
|
48 |
|
49 |
/**
|
50 |
+
* @param string $content
|
51 |
* @return string
|
52 |
*/
|
53 |
+
public function insertStatusExplanation( $content ) {
|
54 |
|
55 |
+
if ( !is_null( $this->spamStatus ) && in_array( $this->spamStatus, [ '0', 'spam', 'trash' ] ) ) {
|
56 |
+
|
57 |
+
switch ( $this->spamStatus ) {
|
58 |
case 'spam':
|
59 |
+
$humanStatus = 'SPAM';
|
60 |
break;
|
61 |
case 'trash':
|
62 |
+
$humanStatus = __( 'Trash' );
|
63 |
break;
|
64 |
default:
|
65 |
case '0':
|
66 |
+
$humanStatus = __( 'Pending Moderation' );
|
67 |
break;
|
68 |
}
|
69 |
|
70 |
+
$additional = (string)apply_filters(
|
71 |
+
'shield/comment_spam_explanation',
|
72 |
+
sprintf(
|
73 |
+
"## Comment SPAM Protection: %s %s ##\n",
|
74 |
+
sprintf( __( '%s marked this comment as "%s".', 'wp-simple-firewall' ),
|
75 |
+
$this->getCon()->getHumanName(), $humanStatus ),
|
76 |
+
sprintf( __( 'Reason: %s', 'wp-simple-firewall' ), $this->spamReason )
|
77 |
+
),
|
78 |
+
$this->spamStatus,
|
79 |
+
$this->spamReason
|
80 |
+
);
|
81 |
+
$content = $additional.$content;
|
82 |
}
|
83 |
|
84 |
+
return $content;
|
85 |
}
|
86 |
|
87 |
/**
|
104 |
);
|
105 |
|
106 |
if ( $mResult->get_error_code() == 'human' ) {
|
107 |
+
$status = $opts->getOpt( 'comments_default_action_human_spam' );
|
108 |
}
|
109 |
else {
|
110 |
+
$status = $opts->getOpt( 'comments_default_action_spam_bot' );
|
111 |
}
|
112 |
|
113 |
+
if ( $status == 'reject' ) {
|
114 |
Services::Response()->redirectToHome();
|
115 |
}
|
116 |
|
117 |
+
$this->spamStatus = $status;
|
118 |
+
$this->spamReason = $mResult->get_error_message();
|
119 |
}
|
120 |
}
|
121 |
|
134 |
|
135 |
$mResult = true;
|
136 |
|
137 |
+
if ( $opts->isEnabledAntiBot() ) {
|
138 |
+
try {
|
139 |
+
( new AntiBot() )
|
140 |
+
->setMod( $this->getMod() )
|
141 |
+
->scan();
|
142 |
+
}
|
143 |
+
catch ( \Exception $e ) {
|
144 |
+
$mResult = new \WP_Error( 'antibot', $e->getMessage() );
|
145 |
+
}
|
146 |
}
|
147 |
+
else {
|
148 |
|
149 |
+
if ( $opts->isEnabledGaspCheck() ) {
|
150 |
+
$mResult = ( new Bot() )
|
151 |
+
->setMod( $this->getMod() )
|
152 |
+
->scan( $aCommData[ 'comment_post_ID' ] );
|
153 |
+
}
|
154 |
+
|
155 |
+
if ( !is_wp_error( $mResult ) && $opts->isEnabledCaptcha() && $mod->getCaptchaCfg()->ready ) {
|
156 |
+
try {
|
157 |
+
if ( $mod->getCaptchaCfg()->provider === 'hcaptcha' ) {
|
158 |
+
( new Utilities\HCaptcha\TestRequest() )
|
159 |
+
->setMod( $this->getMod() )
|
160 |
+
->test();
|
161 |
+
}
|
162 |
+
else {
|
163 |
+
( new Utilities\ReCaptcha\TestRequest() )
|
164 |
+
->setMod( $this->getMod() )
|
165 |
+
->test();
|
166 |
+
}
|
167 |
}
|
168 |
+
catch ( \Exception $e ) {
|
169 |
+
$mResult = new \WP_Error( 'recaptcha', $e->getMessage(), [] );
|
|
|
|
|
170 |
}
|
171 |
}
|
|
|
|
|
|
|
172 |
}
|
173 |
|
174 |
if ( !is_wp_error( $mResult ) && $opts->isEnabledHumanCheck() ) {
|
src/lib/src/Modules/CommentsFilter/Strings.php
CHANGED
@@ -12,6 +12,7 @@ class Strings extends Base\Strings {
|
|
12 |
*/
|
13 |
protected function getAuditMessages() :array {
|
14 |
return [
|
|
|
15 |
'spam_block_human' => [
|
16 |
__( 'Blocked human SPAM comment containing suspicious content.', 'wp-simple-firewall' ),
|
17 |
__( 'Human SPAM filter found "%s" in "%s"', 'wp-simple-firewall' )
|
@@ -94,68 +95,91 @@ class Strings extends Base\Strings {
|
|
94 |
switch ( $key ) {
|
95 |
|
96 |
case 'enable_comments_filter' :
|
97 |
-
$
|
98 |
-
$
|
99 |
-
$
|
100 |
break;
|
101 |
|
102 |
case 'trusted_commenter_minimum' :
|
103 |
-
$
|
104 |
-
$
|
105 |
-
$
|
106 |
-
|
107 |
break;
|
108 |
|
109 |
case 'trusted_user_roles' :
|
110 |
-
$
|
111 |
-
$
|
112 |
-
$
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
117 |
break;
|
118 |
|
119 |
case 'enable_comments_human_spam_filter' :
|
120 |
-
$
|
121 |
-
$
|
122 |
-
$
|
|
|
|
|
|
|
123 |
break;
|
124 |
|
125 |
case 'comments_default_action_human_spam' :
|
126 |
-
$
|
127 |
-
$
|
128 |
-
$
|
129 |
break;
|
130 |
|
131 |
case 'enable_comments_gasp_protection' :
|
132 |
-
$
|
133 |
-
$
|
134 |
-
$
|
135 |
-
|
|
|
|
|
|
|
|
|
|
|
136 |
break;
|
137 |
|
138 |
case 'comments_default_action_spam_bot' :
|
139 |
-
$
|
140 |
-
$
|
141 |
-
$
|
|
|
142 |
break;
|
143 |
|
144 |
case 'custom_message_checkbox' :
|
145 |
-
$
|
146 |
-
$
|
147 |
-
$
|
148 |
-
|
149 |
break;
|
150 |
|
151 |
case 'google_recaptcha_style_comments' :
|
152 |
-
$
|
153 |
-
$
|
154 |
-
$
|
|
|
|
|
155 |
__( 'You can choose the CAPTCHA display format that best suits your site, including the newer Invisible CAPTCHA, when you upgrade to PRO.', 'wp-simple-firewall' )
|
156 |
];
|
157 |
if ( !$mod->getCaptchaCfg()->ready ) {
|
158 |
-
$
|
159 |
$this->getCon()
|
160 |
->getModule_Plugin()
|
161 |
->getUrl_DirectLinkToSection( 'section_third_party_captcha' ),
|
@@ -165,24 +189,24 @@ class Strings extends Base\Strings {
|
|
165 |
break;
|
166 |
|
167 |
case 'custom_message_alert' :
|
168 |
-
$
|
169 |
-
$
|
170 |
-
$
|
171 |
-
|
172 |
break;
|
173 |
|
174 |
case 'custom_message_comment_wait' :
|
175 |
-
$
|
176 |
-
$
|
177 |
-
$
|
178 |
-
|
179 |
break;
|
180 |
|
181 |
case 'custom_message_comment_reload' :
|
182 |
-
$
|
183 |
-
$
|
184 |
-
$
|
185 |
-
|
186 |
break;
|
187 |
|
188 |
default:
|
@@ -190,9 +214,9 @@ class Strings extends Base\Strings {
|
|
190 |
}
|
191 |
|
192 |
return [
|
193 |
-
'name' => $
|
194 |
-
'summary' => $
|
195 |
-
'description' => $
|
196 |
];
|
197 |
}
|
198 |
}
|
12 |
*/
|
13 |
protected function getAuditMessages() :array {
|
14 |
return [
|
15 |
+
'spam_block_antibot' => [ __( 'Blocked SPAM comment that failed AntiBot tests.', 'wp-simple-firewall' ) ],
|
16 |
'spam_block_human' => [
|
17 |
__( 'Blocked human SPAM comment containing suspicious content.', 'wp-simple-firewall' ),
|
18 |
__( 'Human SPAM filter found "%s" in "%s"', 'wp-simple-firewall' )
|
95 |
switch ( $key ) {
|
96 |
|
97 |
case 'enable_comments_filter' :
|
98 |
+
$name = sprintf( __( 'Enable %s Module', 'wp-simple-firewall' ), $modName );
|
99 |
+
$summary = __( 'Enable (or Disable) The Comment SPAM Protection Feature', 'wp-simple-firewall' );
|
100 |
+
$desc = sprintf( __( 'Un-Checking this option will completely disable the %s module.', 'wp-simple-firewall' ), __( 'Comment SPAM Protection', 'wp-simple-firewall' ) );
|
101 |
break;
|
102 |
|
103 |
case 'trusted_commenter_minimum' :
|
104 |
+
$name = __( 'Trusted Commenter Minimum', 'wp-simple-firewall' );
|
105 |
+
$summary = __( 'Minimum Number Of Approved Comments Before Commenter Is Trusted', 'wp-simple-firewall' );
|
106 |
+
$desc = __( 'Specify how many approved comments must exist before a commenter is trusted and their comments are no longer scanned.', 'wp-simple-firewall' )
|
107 |
+
.'<br />'.__( 'Normally WordPress will trust after 1 comment.', 'wp-simple-firewall' );
|
108 |
break;
|
109 |
|
110 |
case 'trusted_user_roles' :
|
111 |
+
$name = __( 'Trusted User Roles', 'wp-simple-firewall' );
|
112 |
+
$summary = __( "Comments From Users With These Roles Will Never Be Scanned", 'wp-simple-firewall' );
|
113 |
+
$desc = __( "Shield doesn't normally scan comments from logged-in or registered users.", 'wp-simple-firewall' )
|
114 |
+
.'<br />'.__( "Specify user roles here that shouldn't be scanned.", 'wp-simple-firewall' )
|
115 |
+
.'<br/>'.sprintf( '%s: %s', __( 'Important', 'wp-simple-firewall' ), __( 'Take a new line for each user role.', 'wp-simple-firewall' ) )
|
116 |
+
.'<br/>'.sprintf( '%s: %s', __( 'Available Roles', 'wp-simple-firewall' ), implode( ', ', Services::WpUsers()
|
117 |
+
->getAvailableUserRoles() ) );
|
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() ),
|
126 |
+
__( 'This feature is designed to replace the CAPTCHA and Bot Protection options.', 'wp-simple-firewall' ),
|
127 |
+
sprintf( '%s - %s', __( 'Important', 'wp-simple-firewall' ),
|
128 |
+
__( "Switching on this feature will disable the CAPTCHA and Bot Protection settings.", 'wp-simple-firewall' ) )
|
129 |
+
];
|
130 |
break;
|
131 |
|
132 |
case 'enable_comments_human_spam_filter' :
|
133 |
+
$name = __( 'Human SPAM Filter', 'wp-simple-firewall' );
|
134 |
+
$summary = sprintf( __( 'Enable (or Disable) The %s Feature', 'wp-simple-firewall' ), __( 'Human SPAM Filter', 'wp-simple-firewall' ) );
|
135 |
+
$desc = [
|
136 |
+
__( 'Most SPAM is automatic, by bots, but sometimes Humans also post comments to your site and these bypass Bot Detection rules.', 'wp-simple-firewall' ),
|
137 |
+
__( 'When this happens, you can scan the content for keywords that are typical of SPAM.', 'wp-simple-firewall' ),
|
138 |
+
];
|
139 |
break;
|
140 |
|
141 |
case 'comments_default_action_human_spam' :
|
142 |
+
$name = __( 'SPAM Action', 'wp-simple-firewall' );
|
143 |
+
$summary = __( 'How To Categorise Comments When Identified To Be SPAM', 'wp-simple-firewall' );
|
144 |
+
$desc = sprintf( __( 'When a comment is detected as being SPAM from %s, the comment will be categorised based on this setting.', 'wp-simple-firewall' ), '<span style"text-decoration:underline;">'.__( 'a human commenter', 'wp-simple-firewall' ).'</span>' );
|
145 |
break;
|
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' ) ),
|
153 |
+
|
154 |
+
__( 'Highly effective detection for the most common types of comment SPAM.', 'wp-simple-firewall' ),
|
155 |
+
sprintf( '%s: %s', __( 'Bonus', 'wp-simple-firewall' ), __( "Unlike Akismet, your data is never sent off-site to 3rd party processing servers.", 'wp-simple-firewall' ) )
|
156 |
+
];
|
157 |
break;
|
158 |
|
159 |
case 'comments_default_action_spam_bot' :
|
160 |
+
$name = __( 'SPAM Action', 'wp-simple-firewall' );
|
161 |
+
$summary = __( 'Where To Put SPAM Comments', 'wp-simple-firewall' );
|
162 |
+
$desc = sprintf( __( 'When a comment is detected as being SPAM, %s will put the comment in the specified folder.', 'wp-simple-firewall' ),
|
163 |
+
$this->getCon()->getHumanName() );
|
164 |
break;
|
165 |
|
166 |
case 'custom_message_checkbox' :
|
167 |
+
$name = __( 'GASP Checkbox Message', 'wp-simple-firewall' );
|
168 |
+
$summary = __( 'If you want a custom checkbox message, please provide this here', 'wp-simple-firewall' );
|
169 |
+
$desc = __( "You can customise the message beside the checkbox.", 'wp-simple-firewall' )
|
170 |
+
.'<br />'.sprintf( __( 'Default Message: %s', 'wp-simple-firewall' ), __( "Please check the box to confirm you're not a spammer", 'wp-simple-firewall' ) );
|
171 |
break;
|
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' ) ),
|
179 |
__( 'You can choose the CAPTCHA display format that best suits your site, including the newer Invisible CAPTCHA, when you upgrade to PRO.', 'wp-simple-firewall' )
|
180 |
];
|
181 |
if ( !$mod->getCaptchaCfg()->ready ) {
|
182 |
+
$desc[] = sprintf( '<a href="%s">%s</a>',
|
183 |
$this->getCon()
|
184 |
->getModule_Plugin()
|
185 |
->getUrl_DirectLinkToSection( 'section_third_party_captcha' ),
|
189 |
break;
|
190 |
|
191 |
case 'custom_message_alert' :
|
192 |
+
$name = __( 'GASP Alert Message', 'wp-simple-firewall' );
|
193 |
+
$summary = __( 'If you want a custom alert message, please provide this here', 'wp-simple-firewall' );
|
194 |
+
$desc = __( "This alert message is displayed when a visitor attempts to submit a comment without checking the box.", 'wp-simple-firewall' )
|
195 |
+
.'<br />'.sprintf( __( 'Default Message: %s', 'wp-simple-firewall' ), __( "Please check the box to confirm you're not a spammer", 'wp-simple-firewall' ) );
|
196 |
break;
|
197 |
|
198 |
case 'custom_message_comment_wait' :
|
199 |
+
$name = __( 'GASP Wait Message', 'wp-simple-firewall' );
|
200 |
+
$summary = __( 'If you want a custom submit-button wait message, please provide this here.', 'wp-simple-firewall' );
|
201 |
+
$desc = __( "Where you see the '%s' this will be the number of seconds. You must ensure you include 1, and only 1, of these.", 'wp-simple-firewall' )
|
202 |
+
.'<br />'.sprintf( __( 'Default Message: %s', 'wp-simple-firewall' ), __( 'Please wait %s seconds before posting your comment', 'wp-simple-firewall' ) );
|
203 |
break;
|
204 |
|
205 |
case 'custom_message_comment_reload' :
|
206 |
+
$name = __( 'GASP Reload Message', 'wp-simple-firewall' );
|
207 |
+
$summary = __( 'If you want a custom message when the comment token has expired, please provide this here.', 'wp-simple-firewall' );
|
208 |
+
$desc = __( 'This message is displayed on the submit-button when the comment token is expired', 'wp-simple-firewall' )
|
209 |
+
.'<br />'.sprintf( __( 'Default Message: %s', 'wp-simple-firewall' ), __( "Please reload this page to post a comment", 'wp-simple-firewall' ) );
|
210 |
break;
|
211 |
|
212 |
default:
|
214 |
}
|
215 |
|
216 |
return [
|
217 |
+
'name' => $name,
|
218 |
+
'summary' => $summary,
|
219 |
+
'description' => $desc,
|
220 |
];
|
221 |
}
|
222 |
}
|
src/lib/src/Modules/CommentsFilter/Upgrade.php
CHANGED
@@ -7,15 +7,15 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
|
|
7 |
class Upgrade extends Base\Upgrade {
|
8 |
|
9 |
protected function upgrade_905() {
|
10 |
-
/** @var Options $
|
11 |
-
$
|
12 |
-
$
|
13 |
'comments_default_action_human_spam',
|
14 |
-
(string)$
|
15 |
);
|
16 |
-
$
|
17 |
'comments_default_action_spam_bot',
|
18 |
-
(string)$
|
19 |
);
|
20 |
}
|
21 |
|
7 |
class Upgrade extends Base\Upgrade {
|
8 |
|
9 |
protected function upgrade_905() {
|
10 |
+
/** @var Options $opts */
|
11 |
+
$opts = $this->getOptions();
|
12 |
+
$opts->setOpt(
|
13 |
'comments_default_action_human_spam',
|
14 |
+
(string)$opts->getOpt( 'comments_default_action_human_spam' )
|
15 |
);
|
16 |
+
$opts->setOpt(
|
17 |
'comments_default_action_spam_bot',
|
18 |
+
(string)$opts->getOpt( 'comments_default_action_spam_bot' )
|
19 |
);
|
20 |
}
|
21 |
|
src/lib/src/Modules/Events/AjaxHandler.php
DELETED
@@ -1,66 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Events;
|
4 |
-
|
5 |
-
use FernleafSystems\Wordpress\Plugin\Shield;
|
6 |
-
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Events;
|
7 |
-
use FernleafSystems\Wordpress\Services\Services;
|
8 |
-
|
9 |
-
class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
|
10 |
-
|
11 |
-
protected function processAjaxAction( string $action ) :array {
|
12 |
-
|
13 |
-
switch ( $action ) {
|
14 |
-
case 'render_chart':
|
15 |
-
$aResponse = $this->ajaxExec_RenderChart();
|
16 |
-
break;
|
17 |
-
|
18 |
-
case 'render_chart_post':
|
19 |
-
$aResponse = $this->ajaxExec_RenderChartPost();
|
20 |
-
break;
|
21 |
-
|
22 |
-
default:
|
23 |
-
$aResponse = parent::processAjaxAction( $action );
|
24 |
-
}
|
25 |
-
|
26 |
-
return $aResponse;
|
27 |
-
}
|
28 |
-
|
29 |
-
private function ajaxExec_RenderChart() :array {
|
30 |
-
/** @var ModCon $mod */
|
31 |
-
$mod = $this->getMod();
|
32 |
-
|
33 |
-
$aParams = $this->getAjaxFormParams();
|
34 |
-
$oReq = new Events\Charts\ChartRequestVO();
|
35 |
-
$oReq->render_location = $aParams[ 'render_location' ];
|
36 |
-
$oReq->chart_params = $aParams[ 'chart_params' ];
|
37 |
-
$aChart = ( new Events\Charts\BuildData() )
|
38 |
-
->setMod( $mod )
|
39 |
-
->build( $oReq );
|
40 |
-
|
41 |
-
return [
|
42 |
-
'success' => true,
|
43 |
-
'message' => 'no message',
|
44 |
-
'chart' => $aChart
|
45 |
-
];
|
46 |
-
}
|
47 |
-
|
48 |
-
private function ajaxExec_RenderChartPost() :array {
|
49 |
-
/** @var ModCon $mod */
|
50 |
-
$mod = $this->getMod();
|
51 |
-
$req = Services::Request();
|
52 |
-
$oChartReq = new Events\Charts\ChartRequestVO();
|
53 |
-
$oChartReq->render_location = $req->post( 'render_location' );
|
54 |
-
$oChartReq->chart_params = $req->post( 'chart_params' );
|
55 |
-
|
56 |
-
$aChart = ( new Events\Charts\BuildData() )
|
57 |
-
->setMod( $mod )
|
58 |
-
->build( $oChartReq );
|
59 |
-
|
60 |
-
return [
|
61 |
-
'success' => true,
|
62 |
-
'message' => 'no message',
|
63 |
-
'chart' => $aChart
|
64 |
-
];
|
65 |
-
}
|
66 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/lib/src/Modules/Events/Charts/BuildData.php
DELETED
@@ -1,131 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Events\Charts;
|
4 |
-
|
5 |
-
use FernleafSystems\Wordpress\Plugin\Shield\Databases\Events;
|
6 |
-
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Events\ModCon;
|
7 |
-
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
8 |
-
use FernleafSystems\Wordpress\Services\Services;
|
9 |
-
|
10 |
-
class BuildData {
|
11 |
-
|
12 |
-
use ModConsumer;
|
13 |
-
|
14 |
-
/**
|
15 |
-
* @param ChartRequestVO $req
|
16 |
-
* @return array
|
17 |
-
*/
|
18 |
-
public function build( ChartRequestVO $req ) {
|
19 |
-
/** @var ModCon $mod */
|
20 |
-
$mod = $this->getMod();
|
21 |
-
|
22 |
-
$this->preProcessRequest( $req );
|
23 |
-
|
24 |
-
/** @var Events\Handler $oDbhEvts */
|
25 |
-
$oDbhEvts = $mod->getDbHandler_Events();
|
26 |
-
|
27 |
-
$nTick = 0;
|
28 |
-
$oTime = Services::Request()->carbon();
|
29 |
-
|
30 |
-
$aLabels = [];
|
31 |
-
$aSeries = [];
|
32 |
-
do {
|
33 |
-
$aLabels[] = $oTime->toDateString();
|
34 |
-
|
35 |
-
/** @var Events\Select $oSelEvts */
|
36 |
-
$oSelEvts = $oDbhEvts->getQuerySelector();
|
37 |
-
switch ( $req->interval ) {
|
38 |
-
case 'hourly':
|
39 |
-
$oSelEvts->filterByBoundary_Hour( $oTime->timestamp );
|
40 |
-
$oTime->subHour();
|
41 |
-
break;
|
42 |
-
case 'daily':
|
43 |
-
$oSelEvts->filterByBoundary_Day( $oTime->timestamp );
|
44 |
-
$oTime->subDay();
|
45 |
-
break;
|
46 |
-
case 'weekly':
|
47 |
-
$oSelEvts->filterByBoundary_Week( $oTime->timestamp );
|
48 |
-
$oTime->subWeek();
|
49 |
-
break;
|
50 |
-
case 'monthly':
|
51 |
-
$oSelEvts->filterByBoundary_Month( $oTime->timestamp );
|
52 |
-
$oTime->subMonth();
|
53 |
-
break;
|
54 |
-
case 'yearly':
|
55 |
-
$oSelEvts->filterByBoundary_Year( $oTime->timestamp );
|
56 |
-
$oTime->subYear();
|
57 |
-
break;
|
58 |
-
}
|
59 |
-
|
60 |
-
$aSeries[] = $oSelEvts->sumEvents( $req->events );
|
61 |
-
|
62 |
-
$nTick++;
|
63 |
-
} while ( $nTick < $req->ticks );
|
64 |
-
|
65 |
-
return [
|
66 |
-
'data' => [
|
67 |
-
'labels' => [],
|
68 |
-
'series' => [
|
69 |
-
array_reverse( $aSeries ),
|
70 |
-
]
|
71 |
-
],
|
72 |
-
'legend_names' => [],
|
73 |
-
];
|
74 |
-
}
|
75 |
-
|
76 |
-
/**
|
77 |
-
* @param ChartRequestVO $oReq
|
78 |
-
*/
|
79 |
-
protected function preProcessRequest( ChartRequestVO $oReq ) {
|
80 |
-
|
81 |
-
if ( empty( $oReq->interval ) ) {
|
82 |
-
switch ( $oReq->render_location ) {
|
83 |
-
case $oReq::LOCATION_STATCARD:
|
84 |
-
$oReq->interval = 'daily';
|
85 |
-
break;
|
86 |
-
default:
|
87 |
-
$oReq->interval = 'weekly';
|
88 |
-
break;
|
89 |
-
}
|
90 |
-
}
|
91 |
-
|
92 |
-
$aAll = array_keys( $this->getCon()->loadEventsService()->getEvents() );
|
93 |
-
if ( !empty( $oReq->chart_params[ 'stat_id' ] ) ) {
|
94 |
-
switch ( $oReq->chart_params[ 'stat_id' ] ) {
|
95 |
-
case 'comment_block':
|
96 |
-
$oReq->events = array_filter(
|
97 |
-
$aAll,
|
98 |
-
function ( $sEvent ) {
|
99 |
-
return strpos( $sEvent, 'spam_block_' ) === 0;
|
100 |
-
}
|
101 |
-
);
|
102 |
-
break;
|
103 |
-
case 'bot_blocks':
|
104 |
-
$oReq->events = array_filter(
|
105 |
-
$aAll,
|
106 |
-
function ( $sEvent ) {
|
107 |
-
return strpos( $sEvent, 'bottrack_' ) === 0;
|
108 |
-
}
|
109 |
-
);
|
110 |
-
break;
|
111 |
-
default:
|
112 |
-
$oReq->events = (array)$oReq->chart_params[ 'stat_id' ];
|
113 |
-
break;
|
114 |
-
}
|
115 |
-
}
|
116 |
-
|
117 |
-
if ( empty( $oReq->ticks ) ) {
|
118 |
-
switch ( $oReq->interval ) {
|
119 |
-
case 'daily':
|
120 |
-
$oReq->ticks = 7;
|
121 |
-
break;
|
122 |
-
case 'weekly':
|
123 |
-
$oReq->ticks = 8;
|
124 |
-
break;
|
125 |
-
default:
|
126 |
-
$oReq->ticks = 12;
|
127 |
-
break;
|
128 |
-
}
|
129 |
-
}
|
130 |
-
}
|
131 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/lib/src/Modules/Events/Charts/ChartRequestVO.php
DELETED
@@ -1,20 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Events\Charts;
|
4 |
-
|
5 |
-
use FernleafSystems\Utilities\Data\Adapter\StdClassAdapter;
|
6 |
-
|
7 |
-
/**
|
8 |
-
* Class ChartRequestVO
|
9 |
-
* @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Events\Charts
|
10 |
-
* @property string $render_location
|
11 |
-
* @property string $interval
|
12 |
-
* @property string $ticks
|
13 |
-
* @property string[] $events
|
14 |
-
* @property array $chart_params
|
15 |
-
*/
|
16 |
-
class ChartRequestVO {
|
17 |
-
|
18 |
-
const LOCATION_STATCARD = 'insights-overview-statcard';
|
19 |
-
use StdClassAdapter;
|
20 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/lib/src/Modules/Events/Lib/Reports/KeyStats.php
CHANGED
@@ -32,6 +32,7 @@ class KeyStats extends BaseReporter {
|
|
32 |
'bottrack_loginfailed',
|
33 |
'bottrack_logininvalid',
|
34 |
'bottrack_xmlrpc',
|
|
|
35 |
'spam_block_bot',
|
36 |
'spam_block_recaptcha',
|
37 |
'spam_block_human',
|
32 |
'bottrack_loginfailed',
|
33 |
'bottrack_logininvalid',
|
34 |
'bottrack_xmlrpc',
|
35 |
+
'bottrack_invalidscript',
|
36 |
'spam_block_bot',
|
37 |
'spam_block_recaptcha',
|
38 |
'spam_block_human',
|
src/lib/src/Modules/Events/Lib/StatsWriter.php
CHANGED
@@ -27,9 +27,9 @@ class StatsWriter extends EventsListener {
|
|
27 |
|
28 |
protected function onShutdown() {
|
29 |
if ( !$this->getCon()->plugin_deleting ) {
|
30 |
-
/** @var Handler $
|
31 |
-
$
|
32 |
-
$
|
33 |
$this->setEventStats();
|
34 |
}
|
35 |
}
|
27 |
|
28 |
protected function onShutdown() {
|
29 |
if ( !$this->getCon()->plugin_deleting ) {
|
30 |
+
/** @var Handler $dbh */
|
31 |
+
$dbh = $this->getDbHandler();
|
32 |
+
$dbh->commitEvents( $this->getEventStats() );
|
33 |
$this->setEventStats();
|
34 |
}
|
35 |
}
|
src/lib/src/Modules/Events/Processor.php
CHANGED
@@ -2,8 +2,8 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Events;
|
4 |
|
5 |
-
use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Databases;
|
|
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Events;
|
8 |
|
9 |
class Processor extends BaseShield\Processor {
|
@@ -32,16 +32,16 @@ class Processor extends BaseShield\Processor {
|
|
32 |
}
|
33 |
|
34 |
public function statsWidget() {
|
35 |
-
/** @var Databases\Events\Select $
|
36 |
-
$
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
|
41 |
$aKeyStats = [
|
42 |
'comments' => [
|
43 |
__( 'Comment Blocks', 'wp-simple-firewall' ),
|
44 |
-
$
|
45 |
'spam_block_bot',
|
46 |
'spam_block_human',
|
47 |
'spam_block_recaptcha'
|
@@ -49,38 +49,36 @@ class Processor extends BaseShield\Processor {
|
|
49 |
],
|
50 |
'firewall' => [
|
51 |
__( 'Firewall Blocks', 'wp-simple-firewall' ),
|
52 |
-
$
|
53 |
],
|
54 |
'login_fail' => [
|
55 |
__( 'Login Blocks', 'wp-simple-firewall' ),
|
56 |
-
$
|
57 |
],
|
58 |
'login_verified' => [
|
59 |
__( 'Login Verified', 'wp-simple-firewall' ),
|
60 |
-
$
|
61 |
],
|
62 |
'session_start' => [
|
63 |
__( 'User Sessions', 'wp-simple-firewall' ),
|
64 |
-
$
|
65 |
],
|
66 |
'ip_killed' => [
|
67 |
__( 'IP Blocks', 'wp-simple-firewall' ),
|
68 |
-
$
|
69 |
],
|
70 |
'ip_transgressions' => [
|
71 |
__( 'Total Offenses', 'wp-simple-firewall' ),
|
72 |
-
$
|
73 |
],
|
74 |
];
|
75 |
|
76 |
-
$aDisplayData = [
|
77 |
-
'sHeading' => sprintf( __( '%s Statistics', 'wp-simple-firewall' ), $this->getCon()->getHumanName() ),
|
78 |
-
'aKeyStats' => $aKeyStats,
|
79 |
-
];
|
80 |
-
|
81 |
echo $this->getMod()->renderTemplate(
|
82 |
'snippets/widget_dashboard_statistics.php',
|
83 |
-
|
|
|
|
|
|
|
84 |
);
|
85 |
}
|
86 |
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Events;
|
4 |
|
|
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Databases;
|
6 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Events;
|
8 |
|
9 |
class Processor extends BaseShield\Processor {
|
32 |
}
|
33 |
|
34 |
public function statsWidget() {
|
35 |
+
/** @var Databases\Events\Select $selector */
|
36 |
+
$selector = $this->getCon()
|
37 |
+
->getModule_Events()
|
38 |
+
->getDbHandler_Events()
|
39 |
+
->getQuerySelector();
|
40 |
|
41 |
$aKeyStats = [
|
42 |
'comments' => [
|
43 |
__( 'Comment Blocks', 'wp-simple-firewall' ),
|
44 |
+
$selector->clearWheres()->sumEvents( [
|
45 |
'spam_block_bot',
|
46 |
'spam_block_human',
|
47 |
'spam_block_recaptcha'
|
49 |
],
|
50 |
'firewall' => [
|
51 |
__( 'Firewall Blocks', 'wp-simple-firewall' ),
|
52 |
+
$selector->clearWheres()->sumEvent( 'firewall_block' )
|
53 |
],
|
54 |
'login_fail' => [
|
55 |
__( 'Login Blocks', 'wp-simple-firewall' ),
|
56 |
+
$selector->clearWheres()->sumEvent( 'login_block' )
|
57 |
],
|
58 |
'login_verified' => [
|
59 |
__( 'Login Verified', 'wp-simple-firewall' ),
|
60 |
+
$selector->clearWheres()->sumEvent( '2fa_success' )
|
61 |
],
|
62 |
'session_start' => [
|
63 |
__( 'User Sessions', 'wp-simple-firewall' ),
|
64 |
+
$selector->clearWheres()->sumEvent( 'session_start' )
|
65 |
],
|
66 |
'ip_killed' => [
|
67 |
__( 'IP Blocks', 'wp-simple-firewall' ),
|
68 |
+
$selector->clearWheres()->sumEvent( 'conn_kill' )
|
69 |
],
|
70 |
'ip_transgressions' => [
|
71 |
__( 'Total Offenses', 'wp-simple-firewall' ),
|
72 |
+
$selector->clearWheres()->sumEvent( 'ip_offense' )
|
73 |
],
|
74 |
];
|
75 |
|
|
|
|
|
|
|
|
|
|
|
76 |
echo $this->getMod()->renderTemplate(
|
77 |
'snippets/widget_dashboard_statistics.php',
|
78 |
+
[
|
79 |
+
'sHeading' => sprintf( __( '%s Statistics', 'wp-simple-firewall' ), $this->getCon()->getHumanName() ),
|
80 |
+
'aKeyStats' => $aKeyStats,
|
81 |
+
]
|
82 |
);
|
83 |
}
|
84 |
|
src/lib/src/Modules/Events/Strings.php
CHANGED
@@ -7,12 +7,11 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
|
|
7 |
class Strings extends Base\Strings {
|
8 |
|
9 |
/**
|
10 |
-
* @param string $
|
11 |
* @return string
|
12 |
*/
|
13 |
-
public function getEventName( $
|
14 |
-
|
15 |
-
return empty( $aE[ $sKey ] ) ? '' : $aE[ $sKey ];
|
16 |
}
|
17 |
|
18 |
/**
|
@@ -44,28 +43,32 @@ class Strings extends Base\Strings {
|
|
44 |
),
|
45 |
'bottrack_fakewebcrawler' => sprintf( '%s: %s',
|
46 |
__( 'Bot Detection', 'wp-simple-firewall' ),
|
47 |
-
__( 'Fake Web Crawler' )
|
48 |
),
|
49 |
'bottrack_linkcheese' => sprintf( '%s: %s',
|
50 |
__( 'Bot Detection', 'wp-simple-firewall' ),
|
51 |
-
__( 'Link Cheese' )
|
52 |
),
|
53 |
'bottrack_loginfailed' => sprintf( '%s: %s',
|
54 |
__( 'Bot Detection', 'wp-simple-firewall' ),
|
55 |
-
__( 'Failed Login' )
|
56 |
),
|
57 |
'bottrack_logininvalid' => sprintf( '%s: %s',
|
58 |
__( 'Bot Detection', 'wp-simple-firewall' ),
|
59 |
-
__( 'Invalid Username Login' )
|
60 |
),
|
61 |
'bottrack_useragent' => sprintf( '%s: %s',
|
62 |
__( 'Bot Detection', 'wp-simple-firewall' ),
|
63 |
-
__( 'Invalid User-Agent' )
|
64 |
),
|
65 |
'bottrack_xmlrpc' => sprintf( '%s: %s',
|
66 |
__( 'Bot Detection', 'wp-simple-firewall' ),
|
67 |
'XML-RPC'
|
68 |
),
|
|
|
|
|
|
|
|
|
69 |
'apc_alert_sent' => sprintf( '%s: %s',
|
70 |
__( 'Alert Sent', 'wp-simple-firewall' ),
|
71 |
__( 'Abandoned Plugin Detected', 'wp-simple-firewall' )
|
@@ -163,7 +166,7 @@ class Strings extends Base\Strings {
|
|
163 |
'cooldown_fail' => __( '', 'wp-simple-firewall' ),
|
164 |
'honeypot_fail' => __( '', 'wp-simple-firewall' ),
|
165 |
'botbox_fail' => __( '', 'wp-simple-firewall' ),
|
166 |
-
'login_block' => __( '', 'wp-simple-firewall' ),
|
167 |
'hide_login_url' => __( '', 'wp-simple-firewall' ),
|
168 |
'2fa_success' => __( '', 'wp-simple-firewall' ),
|
169 |
'check_skip' => __( '', 'wp-simple-firewall' ),
|
@@ -219,7 +222,7 @@ class Strings extends Base\Strings {
|
|
219 |
),
|
220 |
'spam_block_recaptcha' => sprintf( '%s: %s',
|
221 |
__( 'SPAM Blocked', 'wp-simple-firewall' ),
|
222 |
-
__( '
|
223 |
),
|
224 |
'spam_block_human' => sprintf( '%s: %s',
|
225 |
__( 'SPAM Blocked', 'wp-simple-firewall' ),
|
7 |
class Strings extends Base\Strings {
|
8 |
|
9 |
/**
|
10 |
+
* @param string $eventKey
|
11 |
* @return string
|
12 |
*/
|
13 |
+
public function getEventName( $eventKey ) {
|
14 |
+
return $this->getEventNames()[ $eventKey ] ?? '';
|
|
|
15 |
}
|
16 |
|
17 |
/**
|
43 |
),
|
44 |
'bottrack_fakewebcrawler' => sprintf( '%s: %s',
|
45 |
__( 'Bot Detection', 'wp-simple-firewall' ),
|
46 |
+
__( 'Fake Web Crawler', 'wp-simple-firewall' )
|
47 |
),
|
48 |
'bottrack_linkcheese' => sprintf( '%s: %s',
|
49 |
__( 'Bot Detection', 'wp-simple-firewall' ),
|
50 |
+
__( 'Link Cheese', 'wp-simple-firewall' )
|
51 |
),
|
52 |
'bottrack_loginfailed' => sprintf( '%s: %s',
|
53 |
__( 'Bot Detection', 'wp-simple-firewall' ),
|
54 |
+
__( 'Failed Login', 'wp-simple-firewall' )
|
55 |
),
|
56 |
'bottrack_logininvalid' => sprintf( '%s: %s',
|
57 |
__( 'Bot Detection', 'wp-simple-firewall' ),
|
58 |
+
__( 'Invalid Username Login', 'wp-simple-firewall' )
|
59 |
),
|
60 |
'bottrack_useragent' => sprintf( '%s: %s',
|
61 |
__( 'Bot Detection', 'wp-simple-firewall' ),
|
62 |
+
__( 'Invalid User-Agent', 'wp-simple-firewall' )
|
63 |
),
|
64 |
'bottrack_xmlrpc' => sprintf( '%s: %s',
|
65 |
__( 'Bot Detection', 'wp-simple-firewall' ),
|
66 |
'XML-RPC'
|
67 |
),
|
68 |
+
'bottrack_invalidscript' => sprintf( '%s: %s',
|
69 |
+
__( 'Bot Detection', 'wp-simple-firewall' ),
|
70 |
+
__( 'Invalid Script Load', 'wp-simple-firewall' )
|
71 |
+
),
|
72 |
'apc_alert_sent' => sprintf( '%s: %s',
|
73 |
__( 'Alert Sent', 'wp-simple-firewall' ),
|
74 |
__( 'Abandoned Plugin Detected', 'wp-simple-firewall' )
|
166 |
'cooldown_fail' => __( '', 'wp-simple-firewall' ),
|
167 |
'honeypot_fail' => __( '', 'wp-simple-firewall' ),
|
168 |
'botbox_fail' => __( '', 'wp-simple-firewall' ),
|
169 |
+
'login_block' => __( 'Blocked Login', 'wp-simple-firewall' ),
|
170 |
'hide_login_url' => __( '', 'wp-simple-firewall' ),
|
171 |
'2fa_success' => __( '', 'wp-simple-firewall' ),
|
172 |
'check_skip' => __( '', 'wp-simple-firewall' ),
|
222 |
),
|
223 |
'spam_block_recaptcha' => sprintf( '%s: %s',
|
224 |
__( 'SPAM Blocked', 'wp-simple-firewall' ),
|
225 |
+
__( 'CAPTCHA', 'wp-simple-firewall' )
|
226 |
),
|
227 |
'spam_block_human' => sprintf( '%s: %s',
|
228 |
__( 'SPAM Blocked', 'wp-simple-firewall' ),
|
src/lib/src/Modules/GeoIp/Lookup.php
CHANGED
@@ -12,7 +12,7 @@ class Lookup {
|
|
12 |
use Databases\Base\HandlerConsumer;
|
13 |
use IpAddressConsumer;
|
14 |
|
15 |
-
private $
|
16 |
|
17 |
/**
|
18 |
* @return Databases\GeoIp\EntryVO|null
|
@@ -20,8 +20,8 @@ class Lookup {
|
|
20 |
public function lookupIp() {
|
21 |
$ip = $this->getIP();
|
22 |
// Small optimization so we don't SQL it every time.
|
23 |
-
if ( isset( $this->
|
24 |
-
return $this->
|
25 |
}
|
26 |
|
27 |
/** @var Databases\GeoIp\Handler $dbh */
|
@@ -39,11 +39,10 @@ class Lookup {
|
|
39 |
$IP = new Databases\GeoIp\EntryVO();
|
40 |
$IP->ip = $ip;
|
41 |
$IP->meta = $this->redirectliIpLookup();
|
42 |
-
/** @var Databases\GeoIp\Insert $oIsrt */
|
43 |
$dbh->getQueryInserter()->insert( $IP );
|
44 |
}
|
45 |
|
46 |
-
$this->
|
47 |
return $IP;
|
48 |
}
|
49 |
|
12 |
use Databases\Base\HandlerConsumer;
|
13 |
use IpAddressConsumer;
|
14 |
|
15 |
+
private $ips = [];
|
16 |
|
17 |
/**
|
18 |
* @return Databases\GeoIp\EntryVO|null
|
20 |
public function lookupIp() {
|
21 |
$ip = $this->getIP();
|
22 |
// Small optimization so we don't SQL it every time.
|
23 |
+
if ( isset( $this->ips[ $ip ] ) ) {
|
24 |
+
return $this->ips[ $ip ];
|
25 |
}
|
26 |
|
27 |
/** @var Databases\GeoIp\Handler $dbh */
|
39 |
$IP = new Databases\GeoIp\EntryVO();
|
40 |
$IP->ip = $ip;
|
41 |
$IP->meta = $this->redirectliIpLookup();
|
|
|
42 |
$dbh->getQueryInserter()->insert( $IP );
|
43 |
}
|
44 |
|
45 |
+
$this->ips[ $ip ] = $IP;
|
46 |
return $IP;
|
47 |
}
|
48 |
|
src/lib/src/Modules/HackGuard/AjaxHandler.php
CHANGED
@@ -124,7 +124,7 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
|
|
124 |
$FS = Services::WpFs();
|
125 |
|
126 |
$nRID = Services::Request()->post( 'rid' );
|
127 |
-
$
|
128 |
'error' => '',
|
129 |
'success' => false,
|
130 |
'flags' => [
|
@@ -165,42 +165,42 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
|
|
165 |
];
|
166 |
try {
|
167 |
|
168 |
-
$
|
169 |
-
$bDiff = $
|
170 |
-
$
|
171 |
-
$
|
172 |
-
$
|
173 |
( new FileLocker\Ops\PerformAction() )
|
174 |
->setMod( $this->getMod() )
|
175 |
->run( $nRID, 'diff' ) : '';
|
176 |
|
177 |
$oCarb = Services::Request()->carbon( true );
|
178 |
-
$
|
179 |
-
$
|
180 |
-
Services::WpGeneral()->getTimeStampForDisplay( $FS->getModifiedTime( $
|
181 |
-
$
|
182 |
-
$
|
183 |
( new FileLocker\Ops\ReadOriginalFileContent() )
|
184 |
->setMod( $mod )
|
185 |
-
->run( $
|
186 |
), 3 );
|
187 |
-
$
|
188 |
-
Shield\Utilities\Tool\FormatBytes::Format( $FS->getFileSize( $
|
189 |
: 0;
|
190 |
-
$
|
191 |
-
$
|
192 |
}
|
193 |
catch ( \Exception $e ) {
|
194 |
-
$
|
195 |
}
|
196 |
|
197 |
return [
|
198 |
-
'success' => $
|
199 |
-
'message' => $
|
200 |
'html' => $this->getMod()
|
201 |
->renderTemplate(
|
202 |
'/wpadmin_pages/insights/scans/realtime/file_locker/file_diff.twig',
|
203 |
-
$
|
204 |
true
|
205 |
)
|
206 |
];
|
124 |
$FS = Services::WpFs();
|
125 |
|
126 |
$nRID = Services::Request()->post( 'rid' );
|
127 |
+
$data = [
|
128 |
'error' => '',
|
129 |
'success' => false,
|
130 |
'flags' => [
|
165 |
];
|
166 |
try {
|
167 |
|
168 |
+
$lock = $oFLCon->getFileLock( $nRID );
|
169 |
+
$bDiff = $lock->detected_at > 0;
|
170 |
+
$data[ 'ajax' ] = $oFLCon->createFileDownloadLinks( $lock );
|
171 |
+
$data[ 'flags' ][ 'has_diff' ] = $bDiff;
|
172 |
+
$data[ 'html' ][ 'diff' ] = $bDiff ?
|
173 |
( new FileLocker\Ops\PerformAction() )
|
174 |
->setMod( $this->getMod() )
|
175 |
->run( $nRID, 'diff' ) : '';
|
176 |
|
177 |
$oCarb = Services::Request()->carbon( true );
|
178 |
+
$data[ 'vars' ][ 'locked_at' ] = $oCarb->setTimestamp( $lock->created_at )->diffForHumans();
|
179 |
+
$data[ 'vars' ][ 'file_modified_at' ] =
|
180 |
+
Services::WpGeneral()->getTimeStampForDisplay( $FS->getModifiedTime( $lock->file ) );
|
181 |
+
$data[ 'vars' ][ 'change_detected_at' ] = $oCarb->setTimestamp( $lock->detected_at )->diffForHumans();
|
182 |
+
$data[ 'vars' ][ 'file_size_locked' ] = Shield\Utilities\Tool\FormatBytes::Format( strlen(
|
183 |
( new FileLocker\Ops\ReadOriginalFileContent() )
|
184 |
->setMod( $mod )
|
185 |
+
->run( $lock )
|
186 |
), 3 );
|
187 |
+
$data[ 'vars' ][ 'file_size_modified' ] = $FS->exists( $lock->file ) ?
|
188 |
+
Shield\Utilities\Tool\FormatBytes::Format( $FS->getFileSize( $lock->file ), 3 )
|
189 |
: 0;
|
190 |
+
$data[ 'vars' ][ 'file_name' ] = basename( $lock->file );
|
191 |
+
$data[ 'success' ] = true;
|
192 |
}
|
193 |
catch ( \Exception $e ) {
|
194 |
+
$data[ 'error' ] = $e->getMessage();
|
195 |
}
|
196 |
|
197 |
return [
|
198 |
+
'success' => $data[ 'success' ],
|
199 |
+
'message' => $data[ 'error' ],
|
200 |
'html' => $this->getMod()
|
201 |
->renderTemplate(
|
202 |
'/wpadmin_pages/insights/scans/realtime/file_locker/file_diff.twig',
|
203 |
+
$data,
|
204 |
true
|
205 |
)
|
206 |
];
|
src/lib/src/Modules/HackGuard/Debug.php
CHANGED
@@ -3,17 +3,10 @@
|
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard;
|
4 |
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules;
|
6 |
-
use FernleafSystems\Wordpress\Plugin\Shield\Scans\Mal\Signatures;
|
7 |
-
use FernleafSystems\Wordpress\Services\Utilities\Net\IpIdentify;
|
8 |
|
9 |
class Debug extends Modules\Base\Debug {
|
10 |
|
11 |
public function run() {
|
12 |
-
$this->dumpSigs();
|
13 |
die();
|
14 |
}
|
15 |
-
|
16 |
-
private function dumpSigs() {
|
17 |
-
var_dump(Signatures::getAll());
|
18 |
-
}
|
19 |
}
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard;
|
4 |
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules;
|
|
|
|
|
6 |
|
7 |
class Debug extends Modules\Base\Debug {
|
8 |
|
9 |
public function run() {
|
|
|
10 |
die();
|
11 |
}
|
|
|
|
|
|
|
|
|
12 |
}
|
src/lib/src/Modules/HackGuard/Lib/FileLocker/File.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\FileLocker;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Data\Adapter\
|
6 |
use FernleafSystems\Wordpress\Services\Services;
|
7 |
|
8 |
/**
|
@@ -15,21 +15,21 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
15 |
*/
|
16 |
class File {
|
17 |
|
18 |
-
use
|
19 |
|
20 |
-
public function __construct( $
|
21 |
-
$this->file = $
|
22 |
-
$this->dir = wp_normalize_path( $
|
23 |
}
|
24 |
|
25 |
/**
|
26 |
* @return string[]
|
27 |
*/
|
28 |
-
public function getExistingPossiblePaths() {
|
29 |
return array_filter(
|
30 |
$this->getPossiblePaths(),
|
31 |
-
function ( $
|
32 |
-
return Services::WpFs()->isFile( $
|
33 |
}
|
34 |
);
|
35 |
}
|
@@ -37,7 +37,7 @@ class File {
|
|
37 |
/**
|
38 |
* @return string[]
|
39 |
*/
|
40 |
-
public function getPossiblePaths() {
|
41 |
$paths = [];
|
42 |
$dirCount = 0;
|
43 |
$workingDir = realpath( $this->dir );
|
@@ -57,10 +57,7 @@ class File {
|
|
57 |
return $paths;
|
58 |
}
|
59 |
|
60 |
-
|
61 |
-
* @return int
|
62 |
-
*/
|
63 |
-
protected function getMaxDirLevels() {
|
64 |
return (int)max( 1, (int)$this->max_levels );
|
65 |
}
|
66 |
}
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\FileLocker;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Data\Adapter\DynProperties;
|
6 |
use FernleafSystems\Wordpress\Services\Services;
|
7 |
|
8 |
/**
|
15 |
*/
|
16 |
class File {
|
17 |
|
18 |
+
use DynProperties;
|
19 |
|
20 |
+
public function __construct( string $filename, $dir = ABSPATH ) {
|
21 |
+
$this->file = $filename;
|
22 |
+
$this->dir = wp_normalize_path( $dir );
|
23 |
}
|
24 |
|
25 |
/**
|
26 |
* @return string[]
|
27 |
*/
|
28 |
+
public function getExistingPossiblePaths() :array {
|
29 |
return array_filter(
|
30 |
$this->getPossiblePaths(),
|
31 |
+
function ( $path ) {
|
32 |
+
return !empty( $path ) && Services::WpFs()->isFile( $path );
|
33 |
}
|
34 |
);
|
35 |
}
|
37 |
/**
|
38 |
* @return string[]
|
39 |
*/
|
40 |
+
public function getPossiblePaths() :array {
|
41 |
$paths = [];
|
42 |
$dirCount = 0;
|
43 |
$workingDir = realpath( $this->dir );
|
57 |
return $paths;
|
58 |
}
|
59 |
|
60 |
+
protected function getMaxDirLevels() :int {
|
|
|
|
|
|
|
61 |
return (int)max( 1, (int)$this->max_levels );
|
62 |
}
|
63 |
}
|
src/lib/src/Modules/HackGuard/Lib/FileLocker/FileLockerController.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\FileLocker;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Logic\
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Databases\FileLocker;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules;
|
8 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard;
|
@@ -12,12 +12,15 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
12 |
class FileLockerController {
|
13 |
|
14 |
use Modules\ModConsumer;
|
15 |
-
use
|
16 |
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
|
|
|
|
|
|
21 |
/** @var HackGuard\Options $opts */
|
22 |
$opts = $this->getOptions();
|
23 |
return ( count( $opts->getFilesToLock() ) > 0 )
|
@@ -27,46 +30,30 @@ class FileLockerController {
|
|
27 |
->canHandshake();
|
28 |
}
|
29 |
|
30 |
-
/**
|
31 |
-
* @return bool
|
32 |
-
*/
|
33 |
-
protected function canRun() {
|
34 |
-
/** @var HackGuard\ModCon $mod */
|
35 |
-
$mod = $this->getMod();
|
36 |
-
return $this->isEnabled() && $mod->getDbHandler_FileLocker()->isReady();
|
37 |
-
}
|
38 |
-
|
39 |
protected function run() {
|
40 |
-
|
|
|
|
|
|
|
41 |
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
}
|
47 |
-
else {
|
48 |
-
$this->runAnalysis();
|
49 |
-
}
|
50 |
-
}
|
51 |
-
} );
|
52 |
}
|
53 |
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
public function addAdminMenuBarItem( array $aItems ) {
|
59 |
-
$nCountFL = $this->countProblems();
|
60 |
-
if ( $nCountFL > 0 ) {
|
61 |
-
$aItems[] = [
|
62 |
'id' => $this->getCon()->prefix( 'filelocker_problems' ),
|
63 |
'title' => __( 'File Locker', 'wp-simple-firewall' )
|
64 |
-
.sprintf( '<div class="wp-core-ui wp-ui-notification shield-counter"><span aria-hidden="true">%s</span></div>', $
|
65 |
'href' => $this->getCon()->getModule_Insights()->getUrl_SubInsightsPage( 'scans' ),
|
66 |
-
'warnings' => $
|
67 |
];
|
68 |
}
|
69 |
-
return $
|
70 |
}
|
71 |
|
72 |
/**
|
@@ -79,43 +66,47 @@ class FileLockerController {
|
|
79 |
}
|
80 |
|
81 |
/**
|
82 |
-
* @param FileLocker\EntryVO $
|
83 |
* @return string[]
|
84 |
*/
|
85 |
-
public function createFileDownloadLinks( $
|
86 |
/** @var HackGuard\ModCon $mod */
|
87 |
$mod = $this->getMod();
|
88 |
-
$
|
89 |
-
foreach ( [ 'original', 'current' ] as $
|
90 |
-
$
|
91 |
-
|
92 |
-
|
93 |
-
|
|
|
94 |
}
|
95 |
-
return $
|
96 |
}
|
97 |
|
98 |
public function handleFileDownloadRequest() {
|
99 |
-
$
|
100 |
-
$
|
101 |
|
102 |
-
if ( $
|
103 |
-
$
|
104 |
|
105 |
// Note: Download what's on the disk if nothing is changed.
|
106 |
-
if ( $
|
107 |
-
$
|
108 |
}
|
109 |
-
elseif ( $
|
110 |
-
$
|
111 |
->setMod( $this->getMod() )
|
112 |
-
->run( $
|
|
|
|
|
|
|
113 |
}
|
114 |
|
115 |
-
if ( !empty( $
|
116 |
header( 'Set-Cookie: fileDownload=true; path=/' );
|
117 |
Services::Response()
|
118 |
-
->downloadStringAsFile( $
|
119 |
}
|
120 |
}
|
121 |
|
@@ -135,52 +126,69 @@ class FileLockerController {
|
|
135 |
}
|
136 |
|
137 |
/**
|
138 |
-
* @param int $
|
139 |
* @return FileLocker\EntryVO|null
|
140 |
*/
|
141 |
-
public function getFileLock( $
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
return isset( $aLocks[ $nID ] ) ? $aLocks[ $nID ] : null;
|
146 |
}
|
147 |
|
148 |
private function runAnalysis() {
|
149 |
-
/** @var Modules\HackGuard\Options $oOpts */
|
150 |
-
$oOpts = $this->getOptions();
|
151 |
-
|
152 |
// 1. First assess the existing locks for changes.
|
153 |
( new Ops\AssessLocks() )
|
154 |
->setMod( $this->getMod() )
|
155 |
->run();
|
156 |
|
157 |
-
// 2. Create
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
164 |
}
|
165 |
-
|
166 |
-
|
|
|
167 |
}
|
168 |
}
|
169 |
}
|
170 |
|
171 |
/**
|
172 |
-
* @param string $
|
173 |
* @return File|null
|
174 |
* @throws \Exception
|
175 |
*/
|
176 |
-
private function getFile( $
|
177 |
$oFile = null;
|
178 |
|
179 |
$bIsSplitWp = false;
|
180 |
$nMaxPaths = 0;
|
181 |
-
switch ( $
|
182 |
case 'wpconfig':
|
183 |
-
$
|
184 |
$nMaxPaths = 1;
|
185 |
$nLevels = $bIsSplitWp ? 3 : 2;
|
186 |
|
@@ -192,21 +200,21 @@ class FileLockerController {
|
|
192 |
break;
|
193 |
|
194 |
case 'root_htaccess':
|
195 |
-
$
|
196 |
$nLevels = $bIsSplitWp ? 2 : 1;
|
197 |
break;
|
198 |
|
199 |
case 'root_webconfig':
|
200 |
-
$
|
201 |
$nLevels = $bIsSplitWp ? 2 : 1;
|
202 |
break;
|
203 |
|
204 |
case 'root_index':
|
205 |
-
$
|
206 |
$nLevels = $bIsSplitWp ? 2 : 1;
|
207 |
break;
|
208 |
default:
|
209 |
-
if ( Services::WpFs()->isAbsPath( $
|
210 |
$nLevels = 1;
|
211 |
$nMaxPaths = 1;
|
212 |
}
|
@@ -215,9 +223,24 @@ class FileLockerController {
|
|
215 |
}
|
216 |
break;
|
217 |
}
|
218 |
-
$oFile = new File( $
|
219 |
$oFile->max_levels = $nLevels;
|
220 |
$oFile->max_paths = $nMaxPaths;
|
221 |
return $oFile;
|
222 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
223 |
}
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\FileLocker;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Logic\ExecOnce;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Databases\FileLocker;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules;
|
8 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard;
|
12 |
class FileLockerController {
|
13 |
|
14 |
use Modules\ModConsumer;
|
15 |
+
use ExecOnce;
|
16 |
|
17 |
+
protected function canRun() :bool {
|
18 |
+
/** @var HackGuard\ModCon $mod */
|
19 |
+
$mod = $this->getMod();
|
20 |
+
return $this->isEnabled() && $mod->getDbHandler_FileLocker()->isReady();
|
21 |
+
}
|
22 |
+
|
23 |
+
public function isEnabled() :bool {
|
24 |
/** @var HackGuard\Options $opts */
|
25 |
$opts = $this->getOptions();
|
26 |
return ( count( $opts->getFilesToLock() ) > 0 )
|
30 |
->canHandshake();
|
31 |
}
|
32 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
protected function run() {
|
34 |
+
$con = $this->getCon();
|
35 |
+
add_filter( $con->prefix( 'admin_bar_menu_items' ), [ $this, 'addAdminMenuBarItem' ], 100 );
|
36 |
+
add_action( $con->prefix( 'pre_plugin_shutdown' ), [ $this, 'processFileLocks' ] );
|
37 |
+
}
|
38 |
|
39 |
+
public function processFileLocks() {
|
40 |
+
if ( !$this->getCon()->plugin_deactivating && !$this->getCon()->is_my_upgrade ) {
|
41 |
+
$this->getOptions()->isOptChanged( 'file_locker' ) ? $this->deleteAllLocks() : $this->runAnalysis();
|
42 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
}
|
44 |
|
45 |
+
public function addAdminMenuBarItem( array $items ) :array {
|
46 |
+
$problems = $this->countProblems();
|
47 |
+
if ( $problems > 0 ) {
|
48 |
+
$items[] = [
|
|
|
|
|
|
|
|
|
49 |
'id' => $this->getCon()->prefix( 'filelocker_problems' ),
|
50 |
'title' => __( 'File Locker', 'wp-simple-firewall' )
|
51 |
+
.sprintf( '<div class="wp-core-ui wp-ui-notification shield-counter"><span aria-hidden="true">%s</span></div>', $problems ),
|
52 |
'href' => $this->getCon()->getModule_Insights()->getUrl_SubInsightsPage( 'scans' ),
|
53 |
+
'warnings' => $problems
|
54 |
];
|
55 |
}
|
56 |
+
return $items;
|
57 |
}
|
58 |
|
59 |
/**
|
66 |
}
|
67 |
|
68 |
/**
|
69 |
+
* @param FileLocker\EntryVO $lock
|
70 |
* @return string[]
|
71 |
*/
|
72 |
+
public function createFileDownloadLinks( $lock ) :array {
|
73 |
/** @var HackGuard\ModCon $mod */
|
74 |
$mod = $this->getMod();
|
75 |
+
$links = [];
|
76 |
+
foreach ( [ 'original', 'current' ] as $type ) {
|
77 |
+
$links[ $type ] = $mod->createFileDownloadLink( 'filelocker', [
|
78 |
+
'type' => $type,
|
79 |
+
'rid' => $lock->id,
|
80 |
+
'rand' => uniqid(),
|
81 |
+
] );
|
82 |
}
|
83 |
+
return $links;
|
84 |
}
|
85 |
|
86 |
public function handleFileDownloadRequest() {
|
87 |
+
$req = Services::Request();
|
88 |
+
$lock = $this->getFileLock( (int)$req->query( 'rid', 0 ) );
|
89 |
|
90 |
+
if ( $lock instanceof FileLocker\EntryVO ) {
|
91 |
+
$type = $req->query( 'type' );
|
92 |
|
93 |
// Note: Download what's on the disk if nothing is changed.
|
94 |
+
if ( $type == 'current' ) {
|
95 |
+
$content = Services::WpFs()->getFileContent( $lock->file );
|
96 |
}
|
97 |
+
elseif ( $type == 'original' ) {
|
98 |
+
$content = ( new Lib\FileLocker\Ops\ReadOriginalFileContent() )
|
99 |
->setMod( $this->getMod() )
|
100 |
+
->run( $lock );
|
101 |
+
}
|
102 |
+
else {
|
103 |
+
throw new \Exception( 'Invalid file locker type download' );
|
104 |
}
|
105 |
|
106 |
+
if ( !empty( $content ) ) {
|
107 |
header( 'Set-Cookie: fileDownload=true; path=/' );
|
108 |
Services::Response()
|
109 |
+
->downloadStringAsFile( $content, strtoupper( $type ).'-'.basename( $lock->file ) );
|
110 |
}
|
111 |
}
|
112 |
|
126 |
}
|
127 |
|
128 |
/**
|
129 |
+
* @param int $ID
|
130 |
* @return FileLocker\EntryVO|null
|
131 |
*/
|
132 |
+
public function getFileLock( $ID ) {
|
133 |
+
return ( new Lib\FileLocker\Ops\LoadFileLocks() )
|
134 |
+
->setMod( $this->getMod() )
|
135 |
+
->loadLocks()[ $ID ] ?? null;
|
|
|
136 |
}
|
137 |
|
138 |
private function runAnalysis() {
|
|
|
|
|
|
|
139 |
// 1. First assess the existing locks for changes.
|
140 |
( new Ops\AssessLocks() )
|
141 |
->setMod( $this->getMod() )
|
142 |
->run();
|
143 |
|
144 |
+
// 2. Create any outstanding locks.
|
145 |
+
$this->runLocksCreation();
|
146 |
+
}
|
147 |
+
|
148 |
+
/**
|
149 |
+
* There's at least 15 seconds between each attempt to create a file lock.
|
150 |
+
* This ensures our API isn't bombarded by sites that, for some reason, fail to store the lock in the DB.
|
151 |
+
*/
|
152 |
+
private function runLocksCreation() {
|
153 |
+
/** @var Modules\HackGuard\Options $opts */
|
154 |
+
$opts = $this->getOptions();
|
155 |
+
$filesToLock = $opts->getFilesToLock();
|
156 |
+
|
157 |
+
$state = $this->getState();
|
158 |
+
if ( !empty( $filesToLock ) && Services::Request()->ts() - $state[ 'last_locks_created_at' ] > 60 ) {
|
159 |
+
|
160 |
+
$lockCreated = false;
|
161 |
+
foreach ( $opts->getFilesToLock() as $fileKey ) {
|
162 |
+
try {
|
163 |
+
$lockCreated = ( new Ops\CreateFileLocks() )
|
164 |
+
->setMod( $this->getMod() )
|
165 |
+
->setWorkingFile( $this->getFile( $fileKey ) )
|
166 |
+
->create();
|
167 |
+
}
|
168 |
+
catch ( \Exception $e ) {
|
169 |
+
error_log( $e->getMessage() );
|
170 |
+
}
|
171 |
}
|
172 |
+
if ( $lockCreated ) {
|
173 |
+
$state[ 'last_locks_created_at' ] = Services::Request()->ts();
|
174 |
+
$this->setState( $state );
|
175 |
}
|
176 |
}
|
177 |
}
|
178 |
|
179 |
/**
|
180 |
+
* @param string $fileKey
|
181 |
* @return File|null
|
182 |
* @throws \Exception
|
183 |
*/
|
184 |
+
private function getFile( $fileKey ) {
|
185 |
$oFile = null;
|
186 |
|
187 |
$bIsSplitWp = false;
|
188 |
$nMaxPaths = 0;
|
189 |
+
switch ( $fileKey ) {
|
190 |
case 'wpconfig':
|
191 |
+
$fileKey = 'wp-config.php';
|
192 |
$nMaxPaths = 1;
|
193 |
$nLevels = $bIsSplitWp ? 3 : 2;
|
194 |
|
200 |
break;
|
201 |
|
202 |
case 'root_htaccess':
|
203 |
+
$fileKey = '.htaccess';
|
204 |
$nLevels = $bIsSplitWp ? 2 : 1;
|
205 |
break;
|
206 |
|
207 |
case 'root_webconfig':
|
208 |
+
$fileKey = 'Web.Config';
|
209 |
$nLevels = $bIsSplitWp ? 2 : 1;
|
210 |
break;
|
211 |
|
212 |
case 'root_index':
|
213 |
+
$fileKey = 'index.php';
|
214 |
$nLevels = $bIsSplitWp ? 2 : 1;
|
215 |
break;
|
216 |
default:
|
217 |
+
if ( Services::WpFs()->isAbsPath( $fileKey ) && Services::WpFs()->isFile( $fileKey ) ) {
|
218 |
$nLevels = 1;
|
219 |
$nMaxPaths = 1;
|
220 |
}
|
223 |
}
|
224 |
break;
|
225 |
}
|
226 |
+
$oFile = new File( $fileKey );
|
227 |
$oFile->max_levels = $nLevels;
|
228 |
$oFile->max_paths = $nMaxPaths;
|
229 |
return $oFile;
|
230 |
}
|
231 |
+
|
232 |
+
protected function getState() :array {
|
233 |
+
/** @var HackGuard\Options $opts */
|
234 |
+
$opts = $this->getOptions();
|
235 |
+
return array_merge(
|
236 |
+
[
|
237 |
+
'last_locks_created_at' => 0
|
238 |
+
],
|
239 |
+
is_array( $opts->getOpt( 'filelocker_state' ) ) ? $opts->getOpt( 'filelocker_state' ) : []
|
240 |
+
);
|
241 |
+
}
|
242 |
+
|
243 |
+
protected function setState( array $state ) {
|
244 |
+
$this->getOptions()->setOpt( 'filelocker_state', $state );
|
245 |
+
}
|
246 |
}
|
src/lib/src/Modules/HackGuard/Lib/FileLocker/Ops/Accept.php
CHANGED
@@ -13,24 +13,24 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
13 |
class Accept extends BaseOps {
|
14 |
|
15 |
/**
|
16 |
-
* @param FileLocker\EntryVO $
|
17 |
* @return bool
|
18 |
* @throws \ErrorException
|
19 |
*/
|
20 |
-
public function run( $
|
21 |
/** @var ModCon $mod */
|
22 |
$mod = $this->getMod();
|
23 |
|
24 |
$aPublicKey = $this->getPublicKey();
|
25 |
-
$
|
26 |
->setMod( $mod )
|
27 |
-
->build( $
|
28 |
|
29 |
-
/** @var FileLocker\Update $
|
30 |
-
$
|
31 |
-
$
|
32 |
-
'hash_original' => hash_file( 'sha1', $
|
33 |
-
'content' => base64_encode( $
|
34 |
'public_key_id' => key( $aPublicKey ),
|
35 |
'detected_at' => 0,
|
36 |
'updated_at' => Services::Request()->ts(),
|
@@ -38,6 +38,6 @@ class Accept extends BaseOps {
|
|
38 |
] );
|
39 |
|
40 |
$this->clearFileLocksCache();
|
41 |
-
return $
|
42 |
}
|
43 |
}
|
13 |
class Accept extends BaseOps {
|
14 |
|
15 |
/**
|
16 |
+
* @param FileLocker\EntryVO $lock
|
17 |
* @return bool
|
18 |
* @throws \ErrorException
|
19 |
*/
|
20 |
+
public function run( $lock ) {
|
21 |
/** @var ModCon $mod */
|
22 |
$mod = $this->getMod();
|
23 |
|
24 |
$aPublicKey = $this->getPublicKey();
|
25 |
+
$raw = ( new BuildEncryptedFilePayload() )
|
26 |
->setMod( $mod )
|
27 |
+
->build( $lock->file, reset( $aPublicKey ) );
|
28 |
|
29 |
+
/** @var FileLocker\Update $updater */
|
30 |
+
$updater = $mod->getDbHandler_FileLocker()->getQueryUpdater();
|
31 |
+
$success = $updater->updateEntry( $lock, [
|
32 |
+
'hash_original' => hash_file( 'sha1', $lock->file ),
|
33 |
+
'content' => base64_encode( $raw ),
|
34 |
'public_key_id' => key( $aPublicKey ),
|
35 |
'detected_at' => 0,
|
36 |
'updated_at' => Services::Request()->ts(),
|
38 |
] );
|
39 |
|
40 |
$this->clearFileLocksCache();
|
41 |
+
return $success;
|
42 |
}
|
43 |
}
|
src/lib/src/Modules/HackGuard/Lib/FileLocker/Ops/AssessLocks.php
CHANGED
@@ -14,30 +14,30 @@ class AssessLocks extends BaseOps {
|
|
14 |
public function run() {
|
15 |
/** @var ModCon $mod */
|
16 |
$mod = $this->getMod();
|
17 |
-
/** @var FileLocker\Update $
|
18 |
-
$
|
19 |
|
20 |
$this->removeDuplicates();
|
21 |
|
22 |
$aProblemIds = [];
|
23 |
-
foreach ( $this->getFileLocks() as $
|
24 |
try {
|
25 |
-
if ( ( new CompareHash() )->isEqualFileSha1( $
|
26 |
-
if ( !empty( $
|
27 |
-
$
|
28 |
}
|
29 |
}
|
30 |
else {
|
31 |
-
$
|
32 |
-
if ( empty( $
|
33 |
-
$
|
34 |
-
$aProblemIds[] = $
|
35 |
}
|
36 |
}
|
37 |
}
|
38 |
catch ( \InvalidArgumentException $e ) {
|
39 |
-
$
|
40 |
-
$aProblemIds[] = $
|
41 |
}
|
42 |
}
|
43 |
$this->clearFileLocksCache();
|
@@ -45,20 +45,20 @@ class AssessLocks extends BaseOps {
|
|
45 |
}
|
46 |
|
47 |
private function removeDuplicates() {
|
48 |
-
$
|
49 |
-
foreach ( $this->getFileLocks() as $
|
50 |
-
if ( in_array( $
|
51 |
/** @var ModCon $mod */
|
52 |
$mod = $this->getMod();
|
53 |
$mod->getDbHandler_FileLocker()
|
54 |
->getQueryDeleter()
|
55 |
-
->deleteById( $
|
56 |
}
|
57 |
else {
|
58 |
-
$
|
59 |
}
|
60 |
}
|
61 |
-
if ( count( $this->getFileLocks() ) != count( $
|
62 |
$this->clearFileLocksCache();
|
63 |
}
|
64 |
}
|
14 |
public function run() {
|
15 |
/** @var ModCon $mod */
|
16 |
$mod = $this->getMod();
|
17 |
+
/** @var FileLocker\Update $updater */
|
18 |
+
$updater = $mod->getDbHandler_FileLocker()->getQueryUpdater();
|
19 |
|
20 |
$this->removeDuplicates();
|
21 |
|
22 |
$aProblemIds = [];
|
23 |
+
foreach ( $this->getFileLocks() as $lock ) {
|
24 |
try {
|
25 |
+
if ( ( new CompareHash() )->isEqualFileSha1( $lock->file, $lock->hash_original ) ) {
|
26 |
+
if ( !empty( $lock->hash_current ) ) {
|
27 |
+
$updater->updateCurrentHash( $lock, '' );
|
28 |
}
|
29 |
}
|
30 |
else {
|
31 |
+
$fileHash = hash_file( 'sha1', $lock->file );
|
32 |
+
if ( empty( $lock->hash_current ) || !hash_equals( $lock->hash_current, $fileHash ) ) {
|
33 |
+
$updater->updateCurrentHash( $lock, $fileHash );
|
34 |
+
$aProblemIds[] = $lock->id;
|
35 |
}
|
36 |
}
|
37 |
}
|
38 |
catch ( \InvalidArgumentException $e ) {
|
39 |
+
$updater->markProblem( $lock );
|
40 |
+
$aProblemIds[] = $lock->id;
|
41 |
}
|
42 |
}
|
43 |
$this->clearFileLocksCache();
|
45 |
}
|
46 |
|
47 |
private function removeDuplicates() {
|
48 |
+
$paths = [];
|
49 |
+
foreach ( $this->getFileLocks() as $lock ) {
|
50 |
+
if ( in_array( $lock->file, $paths ) ) {
|
51 |
/** @var ModCon $mod */
|
52 |
$mod = $this->getMod();
|
53 |
$mod->getDbHandler_FileLocker()
|
54 |
->getQueryDeleter()
|
55 |
+
->deleteById( $lock->id );
|
56 |
}
|
57 |
else {
|
58 |
+
$paths[] = $lock->file;
|
59 |
}
|
60 |
}
|
61 |
+
if ( count( $this->getFileLocks() ) != count( $paths ) ) {
|
62 |
$this->clearFileLocksCache();
|
63 |
}
|
64 |
}
|
src/lib/src/Modules/HackGuard/Lib/FileLocker/Ops/BaseOps.php
CHANGED
@@ -50,14 +50,14 @@ class BaseOps {
|
|
50 |
* @return array
|
51 |
* @throws \ErrorException
|
52 |
*/
|
53 |
-
protected function getPublicKey() {
|
54 |
-
$
|
55 |
->setMod( $this->getMod() )
|
56 |
->retrieve();
|
57 |
-
if ( empty( $
|
58 |
throw new \ErrorException( 'Cannot encrypt without a public key' );
|
59 |
}
|
60 |
-
return $
|
61 |
}
|
62 |
|
63 |
/**
|
50 |
* @return array
|
51 |
* @throws \ErrorException
|
52 |
*/
|
53 |
+
protected function getPublicKey() :array {
|
54 |
+
$key = ( new GetPublicKey() )
|
55 |
->setMod( $this->getMod() )
|
56 |
->retrieve();
|
57 |
+
if ( empty( $key ) || !is_array( $key ) ) {
|
58 |
throw new \ErrorException( 'Cannot encrypt without a public key' );
|
59 |
}
|
60 |
+
return $key;
|
61 |
}
|
62 |
|
63 |
/**
|
src/lib/src/Modules/HackGuard/Lib/FileLocker/Ops/CreateFileLocks.php
CHANGED
@@ -15,44 +15,46 @@ class CreateFileLocks extends BaseOps {
|
|
15 |
/**
|
16 |
* @throws \Exception
|
17 |
*/
|
18 |
-
public function create() {
|
19 |
-
|
20 |
-
foreach ( $this->oFile->getExistingPossiblePaths() as $
|
21 |
-
$
|
22 |
-
foreach ( $this->getFileLocks() as $
|
23 |
-
if ( $
|
24 |
-
$
|
25 |
break;
|
26 |
}
|
27 |
}
|
28 |
-
if ( !$
|
29 |
-
$this->processPath( $
|
|
|
30 |
}
|
31 |
}
|
|
|
32 |
}
|
33 |
|
34 |
/**
|
35 |
* @param string $path
|
36 |
* @throws \Exception
|
37 |
*/
|
38 |
-
private function processPath( $path ) {
|
39 |
/** @var ModCon $mod */
|
40 |
$mod = $this->getMod();
|
41 |
|
42 |
if ( Services::WpFs()->isFile( $path ) ) {
|
43 |
-
$
|
44 |
-
$
|
45 |
-
$
|
46 |
|
47 |
-
$
|
48 |
-
$
|
49 |
-
$
|
50 |
->setMod( $mod )
|
51 |
-
->build( $path, reset( $
|
52 |
|
53 |
/** @var FileLocker\Insert $oInserter */
|
54 |
$oInserter = $mod->getDbHandler_FileLocker()->getQueryInserter();
|
55 |
-
$oInserter->insert( $
|
56 |
|
57 |
$this->clearFileLocksCache();
|
58 |
}
|
15 |
/**
|
16 |
* @throws \Exception
|
17 |
*/
|
18 |
+
public function create() :bool {
|
19 |
+
$pathsProcessed = false;
|
20 |
+
foreach ( $this->oFile->getExistingPossiblePaths() as $path ) {
|
21 |
+
$theLock = null;
|
22 |
+
foreach ( $this->getFileLocks() as $maybeLock ) {
|
23 |
+
if ( $maybeLock->file === $path ) {
|
24 |
+
$theLock = $maybeLock;
|
25 |
break;
|
26 |
}
|
27 |
}
|
28 |
+
if ( !$theLock instanceof FileLocker\EntryVO ) {
|
29 |
+
$this->processPath( $path );
|
30 |
+
$pathsProcessed = true;
|
31 |
}
|
32 |
}
|
33 |
+
return $pathsProcessed;
|
34 |
}
|
35 |
|
36 |
/**
|
37 |
* @param string $path
|
38 |
* @throws \Exception
|
39 |
*/
|
40 |
+
private function processPath( string $path ) {
|
41 |
/** @var ModCon $mod */
|
42 |
$mod = $this->getMod();
|
43 |
|
44 |
if ( Services::WpFs()->isFile( $path ) ) {
|
45 |
+
$entry = new FileLocker\EntryVO();
|
46 |
+
$entry->file = $path;
|
47 |
+
$entry->hash_original = hash_file( 'sha1', $path );
|
48 |
|
49 |
+
$publicKey = $this->getPublicKey();
|
50 |
+
$entry->public_key_id = key( $publicKey );
|
51 |
+
$entry->content = ( new BuildEncryptedFilePayload() )
|
52 |
->setMod( $mod )
|
53 |
+
->build( $path, reset( $publicKey ) );
|
54 |
|
55 |
/** @var FileLocker\Insert $oInserter */
|
56 |
$oInserter = $mod->getDbHandler_FileLocker()->getQueryInserter();
|
57 |
+
$success = $oInserter->insert( $entry );
|
58 |
|
59 |
$this->clearFileLocksCache();
|
60 |
}
|
src/lib/src/Modules/HackGuard/Lib/FileLocker/Ops/Diff.php
CHANGED
@@ -13,34 +13,38 @@ use FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes;
|
|
13 |
class Diff extends BaseOps {
|
14 |
|
15 |
/**
|
16 |
-
* @param FileLocker\EntryVO $
|
17 |
* @return bool
|
18 |
* @throws \Exception
|
19 |
*/
|
20 |
-
public function run( $
|
21 |
|
22 |
$oFS = Services::WpFs();
|
23 |
|
24 |
-
if ( !$oFS->isFile( $
|
25 |
throw new \Exception( __( 'File is missing or could not be read.', 'wp-simple-firewall' ) );
|
26 |
}
|
27 |
|
28 |
-
$
|
29 |
-
if ( empty( $
|
30 |
throw new \Exception( __( 'File is empty or could not be read.', 'wp-simple-firewall' ) );
|
31 |
}
|
32 |
|
33 |
-
$
|
34 |
->setMod( $this->getMod() )
|
35 |
-
->run( $
|
36 |
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
|
|
|
|
|
|
|
|
42 |
|
43 |
-
return $
|
44 |
}
|
45 |
|
46 |
/**
|
13 |
class Diff extends BaseOps {
|
14 |
|
15 |
/**
|
16 |
+
* @param FileLocker\EntryVO $lock
|
17 |
* @return bool
|
18 |
* @throws \Exception
|
19 |
*/
|
20 |
+
public function run( $lock ) {
|
21 |
|
22 |
$oFS = Services::WpFs();
|
23 |
|
24 |
+
if ( !$oFS->isFile( $lock->file ) ) {
|
25 |
throw new \Exception( __( 'File is missing or could not be read.', 'wp-simple-firewall' ) );
|
26 |
}
|
27 |
|
28 |
+
$current = Services::WpFs()->getFileContent( $lock->file );
|
29 |
+
if ( empty( $current ) ) {
|
30 |
throw new \Exception( __( 'File is empty or could not be read.', 'wp-simple-firewall' ) );
|
31 |
}
|
32 |
|
33 |
+
$original = ( new ReadOriginalFileContent() )
|
34 |
->setMod( $this->getMod() )
|
35 |
+
->run( $lock );
|
36 |
|
37 |
+
/**
|
38 |
+
* The WP Diff is empty if the only difference is white space
|
39 |
+
* @since v10.3 always use WP Hashes DIFF
|
40 |
+
*
|
41 |
+
* $diff = $this->useWpDiff( $original, $current );
|
42 |
+
* if ( empty( $diff ) ) {
|
43 |
+
* $this->useWpHashes( $original, $current );
|
44 |
+
* }
|
45 |
+
*/
|
46 |
|
47 |
+
return $this->useWpHashes( $original, $current );
|
48 |
}
|
49 |
|
50 |
/**
|
src/lib/src/Modules/HackGuard/Lib/FileLocker/Ops/LoadFileLocks.php
CHANGED
@@ -29,10 +29,10 @@ class LoadFileLocks {
|
|
29 |
|
30 |
self::$aFileLockRecords = [];
|
31 |
if ( $mod->getFileLocker()->isEnabled() ) {
|
32 |
-
$
|
33 |
-
if ( is_array( $
|
34 |
-
foreach ( $
|
35 |
-
self::$aFileLockRecords[ $
|
36 |
}
|
37 |
}
|
38 |
}
|
@@ -46,8 +46,8 @@ class LoadFileLocks {
|
|
46 |
public function withProblems() {
|
47 |
return array_filter(
|
48 |
$this->loadLocks(),
|
49 |
-
function ( $
|
50 |
-
return $
|
51 |
}
|
52 |
);
|
53 |
}
|
@@ -58,8 +58,8 @@ class LoadFileLocks {
|
|
58 |
public function withProblemsNotNotified() {
|
59 |
return array_filter(
|
60 |
$this->withProblems(),
|
61 |
-
function ( $
|
62 |
-
return $
|
63 |
}
|
64 |
);
|
65 |
}
|
@@ -70,8 +70,8 @@ class LoadFileLocks {
|
|
70 |
public function withoutProblems() {
|
71 |
return array_filter(
|
72 |
$this->loadLocks(),
|
73 |
-
function ( $
|
74 |
-
return $
|
75 |
}
|
76 |
);
|
77 |
}
|
29 |
|
30 |
self::$aFileLockRecords = [];
|
31 |
if ( $mod->getFileLocker()->isEnabled() ) {
|
32 |
+
$all = $mod->getDbHandler_FileLocker()->getQuerySelector()->all();
|
33 |
+
if ( is_array( $all ) ) {
|
34 |
+
foreach ( $all as $lock ) {
|
35 |
+
self::$aFileLockRecords[ $lock->id ] = $lock;
|
36 |
}
|
37 |
}
|
38 |
}
|
46 |
public function withProblems() {
|
47 |
return array_filter(
|
48 |
$this->loadLocks(),
|
49 |
+
function ( $lock ) {
|
50 |
+
return $lock->detected_at > 0;
|
51 |
}
|
52 |
);
|
53 |
}
|
58 |
public function withProblemsNotNotified() {
|
59 |
return array_filter(
|
60 |
$this->withProblems(),
|
61 |
+
function ( $lock ) {
|
62 |
+
return $lock->notified_at == 0;
|
63 |
}
|
64 |
);
|
65 |
}
|
70 |
public function withoutProblems() {
|
71 |
return array_filter(
|
72 |
$this->loadLocks(),
|
73 |
+
function ( $lock ) {
|
74 |
+
return $lock->detected_at == 0;
|
75 |
}
|
76 |
);
|
77 |
}
|
src/lib/src/Modules/HackGuard/Lib/FileLocker/Ops/PerformAction.php
CHANGED
@@ -12,43 +12,43 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\ModCon;
|
|
12 |
class PerformAction extends BaseOps {
|
13 |
|
14 |
/**
|
15 |
-
* @param int $
|
16 |
-
* @param string $
|
17 |
* @return string
|
18 |
* @throws \Exception
|
19 |
*/
|
20 |
-
public function run( $
|
21 |
/** @var ModCon $mod */
|
22 |
$mod = $this->getMod();
|
23 |
|
24 |
-
if ( !in_array( $
|
25 |
throw new \Exception( __( 'Not a supported file lock action.', 'wp-simple-firewall' ) );
|
26 |
}
|
27 |
-
if ( !is_numeric( $
|
28 |
throw new \Exception( __( 'Please select a valid file.', 'wp-simple-firewall' ) );
|
29 |
}
|
30 |
-
$
|
31 |
-
|
32 |
-
|
33 |
-
if ( !$
|
34 |
throw new \Exception( __( 'Not valid file lock ID.', 'wp-simple-firewall' ) );
|
35 |
}
|
36 |
|
37 |
-
switch ( $
|
38 |
case 'accept':
|
39 |
$mResult = ( new Accept() )
|
40 |
->setMod( $this->getMod() )
|
41 |
-
->run( $
|
42 |
break;
|
43 |
case 'diff':
|
44 |
$mResult = ( new Diff() )
|
45 |
->setMod( $this->getMod() )
|
46 |
-
->run( $
|
47 |
break;
|
48 |
case 'restore':
|
49 |
$mResult = ( new Restore() )
|
50 |
->setMod( $this->getMod() )
|
51 |
-
->run( $
|
52 |
break;
|
53 |
default:
|
54 |
$mResult = false;
|
12 |
class PerformAction extends BaseOps {
|
13 |
|
14 |
/**
|
15 |
+
* @param int $lockID
|
16 |
+
* @param string $action
|
17 |
* @return string
|
18 |
* @throws \Exception
|
19 |
*/
|
20 |
+
public function run( $lockID, $action ) {
|
21 |
/** @var ModCon $mod */
|
22 |
$mod = $this->getMod();
|
23 |
|
24 |
+
if ( !in_array( $action, [ 'accept', 'restore', 'diff' ] ) ) {
|
25 |
throw new \Exception( __( 'Not a supported file lock action.', 'wp-simple-firewall' ) );
|
26 |
}
|
27 |
+
if ( !is_numeric( $lockID ) ) {
|
28 |
throw new \Exception( __( 'Please select a valid file.', 'wp-simple-firewall' ) );
|
29 |
}
|
30 |
+
$lock = $mod->getDbHandler_FileLocker()
|
31 |
+
->getQuerySelector()
|
32 |
+
->byId( (int)$lockID );
|
33 |
+
if ( !$lock instanceof Databases\FileLocker\EntryVO ) {
|
34 |
throw new \Exception( __( 'Not valid file lock ID.', 'wp-simple-firewall' ) );
|
35 |
}
|
36 |
|
37 |
+
switch ( $action ) {
|
38 |
case 'accept':
|
39 |
$mResult = ( new Accept() )
|
40 |
->setMod( $this->getMod() )
|
41 |
+
->run( $lock );
|
42 |
break;
|
43 |
case 'diff':
|
44 |
$mResult = ( new Diff() )
|
45 |
->setMod( $this->getMod() )
|
46 |
+
->run( $lock );
|
47 |
break;
|
48 |
case 'restore':
|
49 |
$mResult = ( new Restore() )
|
50 |
->setMod( $this->getMod() )
|
51 |
+
->run( $lock );
|
52 |
break;
|
53 |
default:
|
54 |
$mResult = false;
|
src/lib/src/Modules/HackGuard/Lib/FileLocker/Ops/ReadOriginalFileContent.php
CHANGED
@@ -28,33 +28,33 @@ class ReadOriginalFileContent extends BaseOps {
|
|
28 |
}
|
29 |
|
30 |
/**
|
31 |
-
* @param Databases\FileLocker\EntryVO $
|
32 |
* @return string|null
|
33 |
* @throws \Exception
|
34 |
*/
|
35 |
-
private function useOriginalFile( Databases\FileLocker\EntryVO $
|
36 |
-
$
|
37 |
-
if ( empty( $
|
38 |
-
&& $
|
39 |
-
return $
|
40 |
}
|
41 |
throw new \Exception( 'Cannot use original file' );
|
42 |
}
|
43 |
|
44 |
/**
|
45 |
-
* @param Databases\FileLocker\EntryVO $
|
46 |
* @return string|null
|
47 |
*/
|
48 |
-
private function useCacheAndApi( Databases\FileLocker\EntryVO $
|
49 |
-
$sCacheKey = 'file-content-'.$
|
50 |
-
$
|
51 |
-
if ( $
|
52 |
-
$
|
53 |
-
$
|
54 |
->setMod( $this->getMod() )
|
55 |
-
->retrieve( $
|
56 |
-
wp_cache_set( $sCacheKey, $
|
57 |
}
|
58 |
-
return $
|
59 |
}
|
60 |
}
|
28 |
}
|
29 |
|
30 |
/**
|
31 |
+
* @param Databases\FileLocker\EntryVO $lock
|
32 |
* @return string|null
|
33 |
* @throws \Exception
|
34 |
*/
|
35 |
+
private function useOriginalFile( Databases\FileLocker\EntryVO $lock ) {
|
36 |
+
$FS = Services::WpFs();
|
37 |
+
if ( empty( $lock->detected_at ) && empty( $lock->hash_current )
|
38 |
+
&& $FS->exists( $lock->file ) ) {
|
39 |
+
return $FS->getFileContent( $lock->file );
|
40 |
}
|
41 |
throw new \Exception( 'Cannot use original file' );
|
42 |
}
|
43 |
|
44 |
/**
|
45 |
+
* @param Databases\FileLocker\EntryVO $lock
|
46 |
* @return string|null
|
47 |
*/
|
48 |
+
private function useCacheAndApi( Databases\FileLocker\EntryVO $lock ) {
|
49 |
+
$sCacheKey = 'file-content-'.$lock->id;
|
50 |
+
$content = wp_cache_get( $sCacheKey, $this->getCon()->prefix( 'filelocker' ) );
|
51 |
+
if ( $content === false ) {
|
52 |
+
$VO = ( new OpenSslEncryptVo() )->applyFromArray( json_decode( $lock->content, true ) );
|
53 |
+
$content = ( new DecryptFile() )
|
54 |
->setMod( $this->getMod() )
|
55 |
+
->retrieve( $VO, $lock->public_key_id );
|
56 |
+
wp_cache_set( $sCacheKey, $content, $this->getCon()->prefix( 'filelocker' ), 3 );
|
57 |
}
|
58 |
+
return $content;
|
59 |
}
|
60 |
}
|
src/lib/src/Modules/HackGuard/Lib/Utility/FileDownloadHandler.php
CHANGED
@@ -11,19 +11,19 @@ class FileDownloadHandler {
|
|
11 |
use HandlerConsumer;
|
12 |
|
13 |
/**
|
14 |
-
* @param int $
|
15 |
*/
|
16 |
-
public function downloadByItemId( $
|
17 |
-
/** @var Scanner\EntryVO $
|
18 |
-
$
|
19 |
-
|
20 |
-
|
21 |
-
if ( $
|
22 |
-
$
|
23 |
-
$
|
24 |
-
if ( $
|
25 |
header( 'Set-Cookie: fileDownload=true; path=/' );
|
26 |
-
Services::Response()->downloadStringAsFile( $
|
27 |
}
|
28 |
}
|
29 |
|
11 |
use HandlerConsumer;
|
12 |
|
13 |
/**
|
14 |
+
* @param int $itemID
|
15 |
*/
|
16 |
+
public function downloadByItemId( int $itemID ) {
|
17 |
+
/** @var Scanner\EntryVO $entry */
|
18 |
+
$entry = $this->getDbHandler()
|
19 |
+
->getQuerySelector()
|
20 |
+
->byId( (int)$itemID );
|
21 |
+
if ( $entry instanceof Scanner\EntryVO && !empty( $entry->meta[ 'path_full' ] ) ) {
|
22 |
+
$path = $entry->meta[ 'path_full' ];
|
23 |
+
$FS = Services::WpFs();
|
24 |
+
if ( $FS->isFile( $path ) ) {
|
25 |
header( 'Set-Cookie: fileDownload=true; path=/' );
|
26 |
+
Services::Response()->downloadStringAsFile( $FS->getFileContent( $path ), basename( $path ) );
|
27 |
}
|
28 |
}
|
29 |
|
src/lib/src/Modules/HackGuard/ModCon.php
CHANGED
@@ -74,19 +74,16 @@ class ModCon extends BaseShield\ModCon {
|
|
74 |
] );
|
75 |
}
|
76 |
|
77 |
-
protected function
|
78 |
-
switch ( $
|
79 |
-
case
|
|
|
|
|
|
|
80 |
( new Lib\Utility\FileDownloadHandler() )
|
81 |
->setDbHandler( $this->getDbHandler_ScanResults() )
|
82 |
->downloadByItemId( (int)Services::Request()->query( 'rid', 0 ) );
|
83 |
break;
|
84 |
-
case 'filelocker_download_original':
|
85 |
-
case 'filelocker_download_current':
|
86 |
-
$this->getFileLocker()->handleFileDownloadRequest();
|
87 |
-
break;
|
88 |
-
default:
|
89 |
-
break;
|
90 |
}
|
91 |
}
|
92 |
|
@@ -193,7 +190,8 @@ class ModCon extends BaseShield\ModCon {
|
|
193 |
}
|
194 |
|
195 |
public function getDbHandler_FileLocker() :Databases\FileLocker\Handler {
|
196 |
-
|
|
|
197 |
}
|
198 |
|
199 |
public function getDbHandler_ScanQueue() :Databases\ScanQueue\Handler {
|
@@ -201,7 +199,7 @@ class ModCon extends BaseShield\ModCon {
|
|
201 |
}
|
202 |
|
203 |
public function getDbHandler_ScanResults() :Databases\Scanner\Handler {
|
204 |
-
return $this->getDbH( '
|
205 |
}
|
206 |
|
207 |
/**
|
@@ -218,9 +216,9 @@ class ModCon extends BaseShield\ModCon {
|
|
218 |
|
219 |
public function onPluginDeactivate() {
|
220 |
// 1. Clean out the scanners
|
221 |
-
/** @var Options $
|
222 |
-
$
|
223 |
-
foreach ( $
|
224 |
$this->getScanCon( $slug )->purge();
|
225 |
}
|
226 |
$this->getDbHandler_ScanQueue()->tableDelete();
|
74 |
] );
|
75 |
}
|
76 |
|
77 |
+
protected function handleFileDownload( string $downloadID ) {
|
78 |
+
switch ( $downloadID ) {
|
79 |
+
case 'filelocker':
|
80 |
+
$this->getFileLocker()->handleFileDownloadRequest();
|
81 |
+
break;
|
82 |
+
case 'scan_file':
|
83 |
( new Lib\Utility\FileDownloadHandler() )
|
84 |
->setDbHandler( $this->getDbHandler_ScanResults() )
|
85 |
->downloadByItemId( (int)Services::Request()->query( 'rid', 0 ) );
|
86 |
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
87 |
}
|
88 |
}
|
89 |
|
190 |
}
|
191 |
|
192 |
public function getDbHandler_FileLocker() :Databases\FileLocker\Handler {
|
193 |
+
$new = $this->getDbH( 'filelocker' );
|
194 |
+
return empty( $new ) ? $this->getDbH( 'file_protect' ) : $new;
|
195 |
}
|
196 |
|
197 |
public function getDbHandler_ScanQueue() :Databases\ScanQueue\Handler {
|
199 |
}
|
200 |
|
201 |
public function getDbHandler_ScanResults() :Databases\Scanner\Handler {
|
202 |
+
return $this->getDbH( 'scanner' );
|
203 |
}
|
204 |
|
205 |
/**
|
216 |
|
217 |
public function onPluginDeactivate() {
|
218 |
// 1. Clean out the scanners
|
219 |
+
/** @var Options $opts */
|
220 |
+
$opts = $this->getOptions();
|
221 |
+
foreach ( $opts->getScanSlugs() as $slug ) {
|
222 |
$this->getScanCon( $slug )->purge();
|
223 |
}
|
224 |
$this->getDbHandler_ScanQueue()->tableDelete();
|
src/lib/src/Modules/HackGuard/Scan/Controller/Base.php
CHANGED
@@ -59,11 +59,7 @@ abstract class Base {
|
|
59 |
}
|
60 |
|
61 |
public function createFileDownloadLink( Databases\Scanner\EntryVO $entry ) :string {
|
62 |
-
|
63 |
-
$mod = $this->getMod();
|
64 |
-
$aActionNonce = $mod->getNonceActionData( 'scan_file_download' );
|
65 |
-
$aActionNonce[ 'rid' ] = $entry->id;
|
66 |
-
return add_query_arg( $aActionNonce, $mod->getUrl_AdminPage() );
|
67 |
}
|
68 |
|
69 |
public function getLastScanAt() :int {
|
59 |
}
|
60 |
|
61 |
public function createFileDownloadLink( Databases\Scanner\EntryVO $entry ) :string {
|
62 |
+
return $this->getMod()->createFileDownloadLink( 'scan_file', [ 'rid' => $entry->id ] );
|
|
|
|
|
|
|
|
|
63 |
}
|
64 |
|
65 |
public function getLastScanAt() :int {
|
src/lib/src/Modules/HackGuard/Scan/Queue/CompleteQueue.php
CHANGED
@@ -25,20 +25,20 @@ class CompleteQueue {
|
|
25 |
/** @var ModCon $mod */
|
26 |
$mod = $this->getMod();
|
27 |
$con = $this->getCon();
|
28 |
-
/** @var Databases\ScanQueue\Handler $
|
29 |
-
$
|
30 |
-
$oSel = $
|
31 |
|
32 |
-
foreach ( $oSel->getDistinctForColumn( 'scan' ) as $
|
33 |
|
34 |
-
$oScanCon = $mod->getScanCon( $
|
35 |
|
36 |
$oResultsSet = ( new CollateResults() )
|
37 |
->setScanController( $oScanCon )
|
38 |
-
->setDbHandler( $
|
39 |
-
->collate( $
|
40 |
|
41 |
-
$con->fireEvent( $
|
42 |
|
43 |
if ( $oResultsSet instanceof Scans\Base\BaseResultsSet ) {
|
44 |
( new HackGuard\Scan\Results\ResultsUpdate() )
|
@@ -46,14 +46,14 @@ class CompleteQueue {
|
|
46 |
->update( $oResultsSet );
|
47 |
|
48 |
if ( $oResultsSet->countItems() > 0 ) {
|
49 |
-
$con->fireEvent( $
|
50 |
}
|
51 |
}
|
52 |
|
53 |
-
/** @var Databases\ScanQueue\Delete $
|
54 |
-
$
|
55 |
-
$
|
56 |
-
|
57 |
}
|
58 |
|
59 |
/** @var HackGuard\Options $opts */
|
25 |
/** @var ModCon $mod */
|
26 |
$mod = $this->getMod();
|
27 |
$con = $this->getCon();
|
28 |
+
/** @var Databases\ScanQueue\Handler $dbh */
|
29 |
+
$dbh = $this->getDbHandler();
|
30 |
+
$oSel = $dbh->getQuerySelector();
|
31 |
|
32 |
+
foreach ( $oSel->getDistinctForColumn( 'scan' ) as $scanSlug ) {
|
33 |
|
34 |
+
$oScanCon = $mod->getScanCon( $scanSlug );
|
35 |
|
36 |
$oResultsSet = ( new CollateResults() )
|
37 |
->setScanController( $oScanCon )
|
38 |
+
->setDbHandler( $dbh )
|
39 |
+
->collate( $scanSlug );
|
40 |
|
41 |
+
$con->fireEvent( $scanSlug.'_scan_run' );
|
42 |
|
43 |
if ( $oResultsSet instanceof Scans\Base\BaseResultsSet ) {
|
44 |
( new HackGuard\Scan\Results\ResultsUpdate() )
|
46 |
->update( $oResultsSet );
|
47 |
|
48 |
if ( $oResultsSet->countItems() > 0 ) {
|
49 |
+
$con->fireEvent( $scanSlug.'_scan_found' );
|
50 |
}
|
51 |
}
|
52 |
|
53 |
+
/** @var Databases\ScanQueue\Delete $deleter */
|
54 |
+
$deleter = $dbh->getQueryDeleter();
|
55 |
+
$deleter->filterByScan( $scanSlug )
|
56 |
+
->query();
|
57 |
}
|
58 |
|
59 |
/** @var HackGuard\Options $opts */
|
src/lib/src/Modules/HackGuard/Scan/Queue/ConvertBetweenTypes.php
CHANGED
@@ -39,7 +39,7 @@ class ConvertBetweenTypes {
|
|
39 |
}
|
40 |
unset( $oAction->items );
|
41 |
unset( $oAction->results );
|
42 |
-
$entry->meta = $oAction->
|
43 |
return $entry;
|
44 |
}
|
45 |
}
|
39 |
}
|
40 |
unset( $oAction->items );
|
41 |
unset( $oAction->results );
|
42 |
+
$entry->meta = $oAction->getRawData();
|
43 |
return $entry;
|
44 |
}
|
45 |
}
|
src/lib/src/Modules/HackGuard/Scan/Queue/QueueProcessor.php
CHANGED
@@ -96,12 +96,11 @@ class QueueProcessor extends Utilities\BackgroundProcessing\BackgroundProcess {
|
|
96 |
* @return bool
|
97 |
*/
|
98 |
protected function is_queue_empty() {
|
99 |
-
/** @var ScanQueue\Select $
|
100 |
-
$
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
return $nUnfinished === 0;
|
105 |
}
|
106 |
|
107 |
/**
|
@@ -112,12 +111,12 @@ class QueueProcessor extends Utilities\BackgroundProcessing\BackgroundProcess {
|
|
112 |
public function save() {
|
113 |
|
114 |
if ( is_array( $this->data ) ) {
|
115 |
-
/** @var ScanQueue\Insert $
|
116 |
-
$
|
117 |
-
foreach ( $this->data as $nKey => $
|
118 |
-
/** @var ScanQueue\EntryVO $
|
119 |
-
if ( $
|
120 |
-
$
|
121 |
}
|
122 |
}
|
123 |
}
|
@@ -134,18 +133,18 @@ class QueueProcessor extends Utilities\BackgroundProcessing\BackgroundProcess {
|
|
134 |
* @return $this
|
135 |
*/
|
136 |
public function update( $key, $data ) {
|
137 |
-
/** @var ScanQueue\Update $
|
138 |
-
$
|
139 |
-
$
|
140 |
-
$
|
141 |
return $this;
|
142 |
}
|
143 |
|
144 |
public function handleExpiredItems() {
|
145 |
-
$
|
146 |
-
|
147 |
-
|
148 |
-
$this->getDbHandler()->deleteRowsOlderThan( $
|
149 |
}
|
150 |
|
151 |
/**
|
96 |
* @return bool
|
97 |
*/
|
98 |
protected function is_queue_empty() {
|
99 |
+
/** @var ScanQueue\Select $selector */
|
100 |
+
$selector = $this->getDbHandler()->getQuerySelector();
|
101 |
+
return $selector->filterByNotStarted()
|
102 |
+
->filterByNotFinished()
|
103 |
+
->count() === 0;
|
|
|
104 |
}
|
105 |
|
106 |
/**
|
111 |
public function save() {
|
112 |
|
113 |
if ( is_array( $this->data ) ) {
|
114 |
+
/** @var ScanQueue\Insert $inserter */
|
115 |
+
$inserter = $this->getDbHandler()->getQueryInserter();
|
116 |
+
foreach ( $this->data as $nKey => $entry ) {
|
117 |
+
/** @var ScanQueue\EntryVO $entry */
|
118 |
+
if ( $entry instanceof ScanQueue\EntryVO ) {
|
119 |
+
$inserter->insert( $entry );
|
120 |
}
|
121 |
}
|
122 |
}
|
133 |
* @return $this
|
134 |
*/
|
135 |
public function update( $key, $data ) {
|
136 |
+
/** @var ScanQueue\Update $updater */
|
137 |
+
$updater = $this->getDbHandler()->getQueryUpdater();
|
138 |
+
$entry = array_shift( $data );
|
139 |
+
$updater->updateById( $entry->id, $entry->getRawData() );
|
140 |
return $this;
|
141 |
}
|
142 |
|
143 |
public function handleExpiredItems() {
|
144 |
+
$boundary = Services::Request()
|
145 |
+
->carbon()
|
146 |
+
->subSeconds( $this->getExpirationInterval() )->timestamp;
|
147 |
+
$this->getDbHandler()->deleteRowsOlderThan( $boundary );
|
148 |
}
|
149 |
|
150 |
/**
|
src/lib/src/Modules/HackGuard/Scan/Results/ResultsUpdate.php
CHANGED
@@ -39,7 +39,7 @@ class ResultsUpdate {
|
|
39 |
$oConverter = ( new ConvertBetweenTypes() )->setScanController( $oSCon );
|
40 |
foreach ( $oConverter->fromResultsToVOs( $oExisting ) as $oVo ) {
|
41 |
$oUp->reset()
|
42 |
-
->setUpdateData( $oVo->
|
43 |
->setUpdateWheres(
|
44 |
[
|
45 |
'scan' => $oSCon->getSlug(),
|
39 |
$oConverter = ( new ConvertBetweenTypes() )->setScanController( $oSCon );
|
40 |
foreach ( $oConverter->fromResultsToVOs( $oExisting ) as $oVo ) {
|
41 |
$oUp->reset()
|
42 |
+
->setUpdateData( $oVo->getRawData() )
|
43 |
->setUpdateWheres(
|
44 |
[
|
45 |
'scan' => $oSCon->getSlug(),
|
src/lib/src/Modules/HackGuard/Scan/ScansController.php
CHANGED
@@ -120,18 +120,18 @@ class ScansController {
|
|
120 |
$opts = $this->getOptions();
|
121 |
|
122 |
if ( $this->getCanScansExecute() ) {
|
123 |
-
$
|
124 |
-
foreach ( $opts->getScanSlugs() as $
|
125 |
-
$
|
126 |
-
if ( $
|
127 |
-
$
|
128 |
}
|
129 |
}
|
130 |
|
131 |
$opts->setIsScanCron( true );
|
132 |
$mod->saveModOptions()
|
133 |
->getScanQueueController()
|
134 |
-
->startScans( $
|
135 |
}
|
136 |
else {
|
137 |
error_log( 'Shield scans cannot execute.' );
|
@@ -142,9 +142,15 @@ class ScansController {
|
|
142 |
* @return string[]
|
143 |
*/
|
144 |
public function getReasonsScansCantExecute() :array {
|
145 |
-
|
146 |
-
|
147 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
148 |
}
|
149 |
|
150 |
public function getCanScansExecute() :bool {
|
@@ -158,22 +164,30 @@ class ScansController {
|
|
158 |
}
|
159 |
|
160 |
public function getFirstRunTimestamp() :int {
|
161 |
-
$c = Services::Request()->carbon( true );
|
162 |
-
$c->addHours( $c->minute < 40 ? 0 : 1 )
|
163 |
-
->minute( $c->minute < 40 ? 45 : 15 )
|
164 |
-
->second( 0 );
|
165 |
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
173 |
}
|
174 |
-
$c->hour( $hour );
|
175 |
}
|
176 |
|
|
|
|
|
|
|
|
|
177 |
return $c->timestamp;
|
178 |
}
|
179 |
|
120 |
$opts = $this->getOptions();
|
121 |
|
122 |
if ( $this->getCanScansExecute() ) {
|
123 |
+
$scans = [];
|
124 |
+
foreach ( $opts->getScanSlugs() as $slug ) {
|
125 |
+
$scanCon = $mod->getScanCon( $slug );
|
126 |
+
if ( $scanCon->isScanningAvailable() && $scanCon->isEnabled() ) {
|
127 |
+
$scans[] = $slug;
|
128 |
}
|
129 |
}
|
130 |
|
131 |
$opts->setIsScanCron( true );
|
132 |
$mod->saveModOptions()
|
133 |
->getScanQueueController()
|
134 |
+
->startScans( $scans );
|
135 |
}
|
136 |
else {
|
137 |
error_log( 'Shield scans cannot execute.' );
|
142 |
* @return string[]
|
143 |
*/
|
144 |
public function getReasonsScansCantExecute() :array {
|
145 |
+
try {
|
146 |
+
$reasons = array_keys( array_filter( [
|
147 |
+
'reason_not_call_self' => !$this->getCon()->getModule_Plugin()->canSiteLoopback()
|
148 |
+
] ) );
|
149 |
+
}
|
150 |
+
catch ( \Exception $e ) {
|
151 |
+
$reasons = [];
|
152 |
+
}
|
153 |
+
return $reasons;
|
154 |
}
|
155 |
|
156 |
public function getCanScansExecute() :bool {
|
164 |
}
|
165 |
|
166 |
public function getFirstRunTimestamp() :int {
|
|
|
|
|
|
|
|
|
167 |
|
168 |
+
$startHour = (int)apply_filters( 'shield/scan_cron_start_hour', 3 );
|
169 |
+
$startMinute = (int)apply_filters( 'shield/scan_cron_start_minute', (int)rand( 0, 59 ) );
|
170 |
+
if ( $startHour < 0 || $startHour > 23 ) {
|
171 |
+
$startHour = 3;
|
172 |
+
}
|
173 |
+
if ( $startMinute < 1 || $startMinute > 59 ) {
|
174 |
+
$startMinute = (int)rand( 0, 59 );
|
175 |
+
}
|
176 |
+
|
177 |
+
$c = Services::Request()->carbon( true );
|
178 |
+
if ( $c->hour > $startHour ) {
|
179 |
+
$c->addDays( 1 ); // Start on this hour, tomorrow
|
180 |
+
}
|
181 |
+
elseif ( $c->hour === $startHour ) {
|
182 |
+
if ( $c->minute >= $startMinute ) {
|
183 |
+
$c->addDays( 1 ); // Start on this minute, tomorrow
|
184 |
}
|
|
|
185 |
}
|
186 |
|
187 |
+
$c->hour( $startHour )
|
188 |
+
->minute( $startMinute )
|
189 |
+
->second( 0 );
|
190 |
+
|
191 |
return $c->timestamp;
|
192 |
}
|
193 |
|
src/lib/src/Modules/HackGuard/Scan/Utilities/WpvAddPluginRows.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Scan\Utilities;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Logic\
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Scan\Controller;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Scans\Wpv;
|
8 |
use FernleafSystems\Wordpress\Services\Services;
|
@@ -10,7 +10,7 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
10 |
class WpvAddPluginRows {
|
11 |
|
12 |
use Controller\ScanControllerConsumer;
|
13 |
-
use
|
14 |
|
15 |
/**
|
16 |
* @var int
|
@@ -26,7 +26,7 @@ class WpvAddPluginRows {
|
|
26 |
$this->addPluginVulnerabilityRows();
|
27 |
}
|
28 |
|
29 |
-
protected function canRun() {
|
30 |
return $this->isWpvulnPluginsHighlightEnabled() && $this->countVulnerablePlugins() > 0;
|
31 |
}
|
32 |
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Scan\Utilities;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Logic\ExecOnce;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Scan\Controller;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Scans\Wpv;
|
8 |
use FernleafSystems\Wordpress\Services\Services;
|
10 |
class WpvAddPluginRows {
|
11 |
|
12 |
use Controller\ScanControllerConsumer;
|
13 |
+
use ExecOnce;
|
14 |
|
15 |
/**
|
16 |
* @var int
|
26 |
$this->addPluginVulnerabilityRows();
|
27 |
}
|
28 |
|
29 |
+
protected function canRun() :bool {
|
30 |
return $this->isWpvulnPluginsHighlightEnabled() && $this->countVulnerablePlugins() > 0;
|
31 |
}
|
32 |
|
src/lib/src/Modules/HackGuard/Strings.php
CHANGED
@@ -265,16 +265,18 @@ class Strings extends Base\Strings {
|
|
265 |
$summary = __( 'Lock Files Against Tampering And Changes', 'wp-simple-firewall' );
|
266 |
$desc = [
|
267 |
__( 'Detects changes to the files, then lets you examine contents and revert as required.', 'wp-simple-firewall' ),
|
268 |
-
sprintf( '%s: %s', __( 'Note', 'wp-simple-firewall' ), __( 'Web.Config is only available for Windows/IIS.', 'wp-simple-firewall' ) )
|
|
|
|
|
269 |
];
|
270 |
|
271 |
-
$
|
272 |
->setMod( $this->getMod() )
|
273 |
->loadLocks();
|
274 |
-
if ( !empty( $
|
275 |
$desc[] = __( 'Locked Files', 'wp-simple-firewall' ).':';
|
276 |
-
foreach ( $
|
277 |
-
$desc[] = sprintf( '<code>%s</code>', $
|
278 |
}
|
279 |
}
|
280 |
break;
|
@@ -289,7 +291,7 @@ class Strings extends Base\Strings {
|
|
289 |
$name = __( 'Scan Uploads', 'wp-simple-firewall' );
|
290 |
$summary = __( 'Scan Uploads Folder For PHP and Javascript', 'wp-simple-firewall' );
|
291 |
$desc = sprintf( '%s - %s', __( 'Warning', 'wp-simple-firewall' ), __( 'Take care when turning on this option - if you are unsure, leave it disabled.', 'wp-simple-firewall' ) )
|
292 |
-
|
293 |
break;
|
294 |
|
295 |
case 'ufc_exclusions' :
|
@@ -297,8 +299,8 @@ class Strings extends Base\Strings {
|
|
297 |
$summary = __( 'Provide A List Of Files To Be Excluded From The Scan', 'wp-simple-firewall' );
|
298 |
$sDefaults = implode( ', ', $this->getOptions()->getOptDefault( 'ufc_exclusions' ) );
|
299 |
$desc = __( 'Take a new line for each file you wish to exclude from the scan.', 'wp-simple-firewall' )
|
300 |
-
|
301 |
-
|
302 |
break;
|
303 |
|
304 |
case 'ic_enabled' :
|
@@ -311,16 +313,16 @@ class Strings extends Base\Strings {
|
|
311 |
$name = __( 'Monitor User Accounts', 'wp-simple-firewall' );
|
312 |
$summary = __( 'Scans For Critical Changes Made To User Accounts', 'wp-simple-firewall' );
|
313 |
$desc = sprintf( __( 'Detects changes made to critical user account information that were made directly on the database and outside of the WordPress system.', 'wp-simple-firewall' ), 'author=' )
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
break;
|
318 |
|
319 |
case 'ptg_depth' : /* DELETED */
|
320 |
$name = __( 'Guard/Scan Depth', 'wp-simple-firewall' );
|
321 |
$summary = __( 'How Deep Into The Plugin Directories To Scan And Guard', 'wp-simple-firewall' );
|
322 |
$desc = __( 'The Guard normally scans only the top level of a folder. Increasing depth will increase scan times.', 'wp-simple-firewall' )
|
323 |
-
|
324 |
break;
|
325 |
|
326 |
case 'ptg_reinstall_links' :
|
@@ -351,8 +353,8 @@ class Strings extends Base\Strings {
|
|
351 |
$name = __( 'Surgical Auto-Repair', 'wp-simple-firewall' );
|
352 |
$summary = __( 'Automatically Attempt To Surgically Remove Malware Code', 'wp-simple-firewall' );
|
353 |
$desc = __( "Attempts to automatically remove code from infected files.", 'wp-simple-firewall' )
|
354 |
-
|
355 |
-
|
356 |
break;
|
357 |
|
358 |
// REMOVED:
|
@@ -360,15 +362,15 @@ class Strings extends Base\Strings {
|
|
360 |
$name = __( 'Auto-Repair WP Plugins', 'wp-simple-firewall' );
|
361 |
$summary = __( 'Automatically Repair WordPress.org Plugins', 'wp-simple-firewall' );
|
362 |
$desc = __( "Automatically repair any plugin files found to have potential malware.", 'wp-simple-firewall' )
|
363 |
-
|
364 |
-
|
365 |
break;
|
366 |
case 'autorepair_themes' :
|
367 |
$name = __( 'Auto-Repair WP Themes', 'wp-simple-firewall' );
|
368 |
$summary = __( 'Automatically Repair WordPress.org Themes', 'wp-simple-firewall' );
|
369 |
$desc = __( "Automatically repair any theme files found to have potential malware.", 'wp-simple-firewall' )
|
370 |
-
|
371 |
-
|
372 |
break;
|
373 |
case 'wpvuln_scan_display' :
|
374 |
$name = __( 'Highlight Plugins', 'wp-simple-firewall' );
|
@@ -384,31 +386,31 @@ class Strings extends Base\Strings {
|
|
384 |
$name = __( 'Ignore False Positives Threshold', 'wp-simple-firewall' );
|
385 |
$summary = __( 'Ignore False Positives In Scan Results Automatically', 'wp-simple-firewall' );
|
386 |
$desc = __( "You can choose to ignore files with potential malware, depending on whether the confidence that it's a 'false positive' meets your minimum threshold.", 'wp-simple-firewall' )
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
break;
|
399 |
case 'notification_interval' :
|
400 |
$name = __( 'Repeat Notifications', 'wp-simple-firewall' );
|
401 |
$summary = __( 'Item Repeat Notifications Suppression Interval', 'wp-simple-firewall' );
|
402 |
$desc = __( 'How long the automated scans should wait before repeating a notification about an item.', 'wp-simple-firewall' )
|
403 |
-
|
404 |
-
|
405 |
break;
|
406 |
case 'ptg_extensions' :
|
407 |
$name = __( 'Included File Types', 'wp-simple-firewall' );
|
408 |
$summary = __( 'The File Types (by File Extension) Included In The Scan', 'wp-simple-firewall' );
|
409 |
$desc = __( 'Take a new line for each file extension.', 'wp-simple-firewall' )
|
410 |
-
|
411 |
-
|
412 |
break;
|
413 |
default:
|
414 |
return parent::getOptionStrings( $key );
|
265 |
$summary = __( 'Lock Files Against Tampering And Changes', 'wp-simple-firewall' );
|
266 |
$desc = [
|
267 |
__( 'Detects changes to the files, then lets you examine contents and revert as required.', 'wp-simple-firewall' ),
|
268 |
+
sprintf( '%s: %s', __( 'Note', 'wp-simple-firewall' ), __( 'Web.Config is only available for Windows/IIS.', 'wp-simple-firewall' ) ),
|
269 |
+
sprintf( '%s: %s', __( 'Important', 'wp-simple-firewall' ), __( 'After saving, it may take up to 60 seconds before a new lock is stored.', 'wp-simple-firewall' ) )
|
270 |
+
.' '.__( "It will be displayed below when it's ready.", 'wp-simple-firewall' )
|
271 |
];
|
272 |
|
273 |
+
$locks = ( new LoadFileLocks() )
|
274 |
->setMod( $this->getMod() )
|
275 |
->loadLocks();
|
276 |
+
if ( !empty( $locks ) ) {
|
277 |
$desc[] = __( 'Locked Files', 'wp-simple-firewall' ).':';
|
278 |
+
foreach ( $locks as $lock ) {
|
279 |
+
$desc[] = sprintf( '<code>%s</code>', $lock->file );
|
280 |
}
|
281 |
}
|
282 |
break;
|
291 |
$name = __( 'Scan Uploads', 'wp-simple-firewall' );
|
292 |
$summary = __( 'Scan Uploads Folder For PHP and Javascript', 'wp-simple-firewall' );
|
293 |
$desc = sprintf( '%s - %s', __( 'Warning', 'wp-simple-firewall' ), __( 'Take care when turning on this option - if you are unsure, leave it disabled.', 'wp-simple-firewall' ) )
|
294 |
+
.'<br />'.__( 'The Uploads folder is primarily for media, but could be used to store nefarious files.', 'wp-simple-firewall' );
|
295 |
break;
|
296 |
|
297 |
case 'ufc_exclusions' :
|
299 |
$summary = __( 'Provide A List Of Files To Be Excluded From The Scan', 'wp-simple-firewall' );
|
300 |
$sDefaults = implode( ', ', $this->getOptions()->getOptDefault( 'ufc_exclusions' ) );
|
301 |
$desc = __( 'Take a new line for each file you wish to exclude from the scan.', 'wp-simple-firewall' )
|
302 |
+
.'<br/><strong>'.__( 'No commas are necessary.', 'wp-simple-firewall' ).'</strong>'
|
303 |
+
.'<br/>'.sprintf( '%s: %s', __( 'Default', 'wp-simple-firewall' ), $sDefaults );
|
304 |
break;
|
305 |
|
306 |
case 'ic_enabled' :
|
313 |
$name = __( 'Monitor User Accounts', 'wp-simple-firewall' );
|
314 |
$summary = __( 'Scans For Critical Changes Made To User Accounts', 'wp-simple-firewall' );
|
315 |
$desc = sprintf( __( 'Detects changes made to critical user account information that were made directly on the database and outside of the WordPress system.', 'wp-simple-firewall' ), 'author=' )
|
316 |
+
.'<br />'.__( 'An example of this might be some form of SQL Injection attack.', 'wp-simple-firewall' )
|
317 |
+
.'<br />'.sprintf( '%s: %s', __( 'Warning', 'wp-simple-firewall' ), __( 'Enabling this option for every page low may slow down your site with large numbers of users.', 'wp-simple-firewall' ) )
|
318 |
+
.'<br />'.sprintf( '%s: %s', __( 'Warning', 'wp-simple-firewall' ), __( 'This option may cause critical problem with 3rd party plugins that manage user accounts.', 'wp-simple-firewall' ) );
|
319 |
break;
|
320 |
|
321 |
case 'ptg_depth' : /* DELETED */
|
322 |
$name = __( 'Guard/Scan Depth', 'wp-simple-firewall' );
|
323 |
$summary = __( 'How Deep Into The Plugin Directories To Scan And Guard', 'wp-simple-firewall' );
|
324 |
$desc = __( 'The Guard normally scans only the top level of a folder. Increasing depth will increase scan times.', 'wp-simple-firewall' )
|
325 |
+
.'<br/>'.sprintf( __( 'Setting it to %s will remove this limit and all sub-folders will be scanned - not recommended', 'wp-simple-firewall' ), 0 );
|
326 |
break;
|
327 |
|
328 |
case 'ptg_reinstall_links' :
|
353 |
$name = __( 'Surgical Auto-Repair', 'wp-simple-firewall' );
|
354 |
$summary = __( 'Automatically Attempt To Surgically Remove Malware Code', 'wp-simple-firewall' );
|
355 |
$desc = __( "Attempts to automatically remove code from infected files.", 'wp-simple-firewall' )
|
356 |
+
.'<br />'.sprintf( '%s: %s', __( 'Warning', 'wp-simple-firewall' ), __( 'This could break your site if code removal leaves remaining code in an inconsistent state.', 'wp-simple-firewall' ) )
|
357 |
+
.'<br />'.sprintf( '%s: %s', __( 'Important', 'wp-simple-firewall' ), __( "Only applies to files that don't fall under the other categories for automatic repair.", 'wp-simple-firewall' ) );
|
358 |
break;
|
359 |
|
360 |
// REMOVED:
|
362 |
$name = __( 'Auto-Repair WP Plugins', 'wp-simple-firewall' );
|
363 |
$summary = __( 'Automatically Repair WordPress.org Plugins', 'wp-simple-firewall' );
|
364 |
$desc = __( "Automatically repair any plugin files found to have potential malware.", 'wp-simple-firewall' )
|
365 |
+
.'<br />'.sprintf( '%s: %s', __( 'Important', 'wp-simple-firewall' ), __( 'Only compatible with plugins installed from WordPress.org.', 'wp-simple-firewall' ) )
|
366 |
+
.'<br />'.sprintf( '%s: %s', __( 'Important', 'wp-simple-firewall' ), __( "Also deletes suspected files if they weren't originally distributed with the plugin.", 'wp-simple-firewall' ) );
|
367 |
break;
|
368 |
case 'autorepair_themes' :
|
369 |
$name = __( 'Auto-Repair WP Themes', 'wp-simple-firewall' );
|
370 |
$summary = __( 'Automatically Repair WordPress.org Themes', 'wp-simple-firewall' );
|
371 |
$desc = __( "Automatically repair any theme files found to have potential malware.", 'wp-simple-firewall' )
|
372 |
+
.'<br />'.sprintf( '%s: %s', __( 'Important', 'wp-simple-firewall' ), __( 'Only compatible with themes installed from WordPress.org.', 'wp-simple-firewall' ) )
|
373 |
+
.'<br />'.sprintf( '%s: %s', __( 'Important', 'wp-simple-firewall' ), __( "Also deletes suspected files if they weren't originally distributed with the theme.", 'wp-simple-firewall' ) );
|
374 |
break;
|
375 |
case 'wpvuln_scan_display' :
|
376 |
$name = __( 'Highlight Plugins', 'wp-simple-firewall' );
|
386 |
$name = __( 'Ignore False Positives Threshold', 'wp-simple-firewall' );
|
387 |
$summary = __( 'Ignore False Positives In Scan Results Automatically', 'wp-simple-firewall' );
|
388 |
$desc = __( "You can choose to ignore files with potential malware, depending on whether the confidence that it's a 'false positive' meets your minimum threshold.", 'wp-simple-firewall' )
|
389 |
+
.'<br />'.__( "A false positive happens when a file appears to contain malware and shows up in scan results, but it's actually clean.", 'wp-simple-firewall' )
|
390 |
+
.' ('.__( "A false positive is similar to when an anti-virus alerts to a file that doesnt have a virus.", 'wp-simple-firewall' ).')'
|
391 |
+
.'<br />'.__( "The higher the confidence level, the more likely a result is a false positive.", 'wp-simple-firewall' )
|
392 |
+
.' '.__( "A low level means it's less likely to be a false positive.", 'wp-simple-firewall' )
|
393 |
+
.'<br />'.__( "The scan will automatically ignore results whose 'false positive' confidence level is greater than your chosen threshold.", 'wp-simple-firewall' )
|
394 |
+
.'<br />'.__( "The higher the confidence threshold you select, the more likely that 'false positives' will appears in your scan results.", 'wp-simple-firewall' )
|
395 |
+
.'<br />'.__( "Disabling network intelligence turns off 'false positive confidence' levels.", 'wp-simple-firewall' )
|
396 |
+
.' '.__( 'You will no longer benefit from the intelligence gathered from the entire network.', 'wp-simple-firewall' )
|
397 |
+
.' '.__( 'All data shared is completely anonymous.', 'wp-simple-firewall' )
|
398 |
+
.' '.' [<a href="https://shsec.io/moreinfomalnetwork">'.__( 'More Info', 'wp-simple-firewall' ).'</a>]'
|
399 |
+
.'<br />'.__( 'The more sites that share this information, the stronger and smarter the network becomes.', 'wp-simple-firewall' );
|
400 |
break;
|
401 |
case 'notification_interval' :
|
402 |
$name = __( 'Repeat Notifications', 'wp-simple-firewall' );
|
403 |
$summary = __( 'Item Repeat Notifications Suppression Interval', 'wp-simple-firewall' );
|
404 |
$desc = __( 'How long the automated scans should wait before repeating a notification about an item.', 'wp-simple-firewall' )
|
405 |
+
.'<br/>'.__( 'Specify the number of days to suppress repeat notifications.', 'wp-simple-firewall' )
|
406 |
+
.'<br/>'.sprintf( '%s: %s', __( 'Note', 'wp-simple-firewall' ), __( 'This is per discovered item or file, not per scan.', 'wp-simple-firewall' ) );
|
407 |
break;
|
408 |
case 'ptg_extensions' :
|
409 |
$name = __( 'Included File Types', 'wp-simple-firewall' );
|
410 |
$summary = __( 'The File Types (by File Extension) Included In The Scan', 'wp-simple-firewall' );
|
411 |
$desc = __( 'Take a new line for each file extension.', 'wp-simple-firewall' )
|
412 |
+
.'<br/>'.__( 'No commas(,) or periods(.) necessary.', 'wp-simple-firewall' )
|
413 |
+
.'<br/>'.__( 'Remove all extensions to scan all file type (not recommended).', 'wp-simple-firewall' );
|
414 |
break;
|
415 |
default:
|
416 |
return parent::getOptionStrings( $key );
|
src/lib/src/Modules/HackGuard/UI.php
CHANGED
@@ -20,7 +20,7 @@ class UI extends BaseShield\UI {
|
|
20 |
}
|
21 |
|
22 |
// Can Scan Checks:
|
23 |
-
$
|
24 |
|
25 |
/** @var \FernleafSystems\Wordpress\Plugin\Shield\Databases\Scanner\Select $oSelector */
|
26 |
$oSelector = $mod->getDbHandler_ScanResults()->getQuerySelector();
|
@@ -39,7 +39,7 @@ class UI extends BaseShield\UI {
|
|
39 |
],
|
40 |
'flags' => [
|
41 |
'is_premium' => $this->getCon()->isPremiumActive(),
|
42 |
-
'can_scan' => count( $
|
43 |
],
|
44 |
'strings' => [
|
45 |
'never' => __( 'Never', 'wp-simple-firewall' ),
|
@@ -68,7 +68,7 @@ class UI extends BaseShield\UI {
|
|
68 |
],
|
69 |
'vars' => [
|
70 |
'initial_check' => $mod->getScanQueueController()->hasRunningScans(),
|
71 |
-
'cannot_scan_reasons' => $
|
72 |
'related_hrefs' => [
|
73 |
[
|
74 |
'href' => $this->getCon()->getModule_HackGuard()->getUrl_AdminPage(),
|
20 |
}
|
21 |
|
22 |
// Can Scan Checks:
|
23 |
+
$reasonsCantScan = $mod->getScansCon()->getReasonsScansCantExecute();
|
24 |
|
25 |
/** @var \FernleafSystems\Wordpress\Plugin\Shield\Databases\Scanner\Select $oSelector */
|
26 |
$oSelector = $mod->getDbHandler_ScanResults()->getQuerySelector();
|
39 |
],
|
40 |
'flags' => [
|
41 |
'is_premium' => $this->getCon()->isPremiumActive(),
|
42 |
+
'can_scan' => count( $reasonsCantScan ) === 0,
|
43 |
],
|
44 |
'strings' => [
|
45 |
'never' => __( 'Never', 'wp-simple-firewall' ),
|
68 |
],
|
69 |
'vars' => [
|
70 |
'initial_check' => $mod->getScanQueueController()->hasRunningScans(),
|
71 |
+
'cannot_scan_reasons' => $reasonsCantScan,
|
72 |
'related_hrefs' => [
|
73 |
[
|
74 |
'href' => $this->getCon()->getModule_HackGuard()->getUrl_AdminPage(),
|
src/lib/src/Modules/Headers/ModCon.php
CHANGED
@@ -3,12 +3,10 @@
|
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Headers;
|
4 |
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
|
6 |
-
use FernleafSystems\Wordpress\Services\Services;
|
7 |
|
8 |
class ModCon extends BaseShield\ModCon {
|
9 |
|
10 |
protected function preProcessOptions() {
|
11 |
-
$this->cleanCspHosts();
|
12 |
$this->cleanCustomRules();
|
13 |
}
|
14 |
|
@@ -16,75 +14,20 @@ class ModCon extends BaseShield\ModCon {
|
|
16 |
/** @var Options $opts */
|
17 |
$opts = $this->getOptions();
|
18 |
$opts->setOpt( 'xcsp_custom', array_unique( array_filter( array_map(
|
19 |
-
function ( $
|
20 |
-
$
|
21 |
-
if ( !empty( $
|
22 |
-
$
|
23 |
}
|
24 |
-
return $
|
25 |
},
|
26 |
$opts->getOpt( 'xcsp_custom', [] )
|
27 |
) ) ) );
|
28 |
}
|
29 |
|
|
|
|
|
|
|
30 |
private function cleanCspHosts() {
|
31 |
-
/** @var Options $opts */
|
32 |
-
$opts = $this->getOptions();
|
33 |
-
|
34 |
-
$aValidDomains = [];
|
35 |
-
foreach ( $opts->getOpt( 'xcsp_hosts', [] ) as $sDomain ) {
|
36 |
-
$bValidDomain = false;
|
37 |
-
$sDomain = trim( $sDomain );
|
38 |
-
|
39 |
-
$bHttps = ( strpos( $sDomain, 'https://' ) === 0 );
|
40 |
-
$bHttp = ( strpos( $sDomain, 'http://' ) === 0 );
|
41 |
-
if ( $bHttp || $bHttps ) {
|
42 |
-
$sDomain = preg_replace( '#^http(s)?://#', '', $sDomain );
|
43 |
-
}
|
44 |
-
|
45 |
-
$sCustomProtocol = '';
|
46 |
-
// Special wildcard case
|
47 |
-
if ( $sDomain == '*' ) {
|
48 |
-
if ( $bHttps ) {
|
49 |
-
$this->getOptions()->setOpt( 'xcsp_https', 'Y' );
|
50 |
-
}
|
51 |
-
else {
|
52 |
-
$bValidDomain = true;
|
53 |
-
}
|
54 |
-
}
|
55 |
-
elseif ( strpos( $sDomain, '://' ) && preg_match( '#^([a-zA-Z]+://)#', $sDomain, $aMatches ) ) {
|
56 |
-
// there's a protocol specified
|
57 |
-
$sCustomProtocol = $aMatches[ 1 ];
|
58 |
-
$sDomain = str_replace( $sCustomProtocol, '', $sDomain );
|
59 |
-
}
|
60 |
-
|
61 |
-
// First we remove the wildcard and test domain, then add it back later.
|
62 |
-
$bWildCard = ( strpos( $sDomain, '*.' ) === 0 );
|
63 |
-
if ( $bWildCard ) {
|
64 |
-
$sDomain = preg_replace( '#^\*\.#', '', $sDomain );
|
65 |
-
}
|
66 |
-
|
67 |
-
if ( !empty ( $sDomain ) && Services::Data()->isValidDomainName( $sDomain ) ) {
|
68 |
-
$bValidDomain = true;
|
69 |
-
}
|
70 |
-
|
71 |
-
if ( $bValidDomain ) {
|
72 |
-
if ( $bWildCard ) {
|
73 |
-
$sDomain = '*.'.$sDomain;
|
74 |
-
}
|
75 |
-
if ( $bHttp ) {
|
76 |
-
// $sDomain = 'http://'.$sDomain; // it seems there's no need to "explicitly" state http://
|
77 |
-
}
|
78 |
-
elseif ( $bHttps ) {
|
79 |
-
$sDomain = 'https://'.$sDomain;
|
80 |
-
}
|
81 |
-
elseif ( !empty( $sCustomProtocol ) ) {
|
82 |
-
$sDomain = $sCustomProtocol.$sDomain;
|
83 |
-
}
|
84 |
-
$aValidDomains[] = $sDomain;
|
85 |
-
}
|
86 |
-
}
|
87 |
-
asort( $aValidDomains );
|
88 |
-
$opts->setOpt( 'xcsp_hosts', array_unique( $aValidDomains ) );
|
89 |
}
|
90 |
}
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Headers;
|
4 |
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
|
|
|
6 |
|
7 |
class ModCon extends BaseShield\ModCon {
|
8 |
|
9 |
protected function preProcessOptions() {
|
|
|
10 |
$this->cleanCustomRules();
|
11 |
}
|
12 |
|
14 |
/** @var Options $opts */
|
15 |
$opts = $this->getOptions();
|
16 |
$opts->setOpt( 'xcsp_custom', array_unique( array_filter( array_map(
|
17 |
+
function ( $rule ) {
|
18 |
+
$rule = trim( preg_replace( '#;|\s{2,}#', '', html_entity_decode( $rule, ENT_QUOTES ) ) );
|
19 |
+
if ( !empty( $rule ) ) {
|
20 |
+
$rule .= ';';
|
21 |
}
|
22 |
+
return $rule;
|
23 |
},
|
24 |
$opts->getOpt( 'xcsp_custom', [] )
|
25 |
) ) ) );
|
26 |
}
|
27 |
|
28 |
+
/**
|
29 |
+
* @deprecated 10.3
|
30 |
+
*/
|
31 |
private function cleanCspHosts() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
}
|
33 |
}
|
src/lib/src/Modules/Headers/Strings.php
CHANGED
@@ -101,46 +101,6 @@ class Strings extends Base\Strings {
|
|
101 |
$sDescription = __( 'Allows for permission and restriction of all resources loaded on your site.', 'wp-simple-firewall' );
|
102 |
break;
|
103 |
|
104 |
-
case 'xcsp_self' :
|
105 |
-
$sName = __( 'Self', 'wp-simple-firewall' );
|
106 |
-
$sSummary = __( "Allow 'self' Directive", 'wp-simple-firewall' );
|
107 |
-
$sDescription = __( "Using 'self' is generally recommended.", 'wp-simple-firewall' )
|
108 |
-
.__( "It essentially means that resources from your own host:protocol are permitted.", 'wp-simple-firewall' );
|
109 |
-
break;
|
110 |
-
|
111 |
-
case 'xcsp_inline' :
|
112 |
-
$sName = __( 'Inline Entities', 'wp-simple-firewall' );
|
113 |
-
$sSummary = __( 'Allow Inline Scripts and CSS', 'wp-simple-firewall' );
|
114 |
-
$sDescription = __( 'Allows parsing of Javascript and CSS declared in-line in your html document.', 'wp-simple-firewall' );
|
115 |
-
break;
|
116 |
-
|
117 |
-
case 'xcsp_data' :
|
118 |
-
$sName = __( 'Embedded Data', 'wp-simple-firewall' );
|
119 |
-
$sSummary = __( 'Allow "data:" Directives', 'wp-simple-firewall' );
|
120 |
-
$sDescription = __( 'Allows use of embedded data directives, most commonly used for images and fonts.', 'wp-simple-firewall' );
|
121 |
-
break;
|
122 |
-
|
123 |
-
case 'xcsp_eval' :
|
124 |
-
$sName = __( 'Allow eval()', 'wp-simple-firewall' );
|
125 |
-
$sSummary = __( 'Allow Javascript eval()', 'wp-simple-firewall' );
|
126 |
-
$sDescription = __( 'Permits the use of Javascript the eval() function.', 'wp-simple-firewall' );
|
127 |
-
break;
|
128 |
-
|
129 |
-
case 'xcsp_https' :
|
130 |
-
$sName = __( 'HTTPS', 'wp-simple-firewall' );
|
131 |
-
$sSummary = __( 'HTTPS Resource Loading', 'wp-simple-firewall' );
|
132 |
-
$sDescription = __( 'Allows loading of any content provided over HTTPS.', 'wp-simple-firewall' );
|
133 |
-
break;
|
134 |
-
|
135 |
-
case 'xcsp_hosts' :
|
136 |
-
$sName = __( 'Permitted Hosts', 'wp-simple-firewall' );
|
137 |
-
$sSummary = __( 'Permitted Hosts and Domains', 'wp-simple-firewall' );
|
138 |
-
$sDescription = __( 'You can explicitly state which hosts/domain from which content may be loaded.', 'wp-simple-firewall' )
|
139 |
-
.' '.__( 'Take great care and test your site as you may block legitimate resources.', 'wp-simple-firewall' )
|
140 |
-
.'<br />- '.__( 'If in-doubt, leave blank or use "*" only.', 'wp-simple-firewall' )
|
141 |
-
.'<br />- '.sprintf( '%s: %s', __( 'Note', 'wp-simple-firewall' ), __( 'You can force only HTTPS for a given domain by prefixing it with "https://".', 'wp-simple-firewall' ) );
|
142 |
-
break;
|
143 |
-
|
144 |
case 'xcsp_custom' :
|
145 |
$sName = __( 'Manual Rules', 'wp-simple-firewall' );
|
146 |
$sSummary = __( 'Manual CSP Rules', 'wp-simple-firewall' );
|
101 |
$sDescription = __( 'Allows for permission and restriction of all resources loaded on your site.', 'wp-simple-firewall' );
|
102 |
break;
|
103 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
104 |
case 'xcsp_custom' :
|
105 |
$sName = __( 'Manual Rules', 'wp-simple-firewall' );
|
106 |
$sSummary = __( 'Manual CSP Rules', 'wp-simple-firewall' );
|
src/lib/src/Modules/IPs/AjaxHandler.php
CHANGED
@@ -5,7 +5,7 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
|
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Ops;
|
7 |
use FernleafSystems\Wordpress\Services\Services;
|
8 |
-
use FernleafSystems\Wordpress\Services\Utilities\Net\
|
9 |
|
10 |
class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
|
11 |
|
@@ -32,6 +32,10 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
|
|
32 |
$response = $this->ajaxExec_IpAnalyseAction();
|
33 |
break;
|
34 |
|
|
|
|
|
|
|
|
|
35 |
default:
|
36 |
$response = parent::processAjaxAction( $action );
|
37 |
}
|
@@ -39,6 +43,29 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
|
|
39 |
return $response;
|
40 |
}
|
41 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
private function ajaxExec_AddIp() :array {
|
43 |
/** @var ModCon $mod */
|
44 |
$mod = $this->getMod();
|
@@ -46,8 +73,8 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
|
|
46 |
|
47 |
$aFormParams = $this->getAjaxFormParams();
|
48 |
|
49 |
-
$
|
50 |
-
$
|
51 |
|
52 |
$ip = preg_replace( '#[^/:.a-f\d]#i', '', ( isset( $aFormParams[ 'ip' ] ) ? $aFormParams[ 'ip' ] : '' ) );
|
53 |
$sList = isset( $aFormParams[ 'list' ] ) ? $aFormParams[ 'list' ] : '';
|
@@ -60,22 +87,22 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
|
|
60 |
|
61 |
// TODO: Bring this IP verification out of here and make it more accessible
|
62 |
if ( empty( $ip ) ) {
|
63 |
-
$
|
64 |
}
|
65 |
elseif ( empty( $sList ) ) {
|
66 |
-
$
|
67 |
}
|
68 |
elseif ( !$bAcceptableIp ) {
|
69 |
-
$
|
70 |
}
|
71 |
elseif ( $bIsBlackList && !$mod->isPremium() ) {
|
72 |
-
$
|
73 |
}
|
74 |
elseif ( $bIsBlackList && $oIpServ->checkIp( $oIpServ->getRequestIp(), $ip ) ) {
|
75 |
-
$
|
76 |
}
|
77 |
elseif ( $bIsBlackList && in_array( $ip, Services::IP()->getServerPublicIPs() ) ) {
|
78 |
-
$
|
79 |
}
|
80 |
else {
|
81 |
$label = $aFormParams[ 'label' ] ?? '';
|
@@ -108,37 +135,45 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
|
|
108 |
}
|
109 |
|
110 |
if ( !empty( $oIP ) ) {
|
111 |
-
$
|
112 |
-
$
|
113 |
}
|
114 |
}
|
115 |
|
116 |
return [
|
117 |
-
'success' => $
|
118 |
-
'message' => $
|
119 |
];
|
120 |
}
|
121 |
|
122 |
private function ajaxExec_IpDelete() :array {
|
123 |
/** @var ModCon $mod */
|
124 |
$mod = $this->getMod();
|
125 |
-
$
|
126 |
-
$
|
127 |
|
128 |
-
if (
|
129 |
-
$
|
130 |
-
}
|
131 |
-
elseif ( $mod->getDbHandler_IPs()->getQueryDeleter()->deleteById( $nId ) ) {
|
132 |
-
$sMessage = __( 'IP address deleted', 'wp-simple-firewall' );
|
133 |
-
$bSuccess = true;
|
134 |
}
|
135 |
else {
|
136 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
137 |
}
|
138 |
|
139 |
return [
|
140 |
-
'success' => $
|
141 |
-
'message' => $
|
142 |
];
|
143 |
}
|
144 |
|
@@ -163,27 +198,25 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
|
|
163 |
|
164 |
$ip = $req->post( 'ip' );
|
165 |
|
166 |
-
$ipIdentifier = new IpIdentify( $ip );
|
167 |
try {
|
168 |
-
$
|
169 |
-
$ipKey = key( $ipID );
|
170 |
$validIP = true;
|
171 |
}
|
172 |
catch ( \Exception $e ) {
|
173 |
-
$ipKey =
|
|
|
174 |
$validIP = false;
|
175 |
}
|
176 |
|
177 |
$success = false;
|
178 |
|
179 |
-
if (
|
180 |
-
$msg = sprintf( __( "IP can't be processed from this page as it's a known service IP: %s" ), $ipIdentifier->getName( $ipKey ) );
|
181 |
-
}
|
182 |
-
elseif ( !$validIP ) {
|
183 |
$msg = __( "IP provided was invalid.", 'wp-simple-firewall' );
|
184 |
}
|
|
|
|
|
|
|
185 |
else {
|
186 |
-
$dbh = $this->getCon()->getModule_IPs()->getDbHandler_IPs();
|
187 |
switch ( $req->post( 'ip_action' ) ) {
|
188 |
|
189 |
case 'block':
|
@@ -201,7 +234,7 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
|
|
201 |
|
202 |
case 'unblock':
|
203 |
$success = ( new Ops\DeleteIp() )
|
204 |
-
->
|
205 |
->setIP( $ip )
|
206 |
->fromBlacklist();
|
207 |
$msg = $success ? __( 'IP address unblocked.', 'wp-simple-firewall' )
|
@@ -223,13 +256,22 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
|
|
223 |
|
224 |
case 'unbypass':
|
225 |
$success = ( new Ops\DeleteIp() )
|
226 |
-
->
|
227 |
->setIP( $ip )
|
228 |
->fromWhiteList();
|
229 |
$msg = $success ? __( 'IP address removed from Bypass list.', 'wp-simple-firewall' )
|
230 |
: __( "IP address couldn't be removed from Bypass list at this time.", 'wp-simple-firewall' );
|
231 |
break;
|
232 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
233 |
default:
|
234 |
$msg = __( 'Unsupported Action.', 'wp-simple-firewall' );
|
235 |
break;
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Ops;
|
7 |
use FernleafSystems\Wordpress\Services\Services;
|
8 |
+
use FernleafSystems\Wordpress\Services\Utilities\Net\IpID;
|
9 |
|
10 |
class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
|
11 |
|
32 |
$response = $this->ajaxExec_IpAnalyseAction();
|
33 |
break;
|
34 |
|
35 |
+
case 'not_bot':
|
36 |
+
$response = $this->ajaxExec_CaptureNotBot();
|
37 |
+
break;
|
38 |
+
|
39 |
default:
|
40 |
$response = parent::processAjaxAction( $action );
|
41 |
}
|
43 |
return $response;
|
44 |
}
|
45 |
|
46 |
+
protected function processNonAuthAjaxAction( string $action ) :array {
|
47 |
+
|
48 |
+
switch ( $action ) {
|
49 |
+
case 'not_bot':
|
50 |
+
$response = $this->ajaxExec_CaptureNotBot();
|
51 |
+
break;
|
52 |
+
default:
|
53 |
+
$response = parent::processNonAuthAjaxAction( $action );
|
54 |
+
}
|
55 |
+
|
56 |
+
return $response;
|
57 |
+
}
|
58 |
+
|
59 |
+
private function ajaxExec_CaptureNotBot() :array {
|
60 |
+
/** @var ModCon $mod */
|
61 |
+
$mod = $this->getMod();
|
62 |
+
return [
|
63 |
+
'success' => $mod->getBotSignalsController()
|
64 |
+
->getHandlerNotBot()
|
65 |
+
->registerAsNotBot()
|
66 |
+
];
|
67 |
+
}
|
68 |
+
|
69 |
private function ajaxExec_AddIp() :array {
|
70 |
/** @var ModCon $mod */
|
71 |
$mod = $this->getMod();
|
73 |
|
74 |
$aFormParams = $this->getAjaxFormParams();
|
75 |
|
76 |
+
$success = false;
|
77 |
+
$msg = __( "IP address wasn't added to the list", 'wp-simple-firewall' );
|
78 |
|
79 |
$ip = preg_replace( '#[^/:.a-f\d]#i', '', ( isset( $aFormParams[ 'ip' ] ) ? $aFormParams[ 'ip' ] : '' ) );
|
80 |
$sList = isset( $aFormParams[ 'list' ] ) ? $aFormParams[ 'list' ] : '';
|
87 |
|
88 |
// TODO: Bring this IP verification out of here and make it more accessible
|
89 |
if ( empty( $ip ) ) {
|
90 |
+
$msg = __( "IP address not provided", 'wp-simple-firewall' );
|
91 |
}
|
92 |
elseif ( empty( $sList ) ) {
|
93 |
+
$msg = __( "IP list not provided", 'wp-simple-firewall' );
|
94 |
}
|
95 |
elseif ( !$bAcceptableIp ) {
|
96 |
+
$msg = __( "IP address isn't either a valid IP or a CIDR range", 'wp-simple-firewall' );
|
97 |
}
|
98 |
elseif ( $bIsBlackList && !$mod->isPremium() ) {
|
99 |
+
$msg = __( "Please upgrade to Pro if you'd like to add IPs to the black list manually.", 'wp-simple-firewall' );
|
100 |
}
|
101 |
elseif ( $bIsBlackList && $oIpServ->checkIp( $oIpServ->getRequestIp(), $ip ) ) {
|
102 |
+
$msg = __( "Manually black listing your current IP address is not supported.", 'wp-simple-firewall' );
|
103 |
}
|
104 |
elseif ( $bIsBlackList && in_array( $ip, Services::IP()->getServerPublicIPs() ) ) {
|
105 |
+
$msg = __( "This IP is reserved and can't be blacklisted.", 'wp-simple-firewall' );
|
106 |
}
|
107 |
else {
|
108 |
$label = $aFormParams[ 'label' ] ?? '';
|
135 |
}
|
136 |
|
137 |
if ( !empty( $oIP ) ) {
|
138 |
+
$msg = __( 'IP address added successfully', 'wp-simple-firewall' );
|
139 |
+
$success = true;
|
140 |
}
|
141 |
}
|
142 |
|
143 |
return [
|
144 |
+
'success' => $success,
|
145 |
+
'message' => $msg,
|
146 |
];
|
147 |
}
|
148 |
|
149 |
private function ajaxExec_IpDelete() :array {
|
150 |
/** @var ModCon $mod */
|
151 |
$mod = $this->getMod();
|
152 |
+
$success = false;
|
153 |
+
$ID = (int)Services::Request()->post( 'rid', -1 );
|
154 |
|
155 |
+
if ( $ID < 0 ) {
|
156 |
+
$msg = __( 'Invalid entry selected', 'wp-simple-firewall' );
|
|
|
|
|
|
|
|
|
157 |
}
|
158 |
else {
|
159 |
+
/** @var Shield\Databases\IPs\EntryVO $IP */
|
160 |
+
$IP = $mod->getDbHandler_IPs()
|
161 |
+
->getQuerySelector()
|
162 |
+
->byId( $ID );
|
163 |
+
if ( $IP instanceof Shield\Databases\IPs\EntryVO ) {
|
164 |
+
$del = ( new Ops\DeleteIp() )
|
165 |
+
->setMod( $this->getMod() )
|
166 |
+
->setIP( $IP->ip );
|
167 |
+
$success = ( $IP->list == $mod::LIST_MANUAL_WHITE ) ?
|
168 |
+
$del->fromWhiteList() : $del->fromBlacklist();
|
169 |
+
}
|
170 |
+
$msg = $success ? __( 'IP address deleted', 'wp-simple-firewall' )
|
171 |
+
: __( "IP address wasn't deleted from the list", 'wp-simple-firewall' );
|
172 |
}
|
173 |
|
174 |
return [
|
175 |
+
'success' => $success,
|
176 |
+
'message' => $msg,
|
177 |
];
|
178 |
}
|
179 |
|
198 |
|
199 |
$ip = $req->post( 'ip' );
|
200 |
|
|
|
201 |
try {
|
202 |
+
list( $ipKey, $ipName ) = ( new IpID( $ip ) )->run();
|
|
|
203 |
$validIP = true;
|
204 |
}
|
205 |
catch ( \Exception $e ) {
|
206 |
+
$ipKey = IpID::UNKNOWN;
|
207 |
+
$ipName = 'Unknown';
|
208 |
$validIP = false;
|
209 |
}
|
210 |
|
211 |
$success = false;
|
212 |
|
213 |
+
if ( !$validIP ) {
|
|
|
|
|
|
|
214 |
$msg = __( "IP provided was invalid.", 'wp-simple-firewall' );
|
215 |
}
|
216 |
+
elseif ( !in_array( $ipKey, [ IpID::UNKNOWN, IpID::VISITOR ] ) ) {
|
217 |
+
$msg = sprintf( __( "IP can't be processed from this page as it's a known service IP: %s" ), $ipName );
|
218 |
+
}
|
219 |
else {
|
|
|
220 |
switch ( $req->post( 'ip_action' ) ) {
|
221 |
|
222 |
case 'block':
|
234 |
|
235 |
case 'unblock':
|
236 |
$success = ( new Ops\DeleteIp() )
|
237 |
+
->setMod( $this->getMod() )
|
238 |
->setIP( $ip )
|
239 |
->fromBlacklist();
|
240 |
$msg = $success ? __( 'IP address unblocked.', 'wp-simple-firewall' )
|
256 |
|
257 |
case 'unbypass':
|
258 |
$success = ( new Ops\DeleteIp() )
|
259 |
+
->setMod( $this->getMod() )
|
260 |
->setIP( $ip )
|
261 |
->fromWhiteList();
|
262 |
$msg = $success ? __( 'IP address removed from Bypass list.', 'wp-simple-firewall' )
|
263 |
: __( "IP address couldn't be removed from Bypass list at this time.", 'wp-simple-firewall' );
|
264 |
break;
|
265 |
|
266 |
+
case 'delete_notbot':
|
267 |
+
$success = ( new Lib\Bots\BotSignalsRecord() )
|
268 |
+
->setMod( $this->getMod() )
|
269 |
+
->setIP( $ip )
|
270 |
+
->delete();
|
271 |
+
$msg = $success ? __( 'IP NotBot Score Reset.', 'wp-simple-firewall' )
|
272 |
+
: __( "IP NotBot Score couldn't be reset at this time.", 'wp-simple-firewall' );
|
273 |
+
break;
|
274 |
+
|
275 |
default:
|
276 |
$msg = __( 'Unsupported Action.', 'wp-simple-firewall' );
|
277 |
break;
|
src/lib/src/Modules/IPs/BotTrack/Base.php
CHANGED
@@ -2,6 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\BotTrack;
|
4 |
|
|
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
|
7 |
use FernleafSystems\Wordpress\Services\Services;
|
@@ -9,10 +10,11 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
9 |
abstract class Base {
|
10 |
|
11 |
use Shield\Modules\ModConsumer;
|
|
|
12 |
|
13 |
const OPT_KEY = '';
|
14 |
|
15 |
-
|
16 |
$this->process();
|
17 |
}
|
18 |
|
@@ -20,15 +22,15 @@ abstract class Base {
|
|
20 |
/** @var IPs\Options $opts */
|
21 |
$opts = $this->getOptions();
|
22 |
|
23 |
-
$
|
24 |
-
if ( $
|
25 |
-
$
|
26 |
}
|
27 |
elseif ( $opts->isTrackOptTransgression( static::OPT_KEY ) ) {
|
28 |
-
$
|
29 |
}
|
30 |
else {
|
31 |
-
$
|
32 |
}
|
33 |
|
34 |
$this->getCon()
|
@@ -36,8 +38,8 @@ abstract class Base {
|
|
36 |
'bot'.static::OPT_KEY,
|
37 |
[
|
38 |
'audit' => $this->getAuditData(),
|
39 |
-
'offense_count' => $
|
40 |
-
'block' => $
|
41 |
]
|
42 |
);
|
43 |
}
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\BotTrack;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Logic\ExecOnce;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
|
8 |
use FernleafSystems\Wordpress\Services\Services;
|
10 |
abstract class Base {
|
11 |
|
12 |
use Shield\Modules\ModConsumer;
|
13 |
+
use ExecOnce;
|
14 |
|
15 |
const OPT_KEY = '';
|
16 |
|
17 |
+
protected function run() {
|
18 |
$this->process();
|
19 |
}
|
20 |
|
22 |
/** @var IPs\Options $opts */
|
23 |
$opts = $this->getOptions();
|
24 |
|
25 |
+
$block = $opts->isTrackOptImmediateBlock( static::OPT_KEY );
|
26 |
+
if ( $block ) {
|
27 |
+
$count = 1;
|
28 |
}
|
29 |
elseif ( $opts->isTrackOptTransgression( static::OPT_KEY ) ) {
|
30 |
+
$count = $opts->isTrackOptDoubleTransgression( static::OPT_KEY ) ? 2 : 1;
|
31 |
}
|
32 |
else {
|
33 |
+
$count = 0;
|
34 |
}
|
35 |
|
36 |
$this->getCon()
|
38 |
'bot'.static::OPT_KEY,
|
39 |
[
|
40 |
'audit' => $this->getAuditData(),
|
41 |
+
'offense_count' => $count,
|
42 |
+
'block' => $block,
|
43 |
]
|
44 |
);
|
45 |
}
|
src/lib/src/Modules/IPs/BotTrack/Track404.php
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\BotTrack;
|
4 |
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\BotTrack;
|
4 |
|
src/lib/src/Modules/IPs/BotTrack/TrackCommentSpam.php
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\BotTrack;
|
4 |
+
|
5 |
+
use FernleafSystems\Utilities\Logic\ExecOnce;
|
6 |
+
use FernleafSystems\Wordpress\Plugin\Shield;
|
7 |
+
|
8 |
+
class TrackCommentSpam {
|
9 |
+
|
10 |
+
use Shield\Modules\ModConsumer;
|
11 |
+
use ExecOnce;
|
12 |
+
|
13 |
+
protected function canRun() :bool {
|
14 |
+
return is_admin() || is_network_admin();
|
15 |
+
}
|
16 |
+
|
17 |
+
protected function run() {
|
18 |
+
add_action( 'spammed_comment', function ( $id ) {
|
19 |
+
$comment = get_comment( $id );
|
20 |
+
if ( $comment instanceof \WP_Comment && !empty( $comment->comment_author_IP ) ) {
|
21 |
+
/** @var Shield\Modules\IPs\ModCon $mod */
|
22 |
+
$mod = $this->getMod();
|
23 |
+
$mod->getBotSignalsController()
|
24 |
+
->getEventListener()
|
25 |
+
->fireEventForIP( $comment->comment_author_IP, 'comment_markspam' );
|
26 |
+
}
|
27 |
+
} );
|
28 |
+
|
29 |
+
add_action( 'unspammed_comment', function ( $id ) {
|
30 |
+
$comment = get_comment( $id );
|
31 |
+
if ( $comment instanceof \WP_Comment && !empty( $comment->comment_author_IP ) ) {
|
32 |
+
/** @var Shield\Modules\IPs\ModCon $mod */
|
33 |
+
$mod = $this->getMod();
|
34 |
+
$mod->getBotSignalsController()
|
35 |
+
->getEventListener()
|
36 |
+
->fireEventForIP( $comment->comment_author_IP, 'comment_unmarkspam' );
|
37 |
+
}
|
38 |
+
} );
|
39 |
+
}
|
40 |
+
}
|
src/lib/src/Modules/IPs/BotTrack/TrackFakeWebCrawler.php
CHANGED
@@ -1,7 +1,8 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\BotTrack;
|
4 |
|
|
|
5 |
use FernleafSystems\Wordpress\Services\Services;
|
6 |
|
7 |
/**
|
@@ -12,32 +13,36 @@ class TrackFakeWebCrawler extends Base {
|
|
12 |
|
13 |
const OPT_KEY = 'track_fakewebcrawler';
|
14 |
|
|
|
|
|
15 |
protected function process() {
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
catch ( \Exception $e ) {
|
20 |
$this->doTransgression();
|
21 |
}
|
22 |
}
|
23 |
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
foreach ( Services::ServiceProviders()->getAllCrawlerUseragents() as $sPossibleAgent ) {
|
34 |
-
if ( stripos( $sUserAgent, $sPossibleAgent ) !== false ) {
|
35 |
-
throw new \Exception( $sPossibleAgent );
|
36 |
break;
|
37 |
}
|
38 |
}
|
39 |
}
|
40 |
|
41 |
-
return $
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
}
|
43 |
}
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\BotTrack;
|
4 |
|
5 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\ModCon;
|
6 |
use FernleafSystems\Wordpress\Services\Services;
|
7 |
|
8 |
/**
|
13 |
|
14 |
const OPT_KEY = 'track_fakewebcrawler';
|
15 |
|
16 |
+
private $agentUsed = '';
|
17 |
+
|
18 |
protected function process() {
|
19 |
+
/** @var ModCon $mod */
|
20 |
+
$mod = $this->getMod();
|
21 |
+
if ( $this->identifiesAsCrawler() && !$mod->isVerifiedBot() ) {
|
|
|
22 |
$this->doTransgression();
|
23 |
}
|
24 |
}
|
25 |
|
26 |
+
private function identifiesAsCrawler() :bool {
|
27 |
+
$identifiesAsCrawler = false;
|
28 |
+
|
29 |
+
$userAgent = Services::Request()->getUserAgent();
|
30 |
+
if ( !empty( $userAgent ) ) {
|
31 |
+
foreach ( Services::ServiceProviders()->getAllCrawlerUseragents() as $possibleAgent ) {
|
32 |
+
if ( stripos( $userAgent, $possibleAgent ) !== false ) {
|
33 |
+
$identifiesAsCrawler = true;
|
34 |
+
$this->agentUsed = $possibleAgent;
|
|
|
|
|
|
|
35 |
break;
|
36 |
}
|
37 |
}
|
38 |
}
|
39 |
|
40 |
+
return $identifiesAsCrawler;
|
41 |
+
}
|
42 |
+
|
43 |
+
protected function getAuditData() :array {
|
44 |
+
return array_merge( parent::getAuditData(), [
|
45 |
+
'script' => $this->agentUsed
|
46 |
+
] );
|
47 |
}
|
48 |
}
|
src/lib/src/Modules/IPs/BotTrack/TrackInvalidScriptLoad.php
ADDED
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\BotTrack;
|
4 |
+
|
5 |
+
use FernleafSystems\Wordpress\Services\Services;
|
6 |
+
|
7 |
+
class TrackInvalidScriptLoad extends Base {
|
8 |
+
|
9 |
+
const OPT_KEY = 'track_invalidscript';
|
10 |
+
|
11 |
+
private $script = null;
|
12 |
+
|
13 |
+
protected function process() {
|
14 |
+
$this->testScript();
|
15 |
+
}
|
16 |
+
|
17 |
+
private function testScript() {
|
18 |
+
$req = Services::Request();
|
19 |
+
|
20 |
+
// For the moment we only handle the actual file name itself.
|
21 |
+
$scripts = array_unique( array_map( 'basename', array_filter( [
|
22 |
+
$req->server( 'SCRIPT_NAME' ),
|
23 |
+
$req->server( 'SCRIPT_FILENAME' ),
|
24 |
+
$req->server( 'PHP_SELF' )
|
25 |
+
] ) ) );
|
26 |
+
// There should only ever be 1. More than 1 means a strange configuration which we wont touch.
|
27 |
+
if ( count( $scripts ) === 1 ) {
|
28 |
+
$script = array_shift( $scripts );
|
29 |
+
if ( !in_array( $script, $this->getAllowedScripts() ) ) {
|
30 |
+
$this->script = $script;
|
31 |
+
$this->doTransgression();
|
32 |
+
}
|
33 |
+
}
|
34 |
+
}
|
35 |
+
|
36 |
+
protected function getAllowedScripts() :array {
|
37 |
+
return [
|
38 |
+
'index.php',
|
39 |
+
'admin-ajax.php',
|
40 |
+
'wp-activate.php',
|
41 |
+
'wp-links-opml.php',
|
42 |
+
'wp-cron.php',
|
43 |
+
'wp-login.php',
|
44 |
+
'wp-mail.php',
|
45 |
+
'wp-comments-post.php',
|
46 |
+
'wp-signup.php',
|
47 |
+
'wp-trackback.php',
|
48 |
+
'xmlrpc.php',
|
49 |
+
'admin.php',
|
50 |
+
];
|
51 |
+
}
|
52 |
+
|
53 |
+
protected function getAuditData() :array {
|
54 |
+
return [
|
55 |
+
'script' => $this->script
|
56 |
+
];
|
57 |
+
}
|
58 |
+
}
|
src/lib/src/Modules/IPs/BotTrack/TrackLinkCheese.php
CHANGED
@@ -13,11 +13,28 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
13 |
class TrackLinkCheese extends Base {
|
14 |
|
15 |
const OPT_KEY = 'track_linkcheese';
|
|
|
16 |
|
17 |
protected function process() {
|
18 |
add_filter( 'robots_txt', [ $this, 'appendRobotsTxt' ], 15 );
|
19 |
add_action( 'wp_footer', [ $this, 'insertMouseTrap' ], 0 );
|
20 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
$this->doTransgression();
|
22 |
}
|
23 |
}
|
@@ -26,69 +43,53 @@ class TrackLinkCheese extends Base {
|
|
26 |
* @param string $robotsText
|
27 |
* @return string
|
28 |
*/
|
29 |
-
public function appendRobotsTxt( $robotsText ) {
|
30 |
-
$template = Services::WpGeneral()->isPermalinksEnabled() ? "Disallow: /%s
|
31 |
-
|
32 |
-
foreach ( $this->getPossibleWords() as $word ) {
|
33 |
-
$robotsText .= sprintf( $template, $this->getCon()->prefix( $word ) );
|
34 |
-
}
|
35 |
-
return $robotsText;
|
36 |
}
|
37 |
|
38 |
-
private function isCheese() {
|
39 |
-
$
|
40 |
-
$req = Services::Request();
|
41 |
|
42 |
-
$
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
);
|
49 |
-
$bIsCheese = isset( $aMatches[ 2 ] );
|
50 |
}
|
51 |
else {
|
52 |
-
|
53 |
-
if ( preg_match( '#^[a-z0-9]{7,9}$#i', $req->query( $con->prefix( $word ) ) ) ) {
|
54 |
-
$bIsCheese = true;
|
55 |
-
break;
|
56 |
-
}
|
57 |
-
}
|
58 |
}
|
59 |
|
60 |
-
return $
|
61 |
}
|
62 |
|
63 |
public function insertMouseTrap() {
|
64 |
-
$id = chr( rand( 97, 122 ) ).rand( 1000, 10000000 );
|
65 |
echo sprintf(
|
66 |
'<style>#%s{display:none !important;}</style><a rel="nofollow" href="%s" title="%s" id="%s">%s</a>',
|
67 |
-
|
68 |
-
$
|
|
|
|
|
|
|
69 |
);
|
70 |
}
|
71 |
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
|
|
77 |
|
78 |
-
|
79 |
-
$
|
80 |
-
$sWord = $this->getPossibleWords()[ rand( 1, count( $this->getPossibleWords() ) ) - 1 ];
|
81 |
-
if ( $oWP->isPermalinksEnabled() ) {
|
82 |
-
$sLink = $oWP->getHomeUrl( sprintf( '/%s-%s/', $con->prefix( $sWord ), $sKey ) );
|
83 |
-
}
|
84 |
-
else {
|
85 |
-
$sLink = add_query_arg( [ $con->prefix( $sWord ) => $sKey ], $oWP->getHomeUrl() );
|
86 |
-
}
|
87 |
-
return $sLink;
|
88 |
}
|
89 |
|
90 |
/**
|
91 |
* @return string[]
|
|
|
92 |
*/
|
93 |
private function getPossibleWords() {
|
94 |
return [
|
13 |
class TrackLinkCheese extends Base {
|
14 |
|
15 |
const OPT_KEY = 'track_linkcheese';
|
16 |
+
const CHEESE_WORD = 'link-cheese';
|
17 |
|
18 |
protected function process() {
|
19 |
add_filter( 'robots_txt', [ $this, 'appendRobotsTxt' ], 15 );
|
20 |
add_action( 'wp_footer', [ $this, 'insertMouseTrap' ], 0 );
|
21 |
+
add_action( 'wp', [ $this, 'testCheese' ], 0 );
|
22 |
+
}
|
23 |
+
|
24 |
+
public function testCheese() {
|
25 |
+
if ( is_404() && $this->isCheese() ) {
|
26 |
+
|
27 |
+
if ( function_exists( 'wp_robots_sensitive_page' ) ) {
|
28 |
+
add_filter( 'wp_robots', 'wp_robots_sensitive_page', 1000 );
|
29 |
+
}
|
30 |
+
elseif ( function_exists( 'wp_sensitive_page_meta' ) ) {
|
31 |
+
if ( !has_action( 'wp_head', 'wp_sensitive_page_meta' ) ) {
|
32 |
+
add_action( 'wp_head', 'wp_sensitive_page_meta' );
|
33 |
+
}
|
34 |
+
}
|
35 |
+
elseif ( !has_action( 'wp_head', 'wp_no_robots' ) ) {
|
36 |
+
add_action( 'wp_head', 'wp_no_robots' );
|
37 |
+
}
|
38 |
$this->doTransgression();
|
39 |
}
|
40 |
}
|
43 |
* @param string $robotsText
|
44 |
* @return string
|
45 |
*/
|
46 |
+
public function appendRobotsTxt( $robotsText ) :string {
|
47 |
+
$template = Services::WpGeneral()->isPermalinksEnabled() ? "Disallow: /%s/\n" : "Disallow: /*?*%s=\n";
|
48 |
+
return rtrim( $robotsText, "\n" )."\n".sprintf( $template, $this->getCheeseWord() );
|
|
|
|
|
|
|
|
|
49 |
}
|
50 |
|
51 |
+
private function isCheese() :bool {
|
52 |
+
$WP = Services::WpGeneral();
|
|
|
53 |
|
54 |
+
if ( $WP->isPermalinksEnabled() ) {
|
55 |
+
$reqPath = trim( (string)Services::Request()->getPath(), '/' );
|
56 |
+
$isCheese = ( $reqPath ===
|
57 |
+
trim( (string)parse_url( $WP->getHomeUrl( $this->getCheeseWord() ), PHP_URL_PATH ), '/' ) )
|
58 |
+
|| preg_match( '#icwp-wpsf-[a-z]+-[a-z0-9]{7,9}#', $reqPath ) > 0;
|
59 |
+
/** TODO: 10.3 legacy remove */
|
|
|
|
|
60 |
}
|
61 |
else {
|
62 |
+
$isCheese = Services::Request()->query( $this->getCheeseWord() ) === '1';
|
|
|
|
|
|
|
|
|
|
|
63 |
}
|
64 |
|
65 |
+
return $isCheese;
|
66 |
}
|
67 |
|
68 |
public function insertMouseTrap() {
|
|
|
69 |
echo sprintf(
|
70 |
'<style>#%s{display:none !important;}</style><a rel="nofollow" href="%s" title="%s" id="%s">%s</a>',
|
71 |
+
'icwpWpsfLinkCheese',
|
72 |
+
$this->buildTrapHref(),
|
73 |
+
'Click here to see something fantastic',
|
74 |
+
'icwpWpsfLinkCheese',
|
75 |
+
'Click to access the login or register cheese'
|
76 |
);
|
77 |
}
|
78 |
|
79 |
+
private function buildTrapHref() :string {
|
80 |
+
$WP = Services::WpGeneral();
|
81 |
+
return $WP->isPermalinksEnabled() ?
|
82 |
+
$WP->getHomeUrl( sprintf( '/%s/', $this->getCheeseWord() ) )
|
83 |
+
: add_query_arg( [ $this->getCheeseWord() => '1' ], $WP->getHomeUrl() );
|
84 |
+
}
|
85 |
|
86 |
+
private function getCheeseWord() :string {
|
87 |
+
return $this->getCon()->prefix( self::CHEESE_WORD );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
88 |
}
|
89 |
|
90 |
/**
|
91 |
* @return string[]
|
92 |
+
* @deprecated 10.3
|
93 |
*/
|
94 |
private function getPossibleWords() {
|
95 |
return [
|
src/lib/src/Modules/IPs/Components/ImportIpsFromFile.php
CHANGED
@@ -19,7 +19,7 @@ class ImportIpsFromFile {
|
|
19 |
private function runFileImport( string $type ) {
|
20 |
$FS = Services::WpFs();
|
21 |
|
22 |
-
$fileImport = $FS->findFileInDir( 'ip_import_'.$type, $this->getCon()->
|
23 |
if ( $FS->isFile( $fileImport ) ) {
|
24 |
$content = $FS->getFileContent( $fileImport );
|
25 |
if ( !empty( $content ) ) {
|
19 |
private function runFileImport( string $type ) {
|
20 |
$FS = Services::WpFs();
|
21 |
|
22 |
+
$fileImport = $FS->findFileInDir( 'ip_import_'.$type, $this->getCon()->paths->forFlag() );
|
23 |
if ( $FS->isFile( $fileImport ) ) {
|
24 |
$content = $FS->getFileContent( $fileImport );
|
25 |
if ( !empty( $content ) ) {
|
src/lib/src/Modules/IPs/Components/QueryIpBlock.php
CHANGED
@@ -57,7 +57,7 @@ class QueryIpBlock {
|
|
57 |
&& $oIP->last_access_at < Services::Request()->ts() - $oOpts->getAutoExpireTime() ) {
|
58 |
|
59 |
( new IPs\Lib\Ops\DeleteIp() )
|
60 |
-
->
|
61 |
->setIP( Services::IP()->getRequestIp() )
|
62 |
->fromBlacklist();
|
63 |
}
|
57 |
&& $oIP->last_access_at < Services::Request()->ts() - $oOpts->getAutoExpireTime() ) {
|
58 |
|
59 |
( new IPs\Lib\Ops\DeleteIp() )
|
60 |
+
->setMod( $mod )
|
61 |
->setIP( Services::IP()->getRequestIp() )
|
62 |
->fromBlacklist();
|
63 |
}
|
src/lib/src/Modules/IPs/Components/UnblockIpByFlag.php
CHANGED
@@ -15,7 +15,7 @@ class UnblockIpByFlag {
|
|
15 |
$mod = $this->getMod();
|
16 |
$FS = Services::WpFs();
|
17 |
|
18 |
-
$path = $FS->findFileInDir( 'unblock', $this->getCon()->
|
19 |
if ( !empty( $path ) && $FS->isFile( $path ) ) {
|
20 |
$sContent = $FS->getFileContent( $path );
|
21 |
if ( !empty( $sContent ) ) {
|
@@ -23,7 +23,7 @@ class UnblockIpByFlag {
|
|
23 |
$aLines = array_map( 'trim', explode( "\n", $sContent ) );
|
24 |
foreach ( $aLines as $sIp ) {
|
25 |
$bRemoved = ( new IPs\Lib\Ops\DeleteIp() )
|
26 |
-
->
|
27 |
->setIP( $sIp )
|
28 |
->fromBlacklist();
|
29 |
if ( $bRemoved ) {
|
15 |
$mod = $this->getMod();
|
16 |
$FS = Services::WpFs();
|
17 |
|
18 |
+
$path = $FS->findFileInDir( 'unblock', $this->getCon()->paths->forFlag() );
|
19 |
if ( !empty( $path ) && $FS->isFile( $path ) ) {
|
20 |
$sContent = $FS->getFileContent( $path );
|
21 |
if ( !empty( $sContent ) ) {
|
23 |
$aLines = array_map( 'trim', explode( "\n", $sContent ) );
|
24 |
foreach ( $aLines as $sIp ) {
|
25 |
$bRemoved = ( new IPs\Lib\Ops\DeleteIp() )
|
26 |
+
->setMod( $mod )
|
27 |
->setIP( $sIp )
|
28 |
->fromBlacklist();
|
29 |
if ( $bRemoved ) {
|
src/lib/src/Modules/IPs/Lib/AutoUnblock.php
CHANGED
@@ -3,7 +3,6 @@
|
|
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\IPs\ModCon;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
8 |
use FernleafSystems\Wordpress\Services\Services;
|
9 |
|
@@ -17,19 +16,40 @@ class AutoUnblock {
|
|
17 |
*/
|
18 |
public function run() :bool {
|
19 |
try {
|
20 |
-
$
|
21 |
}
|
22 |
catch ( \Exception $e ) {
|
23 |
-
$
|
24 |
}
|
25 |
-
if ( !$
|
26 |
try {
|
27 |
-
$
|
28 |
}
|
29 |
catch ( \Exception $e ) {
|
30 |
}
|
31 |
}
|
32 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
}
|
34 |
|
35 |
/**
|
@@ -83,7 +103,7 @@ class AutoUnblock {
|
|
83 |
}
|
84 |
|
85 |
( new IPs\Lib\Ops\DeleteIp() )
|
86 |
-
->
|
87 |
->setIP( $sIP )
|
88 |
->fromBlacklist();
|
89 |
$unblocked = true;
|
@@ -149,7 +169,7 @@ class AutoUnblock {
|
|
149 |
}
|
150 |
elseif ( $linkParts[ 1 ] === 'go' ) {
|
151 |
( new IPs\Lib\Ops\DeleteIp() )
|
152 |
-
->
|
153 |
->setIP( Services::IP()->getRequestIp() )
|
154 |
->fromBlacklist();
|
155 |
$unblocked = true;
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib;
|
4 |
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
|
|
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
7 |
use FernleafSystems\Wordpress\Services\Services;
|
8 |
|
16 |
*/
|
17 |
public function run() :bool {
|
18 |
try {
|
19 |
+
$unblocked = $this->processAutoUnblockRequest();
|
20 |
}
|
21 |
catch ( \Exception $e ) {
|
22 |
+
$unblocked = false;
|
23 |
}
|
24 |
+
if ( !$unblocked ) {
|
25 |
try {
|
26 |
+
$unblocked = $this->processUserMagicLink();
|
27 |
}
|
28 |
catch ( \Exception $e ) {
|
29 |
}
|
30 |
}
|
31 |
+
if ( !$unblocked ) {
|
32 |
+
$unblocked = $this->checkForBlockedServiceBot();
|
33 |
+
}
|
34 |
+
return $unblocked;
|
35 |
+
}
|
36 |
+
|
37 |
+
/**
|
38 |
+
* @deprecated 10.3 - temporary to ensure that service bots aren't blocked and reduce spurious Audit Trail
|
39 |
+
*/
|
40 |
+
private function checkForBlockedServiceBot() :bool {
|
41 |
+
/** @var IPs\ModCon $mod */
|
42 |
+
$mod = $this->getMod();
|
43 |
+
|
44 |
+
$unblocked = false;
|
45 |
+
if ( $mod->isVerifiedBot() ) {
|
46 |
+
( new IPs\Lib\Ops\DeleteIp() )
|
47 |
+
->setMod( $mod )
|
48 |
+
->setIP( Services::IP()->getRequestIp() )
|
49 |
+
->fromBlacklist();
|
50 |
+
$unblocked = true;
|
51 |
+
}
|
52 |
+
return $unblocked;
|
53 |
}
|
54 |
|
55 |
/**
|
103 |
}
|
104 |
|
105 |
( new IPs\Lib\Ops\DeleteIp() )
|
106 |
+
->setMod( $mod )
|
107 |
->setIP( $sIP )
|
108 |
->fromBlacklist();
|
109 |
$unblocked = true;
|
169 |
}
|
170 |
elseif ( $linkParts[ 1 ] === 'go' ) {
|
171 |
( new IPs\Lib\Ops\DeleteIp() )
|
172 |
+
->setMod( $mod )
|
173 |
->setIP( Services::IP()->getRequestIp() )
|
174 |
->fromBlacklist();
|
175 |
$unblocked = true;
|
src/lib/src/Modules/IPs/Lib/BlacklistHandler.php
CHANGED
@@ -2,7 +2,8 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Logic\
|
|
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
|
8 |
use FernleafSystems\Wordpress\Services\Services;
|
@@ -10,18 +11,20 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
10 |
class BlacklistHandler {
|
11 |
|
12 |
use Modules\ModConsumer;
|
13 |
-
use
|
|
|
14 |
|
15 |
protected function run() {
|
16 |
/** @var IPs\ModCon $mod */
|
17 |
$mod = $this->getMod();
|
18 |
-
/** @var IPs\Options $
|
19 |
-
$
|
20 |
-
|
|
|
21 |
|
22 |
-
$
|
23 |
-
if ( Services::WpGeneral()->isCron() && $
|
24 |
-
|
25 |
}
|
26 |
|
27 |
( new IPs\Components\UnblockIpByFlag() )
|
@@ -30,17 +33,17 @@ class BlacklistHandler {
|
|
30 |
|
31 |
add_action( 'init', [ $this, 'loadBotDetectors' ] ); // hook in the bot detection
|
32 |
|
33 |
-
if ( !$mod->isVisitorWhitelisted()
|
34 |
-
&& !$this->isRequestWhitelisted() && !$mod->isVerifiedBot() ) {
|
35 |
|
36 |
// We setup offenses processing immediately but run the blocks on 'init
|
37 |
( new ProcessOffenses() )
|
38 |
->setMod( $this->getMod() )
|
39 |
-
->
|
|
|
40 |
add_action( 'init', function () {
|
41 |
( new BlockRequest() )
|
42 |
->setMod( $this->getMod() )
|
43 |
-
->
|
44 |
}, -100000 );
|
45 |
}
|
46 |
}
|
@@ -58,27 +61,32 @@ class BlacklistHandler {
|
|
58 |
if ( $opts->isEnabledTrackXmlRpc() ) {
|
59 |
( new IPs\BotTrack\TrackXmlRpc() )
|
60 |
->setMod( $mod )
|
61 |
-
->
|
62 |
}
|
63 |
if ( $opts->isEnabledTrack404() ) {
|
64 |
( new IPs\BotTrack\Track404() )
|
65 |
->setMod( $mod )
|
66 |
-
->
|
67 |
}
|
68 |
if ( $opts->isEnabledTrackLoginFailed() ) {
|
69 |
( new IPs\BotTrack\TrackLoginFailed() )
|
70 |
->setMod( $mod )
|
71 |
-
->
|
72 |
}
|
73 |
if ( $opts->isEnabledTrackLoginInvalid() ) {
|
74 |
( new IPs\BotTrack\TrackLoginInvalid() )
|
75 |
->setMod( $mod )
|
76 |
-
->
|
77 |
}
|
78 |
if ( $opts->isEnabledTrackFakeWebCrawler() ) {
|
79 |
( new IPs\BotTrack\TrackFakeWebCrawler() )
|
80 |
->setMod( $mod )
|
81 |
-
->
|
|
|
|
|
|
|
|
|
|
|
82 |
}
|
83 |
}
|
84 |
|
@@ -86,29 +94,31 @@ class BlacklistHandler {
|
|
86 |
if ( $opts->isEnabledTrackLinkCheese() && $mod->canLinkCheese() ) {
|
87 |
( new IPs\BotTrack\TrackLinkCheese() )
|
88 |
->setMod( $mod )
|
89 |
-
->
|
90 |
}
|
91 |
}
|
|
|
|
|
|
|
|
|
|
|
92 |
}
|
93 |
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
$bWhitelisted = false;
|
101 |
-
$aWhitelist = $oOpts->getRequestWhitelistAsRegex();
|
102 |
-
if ( !empty( $aWhitelist ) ) {
|
103 |
$sPath = strtolower( '/'.ltrim( (string)Services::Request()->getPath(), '/' ) );
|
104 |
-
foreach ( $
|
105 |
-
if ( preg_match( $
|
106 |
-
$
|
107 |
break;
|
108 |
}
|
109 |
}
|
110 |
}
|
111 |
-
return $
|
112 |
}
|
113 |
|
114 |
public function runHourlyCron() {
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Logic\ExecOnce;
|
6 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Crons\PluginCronsConsumer;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules;
|
8 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
|
9 |
use FernleafSystems\Wordpress\Services\Services;
|
11 |
class BlacklistHandler {
|
12 |
|
13 |
use Modules\ModConsumer;
|
14 |
+
use ExecOnce;
|
15 |
+
use PluginCronsConsumer;
|
16 |
|
17 |
protected function run() {
|
18 |
/** @var IPs\ModCon $mod */
|
19 |
$mod = $this->getMod();
|
20 |
+
/** @var IPs\Options $opts */
|
21 |
+
$opts = $this->getOptions();
|
22 |
+
|
23 |
+
if ( $opts->isEnabledAutoBlackList() ) {
|
24 |
|
25 |
+
$con = $this->getCon();
|
26 |
+
if ( Services::WpGeneral()->isCron() && $con->isPremiumActive() ) {
|
27 |
+
$this->setupCronHooks();
|
28 |
}
|
29 |
|
30 |
( new IPs\Components\UnblockIpByFlag() )
|
33 |
|
34 |
add_action( 'init', [ $this, 'loadBotDetectors' ] ); // hook in the bot detection
|
35 |
|
36 |
+
if ( !$mod->isVisitorWhitelisted() && !$this->isRequestWhitelisted() ) {
|
|
|
37 |
|
38 |
// We setup offenses processing immediately but run the blocks on 'init
|
39 |
( new ProcessOffenses() )
|
40 |
->setMod( $this->getMod() )
|
41 |
+
->execute();
|
42 |
+
|
43 |
add_action( 'init', function () {
|
44 |
( new BlockRequest() )
|
45 |
->setMod( $this->getMod() )
|
46 |
+
->execute();
|
47 |
}, -100000 );
|
48 |
}
|
49 |
}
|
61 |
if ( $opts->isEnabledTrackXmlRpc() ) {
|
62 |
( new IPs\BotTrack\TrackXmlRpc() )
|
63 |
->setMod( $mod )
|
64 |
+
->execute();
|
65 |
}
|
66 |
if ( $opts->isEnabledTrack404() ) {
|
67 |
( new IPs\BotTrack\Track404() )
|
68 |
->setMod( $mod )
|
69 |
+
->execute();
|
70 |
}
|
71 |
if ( $opts->isEnabledTrackLoginFailed() ) {
|
72 |
( new IPs\BotTrack\TrackLoginFailed() )
|
73 |
->setMod( $mod )
|
74 |
+
->execute();
|
75 |
}
|
76 |
if ( $opts->isEnabledTrackLoginInvalid() ) {
|
77 |
( new IPs\BotTrack\TrackLoginInvalid() )
|
78 |
->setMod( $mod )
|
79 |
+
->execute();
|
80 |
}
|
81 |
if ( $opts->isEnabledTrackFakeWebCrawler() ) {
|
82 |
( new IPs\BotTrack\TrackFakeWebCrawler() )
|
83 |
->setMod( $mod )
|
84 |
+
->execute();
|
85 |
+
}
|
86 |
+
if ( $opts->isEnabledTrackInvalidScript() ) {
|
87 |
+
( new IPs\BotTrack\TrackInvalidScriptLoad() )
|
88 |
+
->setMod( $mod )
|
89 |
+
->execute();
|
90 |
}
|
91 |
}
|
92 |
|
94 |
if ( $opts->isEnabledTrackLinkCheese() && $mod->canLinkCheese() ) {
|
95 |
( new IPs\BotTrack\TrackLinkCheese() )
|
96 |
->setMod( $mod )
|
97 |
+
->execute();
|
98 |
}
|
99 |
}
|
100 |
+
|
101 |
+
// Capture when admins un/mark comments as spam
|
102 |
+
( new IPs\BotTrack\TrackCommentSpam() )
|
103 |
+
->setMod( $mod )
|
104 |
+
->execute();
|
105 |
}
|
106 |
|
107 |
+
private function isRequestWhitelisted() :bool {
|
108 |
+
/** @var IPs\Options $opts */
|
109 |
+
$opts = $this->getOptions();
|
110 |
+
$isWhitelisted = false;
|
111 |
+
$whitelistPaths = $opts->getRequestWhitelistAsRegex();
|
112 |
+
if ( !empty( $whitelistPaths ) ) {
|
|
|
|
|
|
|
113 |
$sPath = strtolower( '/'.ltrim( (string)Services::Request()->getPath(), '/' ) );
|
114 |
+
foreach ( $whitelistPaths as $rule ) {
|
115 |
+
if ( preg_match( $rule, $sPath ) ) {
|
116 |
+
$isWhitelisted = true;
|
117 |
break;
|
118 |
}
|
119 |
}
|
120 |
}
|
121 |
+
return $isWhitelisted;
|
122 |
}
|
123 |
|
124 |
public function runHourlyCron() {
|
src/lib/src/Modules/IPs/Lib/BlockRequest.php
CHANGED
@@ -2,6 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib;
|
4 |
|
|
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
7 |
use FernleafSystems\Wordpress\Services\Services;
|
@@ -10,18 +11,19 @@ use FernleafSystems\Wordpress\Services\Utilities\Obfuscate;
|
|
10 |
class BlockRequest {
|
11 |
|
12 |
use ModConsumer;
|
|
|
13 |
|
14 |
-
|
15 |
if ( $this->isBlocked() ) {
|
16 |
|
17 |
if ( $this->isAutoUnBlocked() ) {
|
18 |
Services::Response()->redirectToHome();
|
19 |
}
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
}
|
26 |
}
|
27 |
|
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;
|
11 |
class BlockRequest {
|
12 |
|
13 |
use ModConsumer;
|
14 |
+
use ExecOnce;
|
15 |
|
16 |
+
protected function run() {
|
17 |
if ( $this->isBlocked() ) {
|
18 |
|
19 |
if ( $this->isAutoUnBlocked() ) {
|
20 |
Services::Response()->redirectToHome();
|
21 |
}
|
22 |
+
else {
|
23 |
+
add_filter( 'shield/is_log_traffic', '__return_false' ); // don't log killed requests
|
24 |
+
$this->getCon()->fireEvent( 'conn_kill' );
|
25 |
+
$this->renderKillPage();
|
26 |
+
}
|
27 |
}
|
28 |
}
|
29 |
|
src/lib/src/Modules/IPs/Lib/Bots/BotSignalsController.php
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Bots;
|
4 |
+
|
5 |
+
use FernleafSystems\Utilities\Logic\ExecOnce;
|
6 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\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
|
17 |
+
*/
|
18 |
+
private $handlerNotBot;
|
19 |
+
|
20 |
+
/**
|
21 |
+
* @var EventListener
|
22 |
+
*/
|
23 |
+
private $eventListener;
|
24 |
+
|
25 |
+
public function isBot( string $IP = '', bool $allowEventFire = true ) :bool {
|
26 |
+
$score = ( new CalculateVisitorBotScores() )
|
27 |
+
->setMod( $this->getMod() )
|
28 |
+
->setIP( empty( $IP ) ? Services::IP()->getRequestIp() : $IP )
|
29 |
+
->probability();
|
30 |
+
$botScoreMinimum = (int)apply_filters( 'shield/antibot_score_minimum',
|
31 |
+
(int)$this->getOptions()->getOpt( 'antibot_minimum', 50 ) );
|
32 |
+
|
33 |
+
$isBot = $score < $botScoreMinimum;
|
34 |
+
|
35 |
+
if ( $allowEventFire ) {
|
36 |
+
$this->getCon()->fireEvent(
|
37 |
+
'antibot_'.( $isBot ? 'fail' : 'pass' ),
|
38 |
+
[
|
39 |
+
'audit' => [
|
40 |
+
'score' => $score,
|
41 |
+
'minimum' => $botScoreMinimum,
|
42 |
+
]
|
43 |
+
]
|
44 |
+
);
|
45 |
+
}
|
46 |
+
return $isBot;
|
47 |
+
}
|
48 |
+
|
49 |
+
public function getHandlerNotBot() :NotBot\NotBotHandler {
|
50 |
+
if ( !isset( $this->handlerNotBot ) ) {
|
51 |
+
$this->handlerNotBot = ( new NotBot\NotBotHandler() )->setMod( $this->getMod() );
|
52 |
+
}
|
53 |
+
return $this->handlerNotBot;
|
54 |
+
}
|
55 |
+
|
56 |
+
public function getEventListener() :EventListener {
|
57 |
+
if ( !isset( $this->eventListener ) ) {
|
58 |
+
$this->eventListener = ( new EventListener() )->setMod( $this->getMod() );
|
59 |
+
}
|
60 |
+
return $this->eventListener;
|
61 |
+
}
|
62 |
+
|
63 |
+
protected function run() {
|
64 |
+
$this->getEventListener()->execute();
|
65 |
+
add_action( 'init', function () {
|
66 |
+
$this->getHandlerNotBot()->execute();
|
67 |
+
} );
|
68 |
+
}
|
69 |
+
}
|
src/lib/src/Modules/IPs/Lib/Bots/BotSignalsRecord.php
ADDED
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
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 {
|
14 |
+
|
15 |
+
use ModConsumer;
|
16 |
+
use IpAddressConsumer;
|
17 |
+
|
18 |
+
public function delete() :bool {
|
19 |
+
/** @var ModCon $mod */
|
20 |
+
$mod = $this->getMod();
|
21 |
+
/** @var Select $select */
|
22 |
+
$select = $mod->getDbHandler_BotSignals()->getQueryDeleter();
|
23 |
+
return $select->filterByIPHuman( $this->getIP() )->query();
|
24 |
+
}
|
25 |
+
|
26 |
+
public function retrieve( bool $storeOnLoad = true ) :EntryVO {
|
27 |
+
/** @var ModCon $mod */
|
28 |
+
$mod = $this->getMod();
|
29 |
+
/** @var Select $select */
|
30 |
+
$select = $mod->getDbHandler_BotSignals()->getQuerySelector();
|
31 |
+
$e = $select->filterByIPHuman( $this->getIP() )->first();
|
32 |
+
if ( !$e instanceof EntryVO ) {
|
33 |
+
$e = new EntryVO();
|
34 |
+
$e->ip = $this->getIP();
|
35 |
+
}
|
36 |
+
|
37 |
+
$ipOnList = ( new LookupIpOnList() )
|
38 |
+
->setDbHandler( $mod->getDbHandler_IPs() )
|
39 |
+
->setIP( $e->ip )
|
40 |
+
->lookupIp();
|
41 |
+
|
42 |
+
if ( !empty( $ipOnList ) ) {
|
43 |
+
if ( empty( $e->bypass_at ) && $ipOnList->list === $mod::LIST_MANUAL_WHITE ) {
|
44 |
+
$e->bypass_at = $ipOnList->created_at;
|
45 |
+
}
|
46 |
+
if ( empty( $e->offense_at ) && $ipOnList->list === $mod::LIST_AUTO_BLACK ) {
|
47 |
+
$e->offense_at = $ipOnList->last_access_at;
|
48 |
+
}
|
49 |
+
$e->blocked_at = $ipOnList->blocked_at;
|
50 |
+
}
|
51 |
+
|
52 |
+
if ( empty( $e->notbot_at ) && Services::IP()->getRequestIp() === $this->getIP() ) {
|
53 |
+
$e->notbot_at = $mod->getBotSignalsController()
|
54 |
+
->getHandlerNotBot()
|
55 |
+
->hasCookie() ? Services::Request()->ts() : 0;
|
56 |
+
}
|
57 |
+
|
58 |
+
if ( $storeOnLoad ) {
|
59 |
+
$this->store( $e );
|
60 |
+
}
|
61 |
+
|
62 |
+
return $e;
|
63 |
+
}
|
64 |
+
|
65 |
+
public function store( EntryVO $entry ) :bool {
|
66 |
+
/** @var ModCon $mod */
|
67 |
+
$mod = $this->getMod();
|
68 |
+
|
69 |
+
if ( empty( $entry->id ) ) {
|
70 |
+
$success = $mod->getDbHandler_BotSignals()
|
71 |
+
->getQueryInserter()
|
72 |
+
->insert( $entry );
|
73 |
+
}
|
74 |
+
else {
|
75 |
+
$data = $entry->getRawData();
|
76 |
+
$data[ 'updated_at' ] = Services::Request()->ts();
|
77 |
+
$success = $mod->getDbHandler_BotSignals()
|
78 |
+
->getQueryUpdater()
|
79 |
+
->updateById( $entry->id, $data );
|
80 |
+
}
|
81 |
+
return $success;
|
82 |
+
}
|
83 |
+
|
84 |
+
/**
|
85 |
+
* @param string $field
|
86 |
+
* @param int|null $ts
|
87 |
+
* @return EntryVO
|
88 |
+
* @throws \LogicException
|
89 |
+
*/
|
90 |
+
public function updateSignalField( string $field, $ts = null ) :EntryVO {
|
91 |
+
/** @var ModCon $mod */
|
92 |
+
$mod = $this->getMod();
|
93 |
+
|
94 |
+
if ( !$mod->getDbHandler_BotSignals()->getTableSchema()->hasColumn( $field ) ) {
|
95 |
+
throw new \LogicException( sprintf( '"%s" is not a valid column on Bot Signals', $field ) );
|
96 |
+
}
|
97 |
+
|
98 |
+
$entry = $this->retrieve( false ); // false as we're going to store it anyway
|
99 |
+
$entry->{$field} = is_null( $ts ) ? Services::Request()->ts() : $ts;
|
100 |
+
|
101 |
+
$this->store( $entry );
|
102 |
+
|
103 |
+
return $entry;
|
104 |
+
}
|
105 |
+
}
|
src/lib/src/Modules/IPs/Lib/Bots/Calculator/BuildScores.php
ADDED
@@ -0,0 +1,297 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Bots\Calculator;
|
4 |
+
|
5 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base\EntryVoConsumer;
|
6 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Databases\BotSignals\EntryVO;
|
7 |
+
use FernleafSystems\Wordpress\Services\Services;
|
8 |
+
use FernleafSystems\Wordpress\Services\Utilities\Net\IpID;
|
9 |
+
|
10 |
+
class BuildScores {
|
11 |
+
|
12 |
+
use EntryVoConsumer;
|
13 |
+
|
14 |
+
public function build() :array {
|
15 |
+
$scores = [];
|
16 |
+
foreach ( $this->getAllFields( true ) as $field ) {
|
17 |
+
$scores[ $field ] = $this->{'score_'.$field}();
|
18 |
+
}
|
19 |
+
$scores[ 'known' ] = $this->score_known();
|
20 |
+
return $scores;
|
21 |
+
}
|
22 |
+
|
23 |
+
private function score_known() :int {
|
24 |
+
try {
|
25 |
+
list( $ipID, $ipName ) = ( new IpID( $this->getRecord()->ip ) )->run();
|
26 |
+
}
|
27 |
+
catch ( \Exception $e ) {
|
28 |
+
$ipID = null;
|
29 |
+
}
|
30 |
+
return ( empty( $ipID ) || in_array( $ipID, [ IpID::UNKNOWN, IpID::VISITOR ] ) )
|
31 |
+
? 0 : 100;
|
32 |
+
}
|
33 |
+
|
34 |
+
private function score_auth() :int {
|
35 |
+
if ( $this->lastAtTs( __FUNCTION__ ) === 0 ) {
|
36 |
+
$score = 0;
|
37 |
+
}
|
38 |
+
else {
|
39 |
+
$score = $this->diffTs( __FUNCTION__ ) < DAY_IN_SECONDS ? 150 : 100;
|
40 |
+
}
|
41 |
+
return $score;
|
42 |
+
}
|
43 |
+
|
44 |
+
private function score_bt404() :int {
|
45 |
+
if ( $this->lastAtTs( __FUNCTION__ ) === 0 ) {
|
46 |
+
$score = 0;
|
47 |
+
}
|
48 |
+
else {
|
49 |
+
$score = $this->diffTs( __FUNCTION__ ) < HOUR_IN_SECONDS ? -25 : -15;
|
50 |
+
}
|
51 |
+
return $score;
|
52 |
+
}
|
53 |
+
|
54 |
+
private function score_btcheese() :int {
|
55 |
+
if ( $this->lastAtTs( __FUNCTION__ ) === 0 ) {
|
56 |
+
$score = 0;
|
57 |
+
}
|
58 |
+
else {
|
59 |
+
$score = $this->diffTs( __FUNCTION__ ) < DAY_IN_SECONDS ? -100 : -75;
|
60 |
+
}
|
61 |
+
return $score;
|
62 |
+
}
|
63 |
+
|
64 |
+
private function score_btfake() :int {
|
65 |
+
if ( $this->lastAtTs( __FUNCTION__ ) === 0 ) {
|
66 |
+
$score = 0;
|
67 |
+
}
|
68 |
+
else {
|
69 |
+
$score = $this->diffTs( __FUNCTION__ ) < DAY_IN_SECONDS ? -65 : -45;
|
70 |
+
}
|
71 |
+
return $score;
|
72 |
+
}
|
73 |
+
|
74 |
+
private function score_btinvalidscript() :int {
|
75 |
+
if ( $this->lastAtTs( __FUNCTION__ ) === 0 ) {
|
76 |
+
$score = 0;
|
77 |
+
}
|
78 |
+
else {
|
79 |
+
$score = $this->diffTs( __FUNCTION__ ) < DAY_IN_SECONDS ? -35 : -25;
|
80 |
+
}
|
81 |
+
return $score;
|
82 |
+
}
|
83 |
+
|
84 |
+
private function score_btloginfail() :int {
|
85 |
+
if ( $this->lastAtTs( __FUNCTION__ ) === 0 ) {
|
86 |
+
$score = 0;
|
87 |
+
}
|
88 |
+
else {
|
89 |
+
$score = $this->diffTs( __FUNCTION__ ) < MINUTE_IN_SECONDS ? -50 : -25;
|
90 |
+
}
|
91 |
+
return $score;
|
92 |
+
}
|
93 |
+
|
94 |
+
private function score_btlogininvalid() :int {
|
95 |
+
if ( $this->lastAtTs( __FUNCTION__ ) === 0 ) {
|
96 |
+
$score = 0;
|
97 |
+
}
|
98 |
+
else {
|
99 |
+
$score = $this->diffTs( __FUNCTION__ ) < DAY_IN_SECONDS ? -85 : -55;
|
100 |
+
}
|
101 |
+
return $score;
|
102 |
+
}
|
103 |
+
|
104 |
+
private function score_btua() :int {
|
105 |
+
if ( $this->lastAtTs( __FUNCTION__ ) === 0 ) {
|
106 |
+
$score = 0;
|
107 |
+
}
|
108 |
+
else {
|
109 |
+
$score = $this->diffTs( __FUNCTION__ ) < DAY_IN_SECONDS ? -35 : -25;
|
110 |
+
}
|
111 |
+
return $score;
|
112 |
+
}
|
113 |
+
|
114 |
+
private function score_btxml() :int {
|
115 |
+
if ( $this->lastAtTs( __FUNCTION__ ) === 0 ) {
|
116 |
+
$score = 0;
|
117 |
+
}
|
118 |
+
else {
|
119 |
+
$score = $this->diffTs( __FUNCTION__ ) < DAY_IN_SECONDS ? -75 : -35;
|
120 |
+
}
|
121 |
+
return $score;
|
122 |
+
}
|
123 |
+
|
124 |
+
private function score_cooldown() :int {
|
125 |
+
if ( $this->lastAtTs( __FUNCTION__ ) === 0 ) {
|
126 |
+
$score = 0;
|
127 |
+
}
|
128 |
+
else {
|
129 |
+
$score = $this->diffTs( __FUNCTION__ ) < MINUTE_IN_SECONDS ? -35 : -15;
|
130 |
+
}
|
131 |
+
return $score;
|
132 |
+
}
|
133 |
+
|
134 |
+
private function score_firewall() :int {
|
135 |
+
if ( $this->lastAtTs( __FUNCTION__ ) === 0 ) {
|
136 |
+
$score = 0;
|
137 |
+
}
|
138 |
+
else {
|
139 |
+
$score = $this->diffTs( __FUNCTION__ ) < DAY_IN_SECONDS ? -45 : -25;
|
140 |
+
}
|
141 |
+
return $score;
|
142 |
+
}
|
143 |
+
|
144 |
+
private function score_offense() :int {
|
145 |
+
if ( $this->lastAtTs( __FUNCTION__ ) === 0 ) {
|
146 |
+
$score = 0;
|
147 |
+
}
|
148 |
+
else {
|
149 |
+
$score = $this->diffTs( __FUNCTION__ ) < MINUTE_IN_SECONDS ? -45 : -25;
|
150 |
+
}
|
151 |
+
return $score;
|
152 |
+
}
|
153 |
+
|
154 |
+
private function score_blocked() :int {
|
155 |
+
if ( $this->lastAtTs( __FUNCTION__ ) === 0 ) {
|
156 |
+
$score = 0;
|
157 |
+
}
|
158 |
+
else {
|
159 |
+
$score = $this->diffTs( __FUNCTION__ ) < DAY_IN_SECONDS ? -75 : -55;
|
160 |
+
}
|
161 |
+
return $score;
|
162 |
+
}
|
163 |
+
|
164 |
+
private function score_unblocked() :int {
|
165 |
+
if ( $this->lastAtTs( __FUNCTION__ ) === 0 ) {
|
166 |
+
$score = 0;
|
167 |
+
}
|
168 |
+
else {
|
169 |
+
$score = $this->diffTs( __FUNCTION__ ) < DAY_IN_SECONDS ? 100 : 75;
|
170 |
+
}
|
171 |
+
return $score;
|
172 |
+
}
|
173 |
+
|
174 |
+
private function score_bypass() :int {
|
175 |
+
return $this->lastAtTs( __FUNCTION__ ) > 0 ? 150 : 0;
|
176 |
+
}
|
177 |
+
|
178 |
+
private function score_captchapass() :int {
|
179 |
+
if ( $this->lastAtTs( __FUNCTION__ ) === 0 ) {
|
180 |
+
$score = 0;
|
181 |
+
}
|
182 |
+
else {
|
183 |
+
$score = $this->diffTs( __FUNCTION__ ) < DAY_IN_SECONDS ? 55 : 25;
|
184 |
+
}
|
185 |
+
return $score;
|
186 |
+
}
|
187 |
+
|
188 |
+
private function score_ratelimit() :int {
|
189 |
+
if ( $this->lastAtTs( __FUNCTION__ ) === 0 ) {
|
190 |
+
$score = 0;
|
191 |
+
}
|
192 |
+
else {
|
193 |
+
$score = $this->diffTs( __FUNCTION__ ) < MINUTE_IN_SECONDS ? -55 : -25;
|
194 |
+
}
|
195 |
+
return $score;
|
196 |
+
}
|
197 |
+
|
198 |
+
private function score_captchafail() :int {
|
199 |
+
if ( $this->lastAtTs( __FUNCTION__ ) === 0 ) {
|
200 |
+
$score = 0;
|
201 |
+
}
|
202 |
+
else {
|
203 |
+
$score = $this->diffTs( __FUNCTION__ ) < HOUR_IN_SECONDS ? -55 : -25;
|
204 |
+
}
|
205 |
+
return $score;
|
206 |
+
}
|
207 |
+
|
208 |
+
private function score_humanspam() :int {
|
209 |
+
if ( $this->lastAtTs( __FUNCTION__ ) === 0 ) {
|
210 |
+
$score = 0;
|
211 |
+
}
|
212 |
+
else {
|
213 |
+
$score = $this->diffTs( __FUNCTION__ ) < DAY_IN_SECONDS ? -30 : -15;
|
214 |
+
}
|
215 |
+
return $score;
|
216 |
+
}
|
217 |
+
|
218 |
+
private function score_markspam() :int {
|
219 |
+
if ( $this->lastAtTs( __FUNCTION__ ) === 0 ) {
|
220 |
+
$score = 0;
|
221 |
+
}
|
222 |
+
else {
|
223 |
+
$score = $this->diffTs( __FUNCTION__ ) < WEEK_IN_SECONDS ? -50 : -25;
|
224 |
+
}
|
225 |
+
return $score;
|
226 |
+
}
|
227 |
+
|
228 |
+
private function score_unmarkspam() :int {
|
229 |
+
if ( $this->lastAtTs( __FUNCTION__ ) === 0 ) {
|
230 |
+
$score = 0;
|
231 |
+
}
|
232 |
+
else {
|
233 |
+
$score = $this->diffTs( __FUNCTION__ ) < WEEK_IN_SECONDS ? 75 : 35;
|
234 |
+
}
|
235 |
+
return $score;
|
236 |
+
}
|
237 |
+
|
238 |
+
private function score_frontpage() :int {
|
239 |
+
if ( $this->lastAtTs( __FUNCTION__ ) === 0 ) {
|
240 |
+
$score = -15;
|
241 |
+
}
|
242 |
+
else {
|
243 |
+
$score = $this->diffTs( __FUNCTION__ ) < HOUR_IN_SECONDS ? 25 : 15;
|
244 |
+
}
|
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 |
+
}
|
257 |
+
|
258 |
+
private function lastAtTs( $fieldFunction ) :int {
|
259 |
+
$field = str_replace( 'score_', '', $fieldFunction ).'_at';
|
260 |
+
return $this->getRecord()->{$field} ?? 0;
|
261 |
+
}
|
262 |
+
|
263 |
+
private function diffTs( $fieldFunction ) :int {
|
264 |
+
$field = str_replace( 'score_', '', $fieldFunction ).'_at';
|
265 |
+
return Services::Request()->ts() - ( $this->getRecord()->{$field} ?? 0 );
|
266 |
+
}
|
267 |
+
|
268 |
+
private function getAllFields( $filterForMethods = false ) :array {
|
269 |
+
$botSignalDBH = shield_security_get_plugin()->getController()
|
270 |
+
->getModule_IPs()
|
271 |
+
->getDbHandler_BotSignals();
|
272 |
+
$fields = array_map(
|
273 |
+
function ( $col ) {
|
274 |
+
return str_replace( '_at', '', $col );
|
275 |
+
},
|
276 |
+
array_filter(
|
277 |
+
$botSignalDBH->getTableSchema()->getColumnNames(),
|
278 |
+
function ( $col ) {
|
279 |
+
return preg_match( '#_at$#', $col ) &&
|
280 |
+
!in_array( $col, [ 'updated_at', 'created_at', 'deleted_at' ] );
|
281 |
+
}
|
282 |
+
)
|
283 |
+
);
|
284 |
+
|
285 |
+
if ( $filterForMethods ) {
|
286 |
+
$fields = array_filter( $fields, function ( $field ) {
|
287 |
+
return method_exists( $this, 'score_'.$field );
|
288 |
+
} );
|
289 |
+
}
|
290 |
+
|
291 |
+
return $fields;
|
292 |
+
}
|
293 |
+
|
294 |
+
private function getRecord() :EntryVO {
|
295 |
+
return $this->getEntryVO();
|
296 |
+
}
|
297 |
+
}
|
src/lib/src/Modules/IPs/Lib/Bots/Calculator/CalculateVisitorBotScores.php
ADDED
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Bots\Calculator;
|
4 |
+
|
5 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Databases\BotSignals\EntryVO;
|
6 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Components\IpAddressConsumer;
|
7 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Bots\BotSignalsRecord;
|
8 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
9 |
+
use FernleafSystems\Wordpress\Services\Services;
|
10 |
+
|
11 |
+
class CalculateVisitorBotScores {
|
12 |
+
|
13 |
+
use IpAddressConsumer;
|
14 |
+
use ModConsumer;
|
15 |
+
|
16 |
+
private $scores = [];
|
17 |
+
|
18 |
+
public function scores() :array {
|
19 |
+
$this->scores = ( new BuildScores() )
|
20 |
+
->setEntryVO( $this->loadEntry() )
|
21 |
+
->build();
|
22 |
+
return $this->getActiveScores();
|
23 |
+
}
|
24 |
+
|
25 |
+
public function total() :int {
|
26 |
+
return (int)array_sum( $this->scores() );
|
27 |
+
}
|
28 |
+
|
29 |
+
public function probability() :int {
|
30 |
+
return (int)max( 0, min( 100, $this->total() ) );
|
31 |
+
}
|
32 |
+
|
33 |
+
private function getActiveScores() :array {
|
34 |
+
return array_filter(
|
35 |
+
$this->scores,
|
36 |
+
function ( $score ) {
|
37 |
+
return $score !== -1;
|
38 |
+
}
|
39 |
+
);
|
40 |
+
}
|
41 |
+
|
42 |
+
private function loadEntry() :EntryVO {
|
43 |
+
$ip = $this->getIP();
|
44 |
+
if ( empty( $ip ) ) {
|
45 |
+
$ip = Services::IP()->getRequestIp();
|
46 |
+
}
|
47 |
+
try {
|
48 |
+
$entry = ( new BotSignalsRecord() )
|
49 |
+
->setMod( $this->getMod() )
|
50 |
+
->setIP( $ip )
|
51 |
+
->retrieve();
|
52 |
+
}
|
53 |
+
catch ( \Exception $e ) {
|
54 |
+
$entry = new EntryVO();
|
55 |
+
$entry->ip = $ip;
|
56 |
+
}
|
57 |
+
|
58 |
+
return $entry;
|
59 |
+
}
|
60 |
+
}
|
src/lib/src/Modules/IPs/Lib/Bots/EventListener.php
ADDED
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Bots;
|
4 |
+
|
5 |
+
use FernleafSystems\Utilities\Logic\ExecOnce;
|
6 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\ModCon;
|
7 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
8 |
+
use FernleafSystems\Wordpress\Services\Services;
|
9 |
+
|
10 |
+
class EventListener {
|
11 |
+
|
12 |
+
use ModConsumer;
|
13 |
+
use ExecOnce;
|
14 |
+
|
15 |
+
public function fireEventForIP( $ip, $event ) {
|
16 |
+
$events = $this->getEventsToColumn();
|
17 |
+
|
18 |
+
foreach ( $events as $eventTrigger => $column ) {
|
19 |
+
if ( $eventTrigger === $event || preg_match( sprintf( '#^%s$#', $eventTrigger ), $event ) ) {
|
20 |
+
try {
|
21 |
+
( new BotSignalsRecord() )
|
22 |
+
->setMod( $this->getMod() )
|
23 |
+
->setIP( $ip )
|
24 |
+
->updateSignalField( $column );
|
25 |
+
}
|
26 |
+
catch ( \LogicException $e ) {
|
27 |
+
error_log( 'Error updating bot signal: '.$e->getMessage() );
|
28 |
+
}
|
29 |
+
}
|
30 |
+
}
|
31 |
+
}
|
32 |
+
|
33 |
+
protected function canRun() :bool {
|
34 |
+
/** @var ModCon $mod */
|
35 |
+
$mod = $this->getMod();
|
36 |
+
return !$mod->isVerifiedBot();
|
37 |
+
}
|
38 |
+
|
39 |
+
protected function run() {
|
40 |
+
add_action( $this->getCon()->prefix( 'event' ), function ( $event ) {
|
41 |
+
$this->fireEventForIP( Services::IP()->getRequestIp(), $event );
|
42 |
+
} );
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* @return string[]
|
47 |
+
*/
|
48 |
+
private function getEventsToColumn() :array {
|
49 |
+
return array_map(
|
50 |
+
function ( $column ) {
|
51 |
+
return str_replace( '_at', '', $column ).'_at';
|
52 |
+
},
|
53 |
+
[
|
54 |
+
'bottrack_notbot' => 'notbot',
|
55 |
+
'frontpage_load' => 'frontpage',
|
56 |
+
'bottrack_404' => 'bt404',
|
57 |
+
'bottrack_fakewebcrawler' => 'btfake',
|
58 |
+
'bottrack_linkcheese' => 'btcheese',
|
59 |
+
'bottrack_loginfailed' => 'btloginfail',
|
60 |
+
'bottrack_useragent' => 'btua',
|
61 |
+
'bottrack_xmlrpc' => 'btxml',
|
62 |
+
'bottrack_logininvalid' => 'btlogininvalid',
|
63 |
+
'bottrack_invalidscript' => 'btinvalidscript',
|
64 |
+
'cooldown_fail' => 'cooldown',
|
65 |
+
'recaptcha_success' => 'captchapass',
|
66 |
+
'request_limit_exceeded' => 'ratelimit',
|
67 |
+
'recaptcha_fail' => 'captchafail',
|
68 |
+
'spam_block_human' => 'humanspam',
|
69 |
+
'comment_markspam' => 'markspam',
|
70 |
+
'comment_unmarkspam' => 'unmarkspam',
|
71 |
+
'blockparam_.*' => 'firewall',
|
72 |
+
'ip_offense' => 'offense',
|
73 |
+
'ip_blocked' => 'blocked',
|
74 |
+
'ip_unblock' => 'unblocked',
|
75 |
+
'ip_bypass' => 'bypass',
|
76 |
+
'login_success' => 'auth',
|
77 |
+
]
|
78 |
+
);
|
79 |
+
}
|
80 |
+
}
|
src/lib/src/Modules/IPs/Lib/Bots/NotBot/InsertNotBotJs.php
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
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 |
+
}
|
16 |
+
|
17 |
+
protected function enqueueJS() {
|
18 |
+
add_filter( 'shield/custom_enqueues', function ( array $enqueues ) {
|
19 |
+
$enqueues[ Enqueue::JS ][] = 'shield/antibot';
|
20 |
+
return $enqueues;
|
21 |
+
} );
|
22 |
+
}
|
23 |
+
|
24 |
+
private function nonceJs() {
|
25 |
+
add_filter( 'shield/custom_localisations', function ( array $localz ) {
|
26 |
+
|
27 |
+
$ajaxData = $this->getMod()->getAjaxActionData( 'not_bot' );
|
28 |
+
$ajaxHref = $ajaxData[ 'ajaxurl' ];
|
29 |
+
unset( $ajaxData[ 'ajaxurl' ] );
|
30 |
+
|
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 |
+
} );
|
45 |
+
}
|
46 |
+
}
|
src/lib/src/Modules/IPs/Lib/Bots/NotBot/NotBotHandler.php
ADDED
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
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 );
|
21 |
+
}
|
22 |
+
|
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()
|
38 |
+
->getEventListener()
|
39 |
+
->fireEventForIP( Services::IP()->getRequestIp(), 'frontpage_load' );
|
40 |
+
}
|
41 |
+
} );
|
42 |
+
}
|
43 |
+
|
44 |
+
private function maybeDeleteCookie() {
|
45 |
+
$cookie = $this->getCookieParts();
|
46 |
+
if ( !empty( $cookie ) && $cookie[ 'ts' ] - Services::Request()->ts() < 300 ) {
|
47 |
+
$this->clearCookie();
|
48 |
+
}
|
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 |
+
}
|
61 |
+
|
62 |
+
public function clearCookie() :bool {
|
63 |
+
Services::Response()->cookieSet(
|
64 |
+
$this->getMod()->prefix( self::SLUG ),
|
65 |
+
'',
|
66 |
+
-self::LIFETIME
|
67 |
+
);
|
68 |
+
return true;
|
69 |
+
}
|
70 |
+
|
71 |
+
public function hasCookie() :bool {
|
72 |
+
$cookie = $this->getCookieParts();
|
73 |
+
return !empty( $cookie )
|
74 |
+
&& ( Services::Request()->ts() < $cookie[ 'ts' ] )
|
75 |
+
&& hash_equals( $this->getHashForVisitorTS( (int)$cookie[ 'ts' ] ), $cookie[ 'hash' ] );
|
76 |
+
}
|
77 |
+
|
78 |
+
protected function getHashForVisitorTS( int $timestamp ) {
|
79 |
+
return hash_hmac( 'sha1',
|
80 |
+
$timestamp.(string)Services::IP()->getRequestIp(),
|
81 |
+
$this->getCon()->getSiteInstallationId()
|
82 |
+
);
|
83 |
+
}
|
84 |
+
|
85 |
+
private function getCookieParts() :array {
|
86 |
+
$parts = [];
|
87 |
+
$req = Services::Request();
|
88 |
+
$notBot = $req->cookie( $this->getMod()->prefix( self::SLUG ), '' );
|
89 |
+
if ( !empty( $notBot ) && strpos( $notBot, 'z' ) ) {
|
90 |
+
list( $ts, $hash ) = explode( 'z', $notBot );
|
91 |
+
$parts[ 'ts' ] = $ts;
|
92 |
+
$parts[ 'hash' ] = $hash;
|
93 |
+
}
|
94 |
+
return $parts;
|
95 |
+
}
|
96 |
+
}
|
src/lib/src/Modules/IPs/Lib/IpAnalyse/BuildDisplay.php
CHANGED
@@ -3,13 +3,18 @@
|
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\IpAnalyse;
|
4 |
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Databases;
|
|
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\GeoIp\Lookup;
|
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 |
-
use FernleafSystems\Wordpress\Services\Utilities\Net\
|
13 |
|
14 |
class BuildDisplay {
|
15 |
|
@@ -26,7 +31,7 @@ class BuildDisplay {
|
|
26 |
|
27 |
$ip = $this->getIP();
|
28 |
if ( !Services::IP()->isValidIp( $ip ) ) {
|
29 |
-
throw new \Exception( "A valid IP address
|
30 |
}
|
31 |
|
32 |
return $mod->renderTemplate(
|
@@ -34,6 +39,7 @@ class BuildDisplay {
|
|
34 |
[
|
35 |
'strings' => [
|
36 |
'title' => sprintf( __( 'Info For IP Address %s', 'wp-simple-firewall' ), $ip ),
|
|
|
37 |
'nav_general' => __( 'General Info', 'wp-simple-firewall' ),
|
38 |
'nav_sessions' => __( 'User Sessions', 'wp-simple-firewall' ),
|
39 |
'nav_audit' => __( 'Audit Trail', 'wp-simple-firewall' ),
|
@@ -44,6 +50,7 @@ class BuildDisplay {
|
|
44 |
],
|
45 |
'content' => [
|
46 |
'general' => $this->renderForGeneral(),
|
|
|
47 |
'sessions' => $this->renderForSessions(),
|
48 |
'audit_trail' => $this->renderForAuditTrail(),
|
49 |
'traffic' => $this->renderForTraffic(),
|
@@ -55,18 +62,18 @@ class BuildDisplay {
|
|
55 |
|
56 |
private function renderForGeneral() :string {
|
57 |
$con = $this->getCon();
|
|
|
|
|
58 |
$ip = $this->getIP();
|
59 |
|
60 |
-
$
|
61 |
-
|
62 |
-
$oBlockIP = ( new LookupIpOnList() )
|
63 |
-
->setDbHandler( $dbh )
|
64 |
->setListTypeBlack()
|
65 |
->setIP( $ip )
|
66 |
->lookup( true );
|
67 |
|
68 |
-
$
|
69 |
-
->setDbHandler( $
|
70 |
->setListTypeWhite()
|
71 |
->setIP( $ip )
|
72 |
->lookup( true );
|
@@ -79,28 +86,42 @@ class BuildDisplay {
|
|
79 |
|
80 |
$sRDNS = gethostbyaddr( $ip );
|
81 |
|
82 |
-
$ipIdentifier = new IpIdentify( $ip );
|
83 |
try {
|
84 |
-
$
|
85 |
-
|
86 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
87 |
}
|
88 |
catch ( \Exception $e ) {
|
89 |
-
$
|
90 |
-
$
|
91 |
}
|
92 |
|
93 |
-
if ( $
|
94 |
$ipEntry = ( new LookupIpOnList() )
|
95 |
-
->setDbHandler( $
|
96 |
->setIP( $ip )
|
97 |
->setListTypeWhite()
|
98 |
->lookup();
|
99 |
if ( $ipEntry instanceof Databases\IPs\EntryVO ) {
|
100 |
-
$
|
101 |
}
|
102 |
}
|
103 |
|
|
|
|
|
|
|
|
|
|
|
|
|
104 |
return $this->getMod()->renderTemplate(
|
105 |
'/wpadmin_pages/insights/ips/ip_analyse/ip_general.twig',
|
106 |
[
|
@@ -108,16 +129,18 @@ class BuildDisplay {
|
|
108 |
'title_general' => __( 'Identifying Info', 'wp-simple-firewall' ),
|
109 |
'title_status' => __( 'IP Status', 'wp-simple-firewall' ),
|
110 |
|
111 |
-
'block_ip'
|
112 |
-
'unblock_ip'
|
113 |
-
'bypass_ip'
|
114 |
-
'unbypass_ip'
|
|
|
115 |
|
116 |
'status' => [
|
117 |
-
'is_you'
|
118 |
-
'offenses'
|
119 |
-
'is_blocked'
|
120 |
-
'is_bypass'
|
|
|
121 |
],
|
122 |
|
123 |
'yes' => __( 'Yes', 'wp-simple-firewall' ),
|
@@ -140,13 +163,15 @@ class BuildDisplay {
|
|
140 |
'vars' => [
|
141 |
'ip' => $ip,
|
142 |
'status' => [
|
143 |
-
'is_you'
|
144 |
-
'offenses'
|
145 |
-
'is_blocked'
|
146 |
-
'is_bypass'
|
|
|
|
|
147 |
],
|
148 |
'identity' => [
|
149 |
-
'who_is_it' => $
|
150 |
'rdns' => $sRDNS === $ip ? __( 'Unavailable', 'wp-simple-firewall' ) : $sRDNS,
|
151 |
'country_name' => $validGeo ? $geo->getCountryName() : __( 'Unknown', 'wp-simple-firewall' ),
|
152 |
'timezone' => $validGeo ? $geo->getTimezone() : __( 'Unknown', 'wp-simple-firewall' ),
|
@@ -178,7 +203,7 @@ class BuildDisplay {
|
|
178 |
->query();
|
179 |
|
180 |
foreach ( $sessions as $key => $session ) {
|
181 |
-
$asArray = $session->
|
182 |
$asArray[ 'logged_in_at' ] = $this->formatTimestampField( (int)$session->logged_in_at );
|
183 |
$asArray[ 'last_activity_at' ] = $this->formatTimestampField( (int)$session->last_activity_at );
|
184 |
$asArray[ 'is_sec_admin' ] = $session->secadmin_at > 0;
|
@@ -216,7 +241,7 @@ class BuildDisplay {
|
|
216 |
->query();
|
217 |
|
218 |
foreach ( $requests as $key => $request ) {
|
219 |
-
$asArray = $request->
|
220 |
$asArray[ 'created_at' ] = $this->formatTimestampField( (int)$request->created_at );
|
221 |
if ( strpos( $request->path, '?' ) === false ) {
|
222 |
$request->path .= '?';
|
@@ -249,6 +274,79 @@ class BuildDisplay {
|
|
249 |
);
|
250 |
}
|
251 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
252 |
private function renderForAuditTrail() :string {
|
253 |
$con = $this->getCon();
|
254 |
/** @var Databases\AuditTrail\Select $sel */
|
@@ -259,22 +357,17 @@ class BuildDisplay {
|
|
259 |
$logs = $sel->filterByIp( $this->getIP() )
|
260 |
->query();
|
261 |
|
262 |
-
foreach ( $logs as $key => $
|
263 |
-
$asArray = $
|
264 |
|
265 |
-
$module = $con->getModule( $
|
266 |
if ( empty( $module ) ) {
|
267 |
$module = $con->getModule_AuditTrail();
|
268 |
}
|
269 |
-
$
|
270 |
-
|
271 |
-
$asArray[ 'event' ] =
|
272 |
-
|
273 |
-
implode( "\n", $oStrings->getAuditMessage( $log->event ) ),
|
274 |
-
$log->meta
|
275 |
-
)
|
276 |
-
) );
|
277 |
-
$asArray[ 'created_at' ] = $this->formatTimestampField( (int)$log->created_at );
|
278 |
|
279 |
$logs[ $key ] = $asArray;
|
280 |
}
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\IpAnalyse;
|
4 |
|
5 |
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;
|
14 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Strings;
|
15 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
16 |
use FernleafSystems\Wordpress\Services\Services;
|
17 |
+
use FernleafSystems\Wordpress\Services\Utilities\Net\IpID;
|
18 |
|
19 |
class BuildDisplay {
|
20 |
|
31 |
|
32 |
$ip = $this->getIP();
|
33 |
if ( !Services::IP()->isValidIp( $ip ) ) {
|
34 |
+
throw new \Exception( "A valid IP address wasn't provided." );
|
35 |
}
|
36 |
|
37 |
return $mod->renderTemplate(
|
39 |
[
|
40 |
'strings' => [
|
41 |
'title' => sprintf( __( 'Info For IP Address %s', 'wp-simple-firewall' ), $ip ),
|
42 |
+
'nav_signals' => __( 'Bot Signals', 'wp-simple-firewall' ),
|
43 |
'nav_general' => __( 'General Info', 'wp-simple-firewall' ),
|
44 |
'nav_sessions' => __( 'User Sessions', 'wp-simple-firewall' ),
|
45 |
'nav_audit' => __( 'Audit Trail', 'wp-simple-firewall' ),
|
50 |
],
|
51 |
'content' => [
|
52 |
'general' => $this->renderForGeneral(),
|
53 |
+
'signals' => $this->renderForBotSignals(),
|
54 |
'sessions' => $this->renderForSessions(),
|
55 |
'audit_trail' => $this->renderForAuditTrail(),
|
56 |
'traffic' => $this->renderForTraffic(),
|
62 |
|
63 |
private function renderForGeneral() :string {
|
64 |
$con = $this->getCon();
|
65 |
+
/** @var ModCon $mod */
|
66 |
+
$mod = $this->getMod();
|
67 |
$ip = $this->getIP();
|
68 |
|
69 |
+
$blockIP = ( new LookupIpOnList() )
|
70 |
+
->setDbHandler( $mod->getDbHandler_IPs() )
|
|
|
|
|
71 |
->setListTypeBlack()
|
72 |
->setIP( $ip )
|
73 |
->lookup( true );
|
74 |
|
75 |
+
$bypassIP = ( new LookupIpOnList() )
|
76 |
+
->setDbHandler( $mod->getDbHandler_IPs() )
|
77 |
->setListTypeWhite()
|
78 |
->setIP( $ip )
|
79 |
->lookup( true );
|
86 |
|
87 |
$sRDNS = gethostbyaddr( $ip );
|
88 |
|
|
|
89 |
try {
|
90 |
+
list( $ipKey, $ipName ) = ( new IpID( $ip ) )
|
91 |
+
->setIgnoreUserAgent( true )
|
92 |
+
->run();
|
93 |
+
// We do a "repair" and unblock previously blocked search providers:
|
94 |
+
if ( $blockIP instanceof Databases\IPs\EntryVO
|
95 |
+
&& in_array( $ipKey, Services::ServiceProviders()->getSearchProviders() ) ) {
|
96 |
+
( new DeleteIp() )
|
97 |
+
->setMod( $mod )
|
98 |
+
->setIP( $ip )
|
99 |
+
->fromBlacklist();
|
100 |
+
unset( $blockIP );
|
101 |
+
}
|
102 |
}
|
103 |
catch ( \Exception $e ) {
|
104 |
+
$ipKey = IpID::UNKNOWN;
|
105 |
+
$ipName = 'Unknown';
|
106 |
}
|
107 |
|
108 |
+
if ( $ipKey === IpID::UNKNOWN ) {
|
109 |
$ipEntry = ( new LookupIpOnList() )
|
110 |
+
->setDbHandler( $mod->getDbHandler_IPs() )
|
111 |
->setIP( $ip )
|
112 |
->setListTypeWhite()
|
113 |
->lookup();
|
114 |
if ( $ipEntry instanceof Databases\IPs\EntryVO ) {
|
115 |
+
$ipName = $ipEntry->label;
|
116 |
}
|
117 |
}
|
118 |
|
119 |
+
$botScore = ( new CalculateVisitorBotScores() )
|
120 |
+
->setMod( $mod )
|
121 |
+
->setIP( $ip )
|
122 |
+
->probability();
|
123 |
+
$isBot = $mod->getBotSignalsController()->isBot( $ip, false );
|
124 |
+
|
125 |
return $this->getMod()->renderTemplate(
|
126 |
'/wpadmin_pages/insights/ips/ip_analyse/ip_general.twig',
|
127 |
[
|
129 |
'title_general' => __( 'Identifying Info', 'wp-simple-firewall' ),
|
130 |
'title_status' => __( 'IP Status', 'wp-simple-firewall' ),
|
131 |
|
132 |
+
'block_ip' => __( 'Block IP', 'wp-simple-firewall' ),
|
133 |
+
'unblock_ip' => __( 'Unblock IP', 'wp-simple-firewall' ),
|
134 |
+
'bypass_ip' => __( 'Add IP Bypass', 'wp-simple-firewall' ),
|
135 |
+
'unbypass_ip' => __( 'Remove IP Bypass', 'wp-simple-firewall' ),
|
136 |
+
'delete_notbot' => __( 'Reset For This IP', 'wp-simple-firewall' ),
|
137 |
|
138 |
'status' => [
|
139 |
+
'is_you' => __( 'Is It You?', 'wp-simple-firewall' ),
|
140 |
+
'offenses' => __( 'Number of offenses', 'wp-simple-firewall' ),
|
141 |
+
'is_blocked' => __( 'Is Blocked', 'wp-simple-firewall' ),
|
142 |
+
'is_bypass' => __( 'Is Bypass IP', 'wp-simple-firewall' ),
|
143 |
+
'notbot_score' => __( 'NotBot Score', 'wp-simple-firewall' ),
|
144 |
],
|
145 |
|
146 |
'yes' => __( 'Yes', 'wp-simple-firewall' ),
|
163 |
'vars' => [
|
164 |
'ip' => $ip,
|
165 |
'status' => [
|
166 |
+
'is_you' => Services::IP()->checkIp( $ip, Services::IP()->getRequestIp() ),
|
167 |
+
'offenses' => $blockIP instanceof Databases\IPs\EntryVO ? $blockIP->transgressions : 0,
|
168 |
+
'is_blocked' => $blockIP instanceof Databases\IPs\EntryVO ? $blockIP->blocked_at > 0 : false,
|
169 |
+
'is_bypass' => $bypassIP instanceof Databases\IPs\EntryVO,
|
170 |
+
'notbot_score' => $botScore,
|
171 |
+
'is_bot' => $isBot,
|
172 |
],
|
173 |
'identity' => [
|
174 |
+
'who_is_it' => $ipName,
|
175 |
'rdns' => $sRDNS === $ip ? __( 'Unavailable', 'wp-simple-firewall' ) : $sRDNS,
|
176 |
'country_name' => $validGeo ? $geo->getCountryName() : __( 'Unknown', 'wp-simple-firewall' ),
|
177 |
'timezone' => $validGeo ? $geo->getTimezone() : __( 'Unknown', 'wp-simple-firewall' ),
|
203 |
->query();
|
204 |
|
205 |
foreach ( $sessions as $key => $session ) {
|
206 |
+
$asArray = $session->getRawData();
|
207 |
$asArray[ 'logged_in_at' ] = $this->formatTimestampField( (int)$session->logged_in_at );
|
208 |
$asArray[ 'last_activity_at' ] = $this->formatTimestampField( (int)$session->last_activity_at );
|
209 |
$asArray[ 'is_sec_admin' ] = $session->secadmin_at > 0;
|
241 |
->query();
|
242 |
|
243 |
foreach ( $requests as $key => $request ) {
|
244 |
+
$asArray = $request->getRawData();
|
245 |
$asArray[ 'created_at' ] = $this->formatTimestampField( (int)$request->created_at );
|
246 |
if ( strpos( $request->path, '?' ) === false ) {
|
247 |
$request->path .= '?';
|
274 |
);
|
275 |
}
|
276 |
|
277 |
+
private function renderForBotSignals() :string {
|
278 |
+
/** @var Strings $strings */
|
279 |
+
$strings = $this->getMod()->getStrings();
|
280 |
+
$names = $strings->getBotSignalNames();
|
281 |
+
|
282 |
+
$signals = [];
|
283 |
+
$scores = ( new CalculateVisitorBotScores() )
|
284 |
+
->setMod( $this->getMod() )
|
285 |
+
->setIP( $this->getIP() )
|
286 |
+
->scores();
|
287 |
+
try {
|
288 |
+
$record = ( new BotSignalsRecord() )
|
289 |
+
->setMod( $this->getMod() )
|
290 |
+
->setIP( $this->getIP() )
|
291 |
+
->retrieve();
|
292 |
+
}
|
293 |
+
catch ( \Exception $e ) {
|
294 |
+
$record = null;
|
295 |
+
$signals = [];
|
296 |
+
}
|
297 |
+
|
298 |
+
foreach ( $scores as $scoreKey => $scoreValue ) {
|
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 {
|
306 |
+
$signals[ $scoreKey ] = __( 'Never Recorded', 'wp-simple-firewall' );
|
307 |
+
}
|
308 |
+
}
|
309 |
+
else {
|
310 |
+
$signals[ $scoreKey ] = Services::Request()
|
311 |
+
->carbon()
|
312 |
+
->setTimestamp( $record->{$column} )->diffForHumans();
|
313 |
+
}
|
314 |
+
}
|
315 |
+
}
|
316 |
+
|
317 |
+
return $this->getMod()->renderTemplate(
|
318 |
+
'/wpadmin_pages/insights/ips/ip_analyse/ip_botsignals.twig',
|
319 |
+
[
|
320 |
+
'strings' => [
|
321 |
+
'title' => __( 'Bot Signals', 'wp-simple-firewall' ),
|
322 |
+
'signal' => __( 'Signal', 'wp-simple-firewall' ),
|
323 |
+
'score' => __( 'Score', 'wp-simple-firewall' ),
|
324 |
+
'total_score' => __( 'Total NotBot Score', 'wp-simple-firewall' ),
|
325 |
+
'when' => __( 'When', 'wp-simple-firewall' ),
|
326 |
+
'bot_probability' => __( 'Bot Probability', 'wp-simple-firewall' ),
|
327 |
+
'botsignal_delete' => __( 'Delete All Bot Signals', 'wp-simple-firewall' ),
|
328 |
+
'signal_names' => $names,
|
329 |
+
'no_signals' => __( 'There are no bot signals for this IP address.', 'wp-simple-firewall' ),
|
330 |
+
],
|
331 |
+
'ajax' => [
|
332 |
+
'has_signals' => !empty( $signals ),
|
333 |
+
],
|
334 |
+
'flags' => [
|
335 |
+
'has_signals' => !empty( $signals ),
|
336 |
+
],
|
337 |
+
'vars' => [
|
338 |
+
'signals' => $signals,
|
339 |
+
'total_signals' => count( $signals ),
|
340 |
+
'scores' => $scores,
|
341 |
+
'total_score' => array_sum( $scores ),
|
342 |
+
'minimum' => array_sum( $scores ),
|
343 |
+
'probability' => 100 - (int)max( 0, min( 100, array_sum( $scores ) ) )
|
344 |
+
],
|
345 |
+
],
|
346 |
+
true
|
347 |
+
);
|
348 |
+
}
|
349 |
+
|
350 |
private function renderForAuditTrail() :string {
|
351 |
$con = $this->getCon();
|
352 |
/** @var Databases\AuditTrail\Select $sel */
|
357 |
$logs = $sel->filterByIp( $this->getIP() )
|
358 |
->query();
|
359 |
|
360 |
+
foreach ( $logs as $key => $entry ) {
|
361 |
+
$asArray = $entry->getRawData();
|
362 |
|
363 |
+
$module = $con->getModule( $entry->context );
|
364 |
if ( empty( $module ) ) {
|
365 |
$module = $con->getModule_AuditTrail();
|
366 |
}
|
367 |
+
$strings = $module->getStrings();
|
368 |
+
|
369 |
+
$asArray[ 'event' ] = AuditMessageBuilder::Build( $entry, $strings->getAuditMessage( $entry->event ) );
|
370 |
+
$asArray[ 'created_at' ] = $this->formatTimestampField( (int)$entry->created_at );
|
|
|
|
|
|
|
|
|
|
|
371 |
|
372 |
$logs[ $key ] = $asArray;
|
373 |
}
|
src/lib/src/Modules/IPs/Lib/IpAnalyse/FindAllPluginIps.php
CHANGED
@@ -41,6 +41,13 @@ class FindAllPluginIps {
|
|
41 |
->getQuerySelector();
|
42 |
$ips = array_merge( $ips, $sel->getDistinctForColumn( 'ip' ) );
|
43 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
return IpListSort::Sort( array_unique( $ips ) );
|
45 |
}
|
46 |
}
|
41 |
->getQuerySelector();
|
42 |
$ips = array_merge( $ips, $sel->getDistinctForColumn( 'ip' ) );
|
43 |
|
44 |
+
// Bot Signal
|
45 |
+
/** @var Databases\BotSignals\Select $sel */
|
46 |
+
$sel = $con->getModule_IPs()
|
47 |
+
->getDbHandler_BotSignals()
|
48 |
+
->getQuerySelector();
|
49 |
+
$ips = array_merge( $ips, $sel->getDistinctIps() );
|
50 |
+
|
51 |
return IpListSort::Sort( array_unique( $ips ) );
|
52 |
}
|
53 |
}
|
src/lib/src/Modules/IPs/Lib/Ops/AddIp.php
CHANGED
@@ -23,40 +23,39 @@ class AddIp {
|
|
23 |
public function toAutoBlacklist() {
|
24 |
/** @var ModCon $mod */
|
25 |
$mod = $this->getMod();
|
26 |
-
$
|
27 |
|
28 |
-
$
|
29 |
-
if ( !Services::IP()->isValidIp( $
|
30 |
throw new \Exception( "IP address isn't valid." );
|
31 |
}
|
32 |
-
if ( in_array( $
|
33 |
throw new \Exception( 'Will not black mark our own server IP' );
|
34 |
}
|
35 |
|
36 |
-
$
|
37 |
->setDbHandler( $mod->getDbHandler_IPs() )
|
38 |
->setListTypeBlack()
|
39 |
-
->setIP( $
|
40 |
->lookup( false );
|
41 |
-
if ( !$
|
42 |
-
$
|
43 |
}
|
44 |
|
45 |
// Edge-case: the IP is on the list but the last access long-enough passed
|
46 |
// that it's set to be removed by the cron - the IP is basically expired.
|
47 |
// We just reset the transgressions
|
48 |
-
/** @var Modules\IPs\Options $
|
49 |
-
$
|
50 |
-
if ( $
|
51 |
-
&& ( $oReq->ts() - $oOpts->getAutoExpireTime() > (int)$oIP->last_access_at ) ) {
|
52 |
$mod->getDbHandler_IPs()
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
}
|
59 |
-
return $
|
60 |
}
|
61 |
|
62 |
/**
|
@@ -74,46 +73,46 @@ class AddIp {
|
|
74 |
throw new \Exception( "IP address isn't valid." );
|
75 |
}
|
76 |
|
77 |
-
$
|
78 |
if ( !in_array( $sIP, $oIpServ->getServerPublicIPs() ) ) {
|
79 |
|
80 |
if ( $oIpServ->isValidIpRange( $sIP ) ) {
|
81 |
( new DeleteIp() )
|
82 |
-
->
|
83 |
->setIP( $sIP )
|
84 |
->fromBlacklist();
|
85 |
}
|
86 |
|
87 |
-
$
|
88 |
->setDbHandler( $mod->getDbHandler_IPs() )
|
89 |
->setListTypeBlack()
|
90 |
->setIP( $sIP )
|
91 |
->lookup( false );
|
92 |
|
93 |
-
if ( !$
|
94 |
-
$
|
95 |
}
|
96 |
|
97 |
-
$
|
98 |
'last_access_at' => Services::Request()->ts()
|
99 |
];
|
100 |
|
101 |
-
if ( $
|
102 |
-
$
|
103 |
}
|
104 |
-
if ( $
|
105 |
-
$
|
106 |
}
|
107 |
-
if ( $
|
108 |
-
$
|
109 |
}
|
110 |
|
111 |
$mod->getDbHandler_IPs()
|
112 |
-
|
113 |
-
|
114 |
}
|
115 |
|
116 |
-
return $
|
117 |
}
|
118 |
|
119 |
/**
|
@@ -133,50 +132,51 @@ class AddIp {
|
|
133 |
|
134 |
if ( $oIpServ->isValidIpRange( $ip ) ) {
|
135 |
( new DeleteIp() )
|
136 |
-
->
|
137 |
->setIP( $ip )
|
138 |
->fromWhiteList();
|
139 |
}
|
140 |
|
141 |
-
$
|
142 |
->setDbHandler( $mod->getDbHandler_IPs() )
|
143 |
->setIP( $this->getIP() )
|
144 |
->lookup( false );
|
145 |
-
if ( !$
|
146 |
-
$
|
|
|
147 |
}
|
148 |
|
149 |
-
$
|
150 |
-
if ( $
|
151 |
-
$
|
152 |
}
|
153 |
-
if ( !empty( $label ) && $
|
154 |
-
$
|
155 |
}
|
156 |
-
if ( $
|
157 |
-
$
|
158 |
}
|
159 |
-
if ( $
|
160 |
-
$
|
161 |
}
|
162 |
|
163 |
-
if ( !empty( $
|
164 |
$mod->getDbHandler_IPs()
|
165 |
-
|
166 |
-
|
167 |
}
|
168 |
|
169 |
-
return $
|
170 |
}
|
171 |
|
172 |
/**
|
173 |
-
* @param string $
|
174 |
* @param string $sLabel
|
175 |
* @param int|null $nLastAccessAt
|
176 |
* @return Databases\IPs\EntryVO|null
|
177 |
* @throws \Exception
|
178 |
*/
|
179 |
-
private function add( $
|
180 |
$oIP = null;
|
181 |
|
182 |
/** @var ModCon $mod */
|
@@ -188,7 +188,7 @@ class AddIp {
|
|
188 |
/** @var Databases\IPs\EntryVO $oTempIp */
|
189 |
$oTempIp = $oDbh->getVo();
|
190 |
$oTempIp->ip = $this->getIP();
|
191 |
-
$oTempIp->list = $
|
192 |
$oTempIp->label = empty( $sLabel ) ? __( 'No Label', 'wp-simple-firewall' ) : trim( $sLabel );
|
193 |
if ( is_numeric( $nLastAccessAt ) && $nLastAccessAt > 0 ) {
|
194 |
$oTempIp->last_access_at = $nLastAccessAt;
|
23 |
public function toAutoBlacklist() {
|
24 |
/** @var ModCon $mod */
|
25 |
$mod = $this->getMod();
|
26 |
+
$req = Services::Request();
|
27 |
|
28 |
+
$ip = $this->getIP();
|
29 |
+
if ( !Services::IP()->isValidIp( $ip ) ) {
|
30 |
throw new \Exception( "IP address isn't valid." );
|
31 |
}
|
32 |
+
if ( in_array( $ip, Services::IP()->getServerPublicIPs() ) ) {
|
33 |
throw new \Exception( 'Will not black mark our own server IP' );
|
34 |
}
|
35 |
|
36 |
+
$IP = ( new LookupIpOnList() )
|
37 |
->setDbHandler( $mod->getDbHandler_IPs() )
|
38 |
->setListTypeBlack()
|
39 |
+
->setIP( $ip )
|
40 |
->lookup( false );
|
41 |
+
if ( !$IP instanceof Databases\IPs\EntryVO ) {
|
42 |
+
$IP = $this->add( $mod::LIST_AUTO_BLACK, 'auto', $req->ts() );
|
43 |
}
|
44 |
|
45 |
// Edge-case: the IP is on the list but the last access long-enough passed
|
46 |
// that it's set to be removed by the cron - the IP is basically expired.
|
47 |
// We just reset the transgressions
|
48 |
+
/** @var Modules\IPs\Options $opts */
|
49 |
+
$opts = $this->getOptions();
|
50 |
+
if ( $IP->transgressions > 0 && ( $req->ts() - $opts->getAutoExpireTime() > (int)$IP->last_access_at ) ) {
|
|
|
51 |
$mod->getDbHandler_IPs()
|
52 |
+
->getQueryUpdater()
|
53 |
+
->updateEntry( $IP, [
|
54 |
+
'last_access_at' => Services::Request()->ts(),
|
55 |
+
'transgressions' => 0
|
56 |
+
] );
|
57 |
}
|
58 |
+
return $IP;
|
59 |
}
|
60 |
|
61 |
/**
|
73 |
throw new \Exception( "IP address isn't valid." );
|
74 |
}
|
75 |
|
76 |
+
$IP = null;
|
77 |
if ( !in_array( $sIP, $oIpServ->getServerPublicIPs() ) ) {
|
78 |
|
79 |
if ( $oIpServ->isValidIpRange( $sIP ) ) {
|
80 |
( new DeleteIp() )
|
81 |
+
->setMod( $mod )
|
82 |
->setIP( $sIP )
|
83 |
->fromBlacklist();
|
84 |
}
|
85 |
|
86 |
+
$IP = ( new LookupIpOnList() )
|
87 |
->setDbHandler( $mod->getDbHandler_IPs() )
|
88 |
->setListTypeBlack()
|
89 |
->setIP( $sIP )
|
90 |
->lookup( false );
|
91 |
|
92 |
+
if ( !$IP instanceof Databases\IPs\EntryVO ) {
|
93 |
+
$IP = $this->add( $mod::LIST_MANUAL_BLACK, $sLabel );
|
94 |
}
|
95 |
|
96 |
+
$updateData = [
|
97 |
'last_access_at' => Services::Request()->ts()
|
98 |
];
|
99 |
|
100 |
+
if ( $IP->list != $mod::LIST_MANUAL_BLACK ) {
|
101 |
+
$updateData[ 'list' ] = $mod::LIST_MANUAL_BLACK;
|
102 |
}
|
103 |
+
if ( $IP->label != $sLabel ) {
|
104 |
+
$updateData[ 'label' ] = $sLabel;
|
105 |
}
|
106 |
+
if ( $IP->blocked_at == 0 ) {
|
107 |
+
$updateData[ 'blocked_at' ] = Services::Request()->ts();
|
108 |
}
|
109 |
|
110 |
$mod->getDbHandler_IPs()
|
111 |
+
->getQueryUpdater()
|
112 |
+
->updateEntry( $IP, $updateData );
|
113 |
}
|
114 |
|
115 |
+
return $IP;
|
116 |
}
|
117 |
|
118 |
/**
|
132 |
|
133 |
if ( $oIpServ->isValidIpRange( $ip ) ) {
|
134 |
( new DeleteIp() )
|
135 |
+
->setMod( $mod )
|
136 |
->setIP( $ip )
|
137 |
->fromWhiteList();
|
138 |
}
|
139 |
|
140 |
+
$IP = ( new LookupIpOnList() )
|
141 |
->setDbHandler( $mod->getDbHandler_IPs() )
|
142 |
->setIP( $this->getIP() )
|
143 |
->lookup( false );
|
144 |
+
if ( !$IP instanceof Databases\IPs\EntryVO ) {
|
145 |
+
$this->getCon()->fireEvent( 'ip_bypass' );
|
146 |
+
$IP = $this->add( $mod::LIST_MANUAL_WHITE, $label );
|
147 |
}
|
148 |
|
149 |
+
$updateData = [];
|
150 |
+
if ( $IP->list != $mod::LIST_MANUAL_WHITE ) {
|
151 |
+
$updateData[ 'list' ] = $mod::LIST_MANUAL_WHITE;
|
152 |
}
|
153 |
+
if ( !empty( $label ) && $IP->label != $label ) {
|
154 |
+
$updateData[ 'label' ] = $label;
|
155 |
}
|
156 |
+
if ( $IP->blocked_at > 0 ) {
|
157 |
+
$updateData[ 'blocked_at' ] = 0;
|
158 |
}
|
159 |
+
if ( $IP->transgressions > 0 ) {
|
160 |
+
$updateData[ 'transgressions' ] = 0;
|
161 |
}
|
162 |
|
163 |
+
if ( !empty( $updateData ) ) {
|
164 |
$mod->getDbHandler_IPs()
|
165 |
+
->getQueryUpdater()
|
166 |
+
->updateEntry( $IP, $updateData );
|
167 |
}
|
168 |
|
169 |
+
return $IP;
|
170 |
}
|
171 |
|
172 |
/**
|
173 |
+
* @param string $list
|
174 |
* @param string $sLabel
|
175 |
* @param int|null $nLastAccessAt
|
176 |
* @return Databases\IPs\EntryVO|null
|
177 |
* @throws \Exception
|
178 |
*/
|
179 |
+
private function add( string $list, $sLabel = '', $nLastAccessAt = null ) {
|
180 |
$oIP = null;
|
181 |
|
182 |
/** @var ModCon $mod */
|
188 |
/** @var Databases\IPs\EntryVO $oTempIp */
|
189 |
$oTempIp = $oDbh->getVo();
|
190 |
$oTempIp->ip = $this->getIP();
|
191 |
+
$oTempIp->list = $list;
|
192 |
$oTempIp->label = empty( $sLabel ) ? __( 'No Label', 'wp-simple-firewall' ) : trim( $sLabel );
|
193 |
if ( is_numeric( $nLastAccessAt ) && $nLastAccessAt > 0 ) {
|
194 |
$oTempIp->last_access_at = $nLastAccessAt;
|
src/lib/src/Modules/IPs/Lib/Ops/DeleteIp.php
CHANGED
@@ -6,16 +6,13 @@ use FernleafSystems\Wordpress\Plugin\Shield;
|
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Databases;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
|
8 |
|
9 |
-
/**
|
10 |
-
* Class DeleteIp
|
11 |
-
* @package FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Ops
|
12 |
-
*/
|
13 |
class DeleteIp {
|
14 |
|
15 |
-
use
|
16 |
use IPs\Components\IpAddressConsumer;
|
17 |
|
18 |
public function fromBlacklist() :bool {
|
|
|
19 |
return (bool)$this->getDeleter()
|
20 |
->filterByBlacklist()
|
21 |
->query();
|
@@ -28,9 +25,11 @@ class DeleteIp {
|
|
28 |
}
|
29 |
|
30 |
private function getDeleter() :Databases\IPs\Delete {
|
31 |
-
/** @var
|
32 |
-
$
|
33 |
-
|
34 |
-
|
|
|
|
|
35 |
}
|
36 |
}
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Databases;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
|
8 |
|
|
|
|
|
|
|
|
|
9 |
class DeleteIp {
|
10 |
|
11 |
+
use Shield\Modules\ModConsumer;
|
12 |
use IPs\Components\IpAddressConsumer;
|
13 |
|
14 |
public function fromBlacklist() :bool {
|
15 |
+
$this->getCon()->fireEvent( 'ip_unblock' );
|
16 |
return (bool)$this->getDeleter()
|
17 |
->filterByBlacklist()
|
18 |
->query();
|
25 |
}
|
26 |
|
27 |
private function getDeleter() :Databases\IPs\Delete {
|
28 |
+
/** @var IPs\ModCon $mod */
|
29 |
+
$mod = $this->getMod();
|
30 |
+
/** @var Databases\IPs\Delete $deleter */
|
31 |
+
$deleter = $mod->getDbHandler_IPs()->getQueryDeleter();
|
32 |
+
return $deleter->filterByIp( $this->getIP() )
|
33 |
+
->setLimit( 1 );
|
34 |
}
|
35 |
}
|
src/lib/src/Modules/IPs/Lib/Ops/LookupIpOnList.php
CHANGED
@@ -106,17 +106,34 @@ class LookupIpOnList {
|
|
106 |
}
|
107 |
|
108 |
/**
|
109 |
-
* @param bool $
|
110 |
* @return $this
|
111 |
*/
|
112 |
-
public function setIsIpBlocked( $
|
113 |
-
$this->isBlocked = $
|
114 |
return $this;
|
115 |
}
|
116 |
|
117 |
/**
|
118 |
* @return $this
|
119 |
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
120 |
public function setListTypeBlack() {
|
121 |
$this->listType = 'black';
|
122 |
return $this;
|
@@ -124,6 +141,7 @@ class LookupIpOnList {
|
|
124 |
|
125 |
/**
|
126 |
* @return $this
|
|
|
127 |
*/
|
128 |
public function setListTypeWhite() {
|
129 |
$this->listType = 'white';
|
106 |
}
|
107 |
|
108 |
/**
|
109 |
+
* @param bool $blocked
|
110 |
* @return $this
|
111 |
*/
|
112 |
+
public function setIsIpBlocked( bool $blocked ) {
|
113 |
+
$this->isBlocked = $blocked;
|
114 |
return $this;
|
115 |
}
|
116 |
|
117 |
/**
|
118 |
* @return $this
|
119 |
*/
|
120 |
+
public function setListTypeBlock() {
|
121 |
+
$this->listType = 'black';
|
122 |
+
return $this;
|
123 |
+
}
|
124 |
+
|
125 |
+
/**
|
126 |
+
* @return $this
|
127 |
+
*/
|
128 |
+
public function setListTypeBypass() {
|
129 |
+
$this->listType = 'white';
|
130 |
+
return $this;
|
131 |
+
}
|
132 |
+
|
133 |
+
/**
|
134 |
+
* @return $this
|
135 |
+
* @deprecated 11.0
|
136 |
+
*/
|
137 |
public function setListTypeBlack() {
|
138 |
$this->listType = 'black';
|
139 |
return $this;
|
141 |
|
142 |
/**
|
143 |
* @return $this
|
144 |
+
* @deprecated 11.0
|
145 |
*/
|
146 |
public function setListTypeWhite() {
|
147 |
$this->listType = 'white';
|
src/lib/src/Modules/IPs/Lib/ProcessOffenses.php
CHANGED
@@ -2,6 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib;
|
4 |
|
|
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
7 |
use FernleafSystems\Wordpress\Services\Services;
|
@@ -9,8 +10,13 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
9 |
class ProcessOffenses {
|
10 |
|
11 |
use ModConsumer;
|
|
|
12 |
|
13 |
-
|
|
|
|
|
|
|
|
|
14 |
/** @var IPs\ModCon $mod */
|
15 |
$mod = $this->getMod();
|
16 |
|
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;
|
10 |
class ProcessOffenses {
|
11 |
|
12 |
use ModConsumer;
|
13 |
+
use ExecOnce;
|
14 |
|
15 |
+
protected function canRun() :bool {
|
16 |
+
return !$this->getMod()->isVerifiedBot();
|
17 |
+
}
|
18 |
+
|
19 |
+
protected function run() {
|
20 |
/** @var IPs\ModCon $mod */
|
21 |
$mod = $this->getMod();
|
22 |
|
src/lib/src/Modules/IPs/ModCon.php
CHANGED
@@ -4,6 +4,7 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
|
|
4 |
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
|
|
|
7 |
use FernleafSystems\Wordpress\Services\Services;
|
8 |
|
9 |
class ModCon extends BaseShield\ModCon {
|
@@ -22,6 +23,19 @@ class ModCon extends BaseShield\ModCon {
|
|
22 |
*/
|
23 |
private $oBlacklistHandler;
|
24 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
public function getBlacklistHandler() :Lib\BlacklistHandler {
|
26 |
if ( !isset( $this->oBlacklistHandler ) ) {
|
27 |
$this->oBlacklistHandler = ( new Lib\BlacklistHandler() )->setMod( $this );
|
@@ -29,8 +43,13 @@ class ModCon extends BaseShield\ModCon {
|
|
29 |
return $this->oBlacklistHandler;
|
30 |
}
|
31 |
|
|
|
|
|
|
|
|
|
32 |
public function getDbHandler_IPs() :Shield\Databases\IPs\Handler {
|
33 |
-
|
|
|
34 |
}
|
35 |
|
36 |
/**
|
@@ -45,6 +64,16 @@ class ModCon extends BaseShield\ModCon {
|
|
45 |
&& parent::isReadyToExecute();
|
46 |
}
|
47 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
48 |
protected function preProcessOptions() {
|
49 |
/** @var Options $opts */
|
50 |
$opts = $this->getOptions();
|
4 |
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
|
7 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Utilities\Tool\DbTableExport;
|
8 |
use FernleafSystems\Wordpress\Services\Services;
|
9 |
|
10 |
class ModCon extends BaseShield\ModCon {
|
23 |
*/
|
24 |
private $oBlacklistHandler;
|
25 |
|
26 |
+
/**
|
27 |
+
* @var Lib\Bots\BotSignalsController
|
28 |
+
*/
|
29 |
+
private $botSignalsCon;
|
30 |
+
|
31 |
+
public function getBotSignalsController() :Lib\Bots\BotSignalsController {
|
32 |
+
if ( !isset( $this->botSignalsCon ) ) {
|
33 |
+
$this->botSignalsCon = ( new Lib\Bots\BotSignalsController() )
|
34 |
+
->setMod( $this );
|
35 |
+
}
|
36 |
+
return $this->botSignalsCon;
|
37 |
+
}
|
38 |
+
|
39 |
public function getBlacklistHandler() :Lib\BlacklistHandler {
|
40 |
if ( !isset( $this->oBlacklistHandler ) ) {
|
41 |
$this->oBlacklistHandler = ( new Lib\BlacklistHandler() )->setMod( $this );
|
43 |
return $this->oBlacklistHandler;
|
44 |
}
|
45 |
|
46 |
+
public function getDbHandler_BotSignals() :Shield\Databases\BotSignals\Handler {
|
47 |
+
return $this->getDbH( 'botsignals' );
|
48 |
+
}
|
49 |
+
|
50 |
public function getDbHandler_IPs() :Shield\Databases\IPs\Handler {
|
51 |
+
$new = $this->getDbH( 'ip_lists' );
|
52 |
+
return empty( $new ) ? $this->getDbH( 'ips' ) : $new;
|
53 |
}
|
54 |
|
55 |
/**
|
64 |
&& parent::isReadyToExecute();
|
65 |
}
|
66 |
|
67 |
+
protected function handleFileDownload( string $downloadID ) {
|
68 |
+
switch ( $downloadID ) {
|
69 |
+
case 'db_ip':
|
70 |
+
( new DbTableExport() )
|
71 |
+
->setDbHandler( $this->getDbHandler_IPs() )
|
72 |
+
->toCSV();
|
73 |
+
break;
|
74 |
+
}
|
75 |
+
}
|
76 |
+
|
77 |
protected function preProcessOptions() {
|
78 |
/** @var Options $opts */
|
79 |
$opts = $this->getOptions();
|
src/lib/src/Modules/IPs/Options.php
CHANGED
@@ -69,59 +69,39 @@ class Options extends BaseShield\Options {
|
|
69 |
);
|
70 |
}
|
71 |
|
72 |
-
|
73 |
-
* @return bool
|
74 |
-
*/
|
75 |
-
public function isEnabledAutoBlackList() {
|
76 |
return $this->getOffenseLimit() > 0;
|
77 |
}
|
78 |
|
79 |
-
|
80 |
-
* @return bool
|
81 |
-
*/
|
82 |
-
public function isEnabledAutoVisitorRecover() {
|
83 |
return in_array( 'gasp', (array)$this->getOpt( 'user_auto_recover', [] ) );
|
84 |
}
|
85 |
|
86 |
-
|
87 |
-
* @return bool
|
88 |
-
*/
|
89 |
-
public function isEnabledMagicEmailLinkRecover() {
|
90 |
return in_array( 'email', (array)$this->getOpt( 'user_auto_recover', [] ) );
|
91 |
}
|
92 |
|
93 |
-
|
94 |
-
* @return bool
|
95 |
-
*/
|
96 |
-
public function isEnabledTrack404() {
|
97 |
return $this->isSelectOptionEnabled( 'track_404' );
|
98 |
}
|
99 |
|
100 |
-
|
101 |
-
* @return bool
|
102 |
-
*/
|
103 |
-
public function isEnabledTrackFakeWebCrawler() {
|
104 |
return $this->isSelectOptionEnabled( 'track_fakewebcrawler' );
|
105 |
}
|
106 |
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
|
|
111 |
return $this->isSelectOptionEnabled( 'track_logininvalid' );
|
112 |
}
|
113 |
|
114 |
-
|
115 |
-
* @return bool
|
116 |
-
*/
|
117 |
-
public function isEnabledTrackLoginFailed() {
|
118 |
return $this->isSelectOptionEnabled( 'track_loginfailed' );
|
119 |
}
|
120 |
|
121 |
-
|
122 |
-
* @return bool
|
123 |
-
*/
|
124 |
-
public function isEnabledTrackLinkCheese() {
|
125 |
return $this->isSelectOptionEnabled( 'track_linkcheese' );
|
126 |
}
|
127 |
|
@@ -156,11 +136,7 @@ class Options extends BaseShield\Options {
|
|
156 |
return $this->isOpt( $key, 'block' );
|
157 |
}
|
158 |
|
159 |
-
|
160 |
-
* @param string $key
|
161 |
-
* @return bool
|
162 |
-
*/
|
163 |
-
protected function isSelectOptionEnabled( $key ) {
|
164 |
return !$this->isOpt( $key, 'disabled' );
|
165 |
}
|
166 |
}
|
69 |
);
|
70 |
}
|
71 |
|
72 |
+
public function isEnabledAutoBlackList() :bool {
|
|
|
|
|
|
|
73 |
return $this->getOffenseLimit() > 0;
|
74 |
}
|
75 |
|
76 |
+
public function isEnabledAutoVisitorRecover() :bool {
|
|
|
|
|
|
|
77 |
return in_array( 'gasp', (array)$this->getOpt( 'user_auto_recover', [] ) );
|
78 |
}
|
79 |
|
80 |
+
public function isEnabledMagicEmailLinkRecover() :bool {
|
|
|
|
|
|
|
81 |
return in_array( 'email', (array)$this->getOpt( 'user_auto_recover', [] ) );
|
82 |
}
|
83 |
|
84 |
+
public function isEnabledTrack404() :bool {
|
|
|
|
|
|
|
85 |
return $this->isSelectOptionEnabled( 'track_404' );
|
86 |
}
|
87 |
|
88 |
+
public function isEnabledTrackFakeWebCrawler() :bool {
|
|
|
|
|
|
|
89 |
return $this->isSelectOptionEnabled( 'track_fakewebcrawler' );
|
90 |
}
|
91 |
|
92 |
+
public function isEnabledTrackInvalidScript() :bool {
|
93 |
+
return $this->isSelectOptionEnabled( 'track_invalidscript' );
|
94 |
+
}
|
95 |
+
|
96 |
+
public function isEnabledTrackLoginInvalid() :bool {
|
97 |
return $this->isSelectOptionEnabled( 'track_logininvalid' );
|
98 |
}
|
99 |
|
100 |
+
public function isEnabledTrackLoginFailed() :bool {
|
|
|
|
|
|
|
101 |
return $this->isSelectOptionEnabled( 'track_loginfailed' );
|
102 |
}
|
103 |
|
104 |
+
public function isEnabledTrackLinkCheese() :bool {
|
|
|
|
|
|
|
105 |
return $this->isSelectOptionEnabled( 'track_linkcheese' );
|
106 |
}
|
107 |
|
136 |
return $this->isOpt( $key, 'block' );
|
137 |
}
|
138 |
|
139 |
+
protected function isSelectOptionEnabled( string $key ) :bool {
|
|
|
|
|
|
|
|
|
140 |
return !$this->isOpt( $key, 'disabled' );
|
141 |
}
|
142 |
}
|
src/lib/src/Modules/IPs/Processor.php
CHANGED
@@ -10,5 +10,6 @@ class Processor extends BaseShield\Processor {
|
|
10 |
/** @var ModCon $mod */
|
11 |
$mod = $this->getMod();
|
12 |
$mod->getBlacklistHandler()->execute();
|
|
|
13 |
}
|
14 |
}
|
10 |
/** @var ModCon $mod */
|
11 |
$mod = $this->getMod();
|
12 |
$mod->getBlacklistHandler()->execute();
|
13 |
+
$mod->getBotSignalsController()->execute();
|
14 |
}
|
15 |
}
|
src/lib/src/Modules/IPs/Strings.php
CHANGED
@@ -114,15 +114,15 @@ class Strings extends Base\Strings {
|
|
114 |
switch ( $key ) {
|
115 |
|
116 |
case 'enable_ips' :
|
117 |
-
$
|
118 |
-
$
|
119 |
-
$
|
120 |
break;
|
121 |
|
122 |
case 'transgression_limit' :
|
123 |
-
$
|
124 |
-
$
|
125 |
-
$
|
126 |
sprintf( __( 'An offense is registered against an IP address each time a visitor trips the defenses of the %s plugin.', 'wp-simple-firewall' ), $sPlugName ),
|
127 |
__( 'When the number of these offenses exceeds the limit, they are automatically blocked from accessing the site.', 'wp-simple-firewall' ),
|
128 |
sprintf( __( 'Set this to "0" to turn off the %s feature.', 'wp-simple-firewall' ), __( 'Automatic IP Black List', 'wp-simple-firewall' ) )
|
@@ -130,9 +130,9 @@ class Strings extends Base\Strings {
|
|
130 |
break;
|
131 |
|
132 |
case 'auto_expire' :
|
133 |
-
$
|
134 |
-
$
|
135 |
-
$
|
136 |
__( 'Blocked IP addresses are eventually removed.', 'wp-simple-firewall' )
|
137 |
.'<br/>'.__( 'This option lets you specify how long they should be kept.', 'wp-simple-firewall' ),
|
138 |
__( 'Large, permanent IP Block Lists will degrade site performance.', 'wp-simple-firewall' ),
|
@@ -141,74 +141,98 @@ class Strings extends Base\Strings {
|
|
141 |
break;
|
142 |
|
143 |
case 'user_auto_recover' :
|
144 |
-
$
|
145 |
-
$
|
146 |
-
$
|
147 |
break;
|
148 |
|
149 |
case 'request_whitelist' :
|
150 |
-
$
|
151 |
-
$
|
152 |
-
$
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
|
159 |
break;
|
160 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
161 |
case 'text_loginfailed' :
|
162 |
-
$
|
163 |
-
$
|
164 |
-
$
|
165 |
break;
|
166 |
|
167 |
case 'text_remainingtrans' :
|
168 |
-
$
|
169 |
-
$
|
170 |
-
$
|
171 |
break;
|
172 |
|
173 |
case 'track_404' :
|
174 |
-
$
|
175 |
-
$
|
176 |
-
$
|
177 |
-
|
178 |
break;
|
179 |
|
180 |
case 'track_xmlrpc' :
|
181 |
-
$
|
182 |
-
$
|
183 |
-
$
|
184 |
-
|
185 |
-
|
186 |
break;
|
187 |
|
188 |
case 'track_linkcheese' :
|
189 |
-
$
|
190 |
-
$
|
191 |
-
$
|
192 |
-
|
193 |
break;
|
194 |
|
195 |
case 'track_logininvalid' :
|
196 |
-
$
|
197 |
-
$
|
198 |
-
$
|
199 |
-
|
200 |
break;
|
201 |
|
202 |
case 'track_loginfailed' :
|
203 |
-
$
|
204 |
-
$
|
205 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
206 |
break;
|
207 |
|
208 |
case 'track_fakewebcrawler' :
|
209 |
-
$
|
210 |
-
$
|
211 |
-
$
|
212 |
__( "Identify a visitor as a Bot when it presents as an official web crawler, but analysis shows it's fake.", 'wp-simple-firewall' ),
|
213 |
__( "Many bots pretend to be a Google Bot.", 'wp-simple-firewall' )
|
214 |
.'<br/>'.__( "We can then know that a bot isn't here for anything good and block them.", 'wp-simple-firewall' ),
|
@@ -216,9 +240,9 @@ class Strings extends Base\Strings {
|
|
216 |
break;
|
217 |
|
218 |
case 'track_useragent' :
|
219 |
-
$
|
220 |
-
$
|
221 |
-
$
|
222 |
__( "Identify a bot when the user agent is not provided.", 'wp-simple-firewall' ),
|
223 |
sprintf( '%s:<br/><code>%s</code>',
|
224 |
__( 'For example, your browser user agent is', 'wp-simple-firewall' ), Services::Request()
|
@@ -231,9 +255,45 @@ class Strings extends Base\Strings {
|
|
231 |
}
|
232 |
|
233 |
return [
|
234 |
-
'name' => $
|
235 |
-
'summary' => $
|
236 |
-
'description' => $
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
237 |
];
|
238 |
}
|
239 |
|
@@ -265,7 +325,8 @@ class Strings extends Base\Strings {
|
|
265 |
__( '404 detected at "%s".', 'wp-simple-firewall' )
|
266 |
],
|
267 |
'bottrack_fakewebcrawler' => [
|
268 |
-
__( 'Fake Web Crawler detected at "%s".', 'wp-simple-firewall' )
|
|
|
269 |
],
|
270 |
'bottrack_linkcheese' => [
|
271 |
__( 'Link cheese access detected at "%s".', 'wp-simple-firewall' )
|
@@ -282,6 +343,9 @@ class Strings extends Base\Strings {
|
|
282 |
'bottrack_xmlrpc' => [
|
283 |
__( 'Access to XML-RPC detected at "%s".', 'wp-simple-firewall' )
|
284 |
],
|
|
|
|
|
|
|
285 |
];
|
286 |
}
|
287 |
}
|
114 |
switch ( $key ) {
|
115 |
|
116 |
case 'enable_ips' :
|
117 |
+
$name = sprintf( __( 'Enable %s Module', 'wp-simple-firewall' ), $sModName );
|
118 |
+
$summary = sprintf( __( 'Enable (or Disable) The %s Module', 'wp-simple-firewall' ), $sModName );
|
119 |
+
$desc = sprintf( __( 'Un-Checking this option will completely disable the %s module.', 'wp-simple-firewall' ), $sModName );
|
120 |
break;
|
121 |
|
122 |
case 'transgression_limit' :
|
123 |
+
$name = __( 'Offense Limit', 'wp-simple-firewall' );
|
124 |
+
$summary = __( 'Visitor IP address will be Black Listed after X bad actions on your site', 'wp-simple-firewall' );
|
125 |
+
$desc = [
|
126 |
sprintf( __( 'An offense is registered against an IP address each time a visitor trips the defenses of the %s plugin.', 'wp-simple-firewall' ), $sPlugName ),
|
127 |
__( 'When the number of these offenses exceeds the limit, they are automatically blocked from accessing the site.', 'wp-simple-firewall' ),
|
128 |
sprintf( __( 'Set this to "0" to turn off the %s feature.', 'wp-simple-firewall' ), __( 'Automatic IP Black List', 'wp-simple-firewall' ) )
|
130 |
break;
|
131 |
|
132 |
case 'auto_expire' :
|
133 |
+
$name = __( 'Auto Block Expiration', 'wp-simple-firewall' );
|
134 |
+
$summary = __( 'After 1 "X" a black listed IP will be removed from the black list', 'wp-simple-firewall' );
|
135 |
+
$desc = [
|
136 |
__( 'Blocked IP addresses are eventually removed.', 'wp-simple-firewall' )
|
137 |
.'<br/>'.__( 'This option lets you specify how long they should be kept.', 'wp-simple-firewall' ),
|
138 |
__( 'Large, permanent IP Block Lists will degrade site performance.', 'wp-simple-firewall' ),
|
141 |
break;
|
142 |
|
143 |
case 'user_auto_recover' :
|
144 |
+
$name = __( 'User Auto Unblock', 'wp-simple-firewall' );
|
145 |
+
$summary = __( 'Allow Visitors To Unblock Their IP', 'wp-simple-firewall' );
|
146 |
+
$desc = __( 'Allow visitors blocked by the plugin to automatically unblock themselves.', 'wp-simple-firewall' );
|
147 |
break;
|
148 |
|
149 |
case 'request_whitelist' :
|
150 |
+
$name = __( 'Request Path Whitelist', 'wp-simple-firewall' );
|
151 |
+
$summary = __( 'Request Path Whitelist', 'wp-simple-firewall' );
|
152 |
+
$desc = __( 'A list of request paths that will never trigger an offense.', 'wp-simple-firewall' )
|
153 |
+
.'<br />- '.__( 'This is an advanced option and should be used with great care.', 'wp-simple-firewall' )
|
154 |
+
.'<br />- '.__( 'Take a new line for each whitelisted path.', 'wp-simple-firewall' )
|
155 |
+
.'<br />- '.__( "All characters will be treated as case-insensitive.", 'wp-simple-firewall' )
|
156 |
+
.'<br />- '.__( "The paths are compared against only the request path, not the query portion.", 'wp-simple-firewall' )
|
157 |
+
.'<br />- '.__( "If a path you add matches your website root (/), it'll be removed automatically.", 'wp-simple-firewall' );
|
158 |
|
159 |
break;
|
160 |
|
161 |
+
case 'antibot_minimum' :
|
162 |
+
$name = __( 'AntiBot Minimum Score', 'wp-simple-firewall' );
|
163 |
+
$summary = __( 'AntiBot Minimum Score (Percentage)', 'wp-simple-firewall' );
|
164 |
+
$desc = [
|
165 |
+
__( "Every IP address accessing your site gets its own unique visitor score - the higher the score, the better the visitor i.e. the more likely it's human.", 'wp-simple-firewall' ),
|
166 |
+
__( "A score of '100' would mean it's almost certainly good, a score of '0' means it's highly likely to be a bad bot.", 'wp-simple-firewall' ),
|
167 |
+
__( 'When a bot tries to login, or post a comment, we test its visitor score.', 'wp-simple-firewall' )
|
168 |
+
.' '.__( 'If the visitor score fails to meet your Minimum AntiBot Score, we prevent the request. If its higher, we allow it.', 'wp-simple-firewall' ),
|
169 |
+
__( "This means: choose a higher minimum score to be more strict and capture more bots (but potentially block someone that appears to be a bot, but isn't).", 'wp-simple-firewall' )
|
170 |
+
.' '.__( "Or choose a lower minimum score to perhaps allow through more bots (but reduce the chances of accidentally blocking legitimate visitors).", 'wp-simple-firewall' ),
|
171 |
+
];
|
172 |
+
break;
|
173 |
+
|
174 |
case 'text_loginfailed' :
|
175 |
+
$name = __( 'Login Failed', 'wp-simple-firewall' );
|
176 |
+
$summary = __( 'Visitor Triggers The IP Offense System Through A Failed Login', 'wp-simple-firewall' );
|
177 |
+
$desc = __( 'This message is displayed if the visitor fails a login attempt.', 'wp-simple-firewall' );
|
178 |
break;
|
179 |
|
180 |
case 'text_remainingtrans' :
|
181 |
+
$name = __( 'Remaining Offenses', 'wp-simple-firewall' );
|
182 |
+
$summary = __( 'Visitor Triggers The IP Offenses System Through A Firewall Block', 'wp-simple-firewall' );
|
183 |
+
$desc = __( 'This message is displayed if the visitor triggered the IP Offense system and reports how many offenses remain before being blocked.', 'wp-simple-firewall' );
|
184 |
break;
|
185 |
|
186 |
case 'track_404' :
|
187 |
+
$name = __( '404 Detect', 'wp-simple-firewall' );
|
188 |
+
$summary = __( 'Identify A Bot When It Hits A 404', 'wp-simple-firewall' );
|
189 |
+
$desc = __( "Detect when a visitor tries to load a non-existent page.", 'wp-simple-firewall' )
|
190 |
+
.'<br/>'.__( "Care should be taken to ensure you don't have legitimate links on your site that are 404s.", 'wp-simple-firewall' );
|
191 |
break;
|
192 |
|
193 |
case 'track_xmlrpc' :
|
194 |
+
$name = __( 'XML-RPC Access', 'wp-simple-firewall' );
|
195 |
+
$summary = __( 'Identify A Bot When It Accesses XML-RPC', 'wp-simple-firewall' );
|
196 |
+
$desc = __( "If you don't use XML-RPC, there's no reason anything should be accessing it.", 'wp-simple-firewall' )
|
197 |
+
.'<br/>'.__( "Be careful the ensure you don't block legitimate XML-RPC traffic if your site needs it.", 'wp-simple-firewall' )
|
198 |
+
.'<br/>'.__( "We recommend logging here in-case of blocking valid request unless you're sure.", 'wp-simple-firewall' );
|
199 |
break;
|
200 |
|
201 |
case 'track_linkcheese' :
|
202 |
+
$name = __( 'Link Cheese', 'wp-simple-firewall' );
|
203 |
+
$summary = __( 'Tempt A Bot With A Fake Link To Follow', 'wp-simple-firewall' );
|
204 |
+
$desc = __( "Detect a bot when it follows a fake 'no-follow' link.", 'wp-simple-firewall' )
|
205 |
+
.'<br/>'.__( "This works because legitimate web crawlers respect 'robots.txt' and 'nofollow' directives.", 'wp-simple-firewall' );
|
206 |
break;
|
207 |
|
208 |
case 'track_logininvalid' :
|
209 |
+
$name = __( 'Invalid Usernames', 'wp-simple-firewall' );
|
210 |
+
$summary = __( "Detect Attempted Logins With Usernames That Don't Exist", 'wp-simple-firewall' );
|
211 |
+
$desc = __( "Identify a Bot when it tries to login with a non-existent username.", 'wp-simple-firewall' )
|
212 |
+
.'<br/>'.__( "This includes the default 'admin' if you've removed that account.", 'wp-simple-firewall' );
|
213 |
break;
|
214 |
|
215 |
case 'track_loginfailed' :
|
216 |
+
$name = __( 'Failed Login', 'wp-simple-firewall' );
|
217 |
+
$summary = __( 'Detect Failed Login Attempts For Users That Exist', 'wp-simple-firewall' );
|
218 |
+
$desc = __( "Penalise a visitor when they try to login using a valid username, but it fails.", 'wp-simple-firewall' );
|
219 |
+
break;
|
220 |
+
|
221 |
+
case 'track_invalidscript' :
|
222 |
+
$name = __( 'Invalid Script Load', 'wp-simple-firewall' );
|
223 |
+
$summary = __( 'Identify Bot Attempts To Load WordPress In A Non-Standard Way', 'wp-simple-firewall' );
|
224 |
+
$desc = [
|
225 |
+
__( "Detect when a bot tries to load WordPress directly from a file that isn't normally used to load WordPress.", 'wp-simple-firewall' ),
|
226 |
+
__( 'WordPress should only be loaded in a limited number of ways.', 'wp-simple-firewall' ),
|
227 |
+
sprintf( '%s - %s', __( 'Recommendation', 'wp-simple-firewall' ),
|
228 |
+
sprintf( __( 'Set this option to "%s" and monitor the Audit Trail, since some plugins, themes, or custom integrations may trigger this.', 'wp-simple-firewall' ), __( 'Audit Log Only', 'wp-simple-firewall' ) ) )
|
229 |
+
];
|
230 |
break;
|
231 |
|
232 |
case 'track_fakewebcrawler' :
|
233 |
+
$name = __( 'Fake Web Crawler', 'wp-simple-firewall' );
|
234 |
+
$summary = __( 'Detect Fake Search Engine Crawlers', 'wp-simple-firewall' );
|
235 |
+
$desc = [
|
236 |
__( "Identify a visitor as a Bot when it presents as an official web crawler, but analysis shows it's fake.", 'wp-simple-firewall' ),
|
237 |
__( "Many bots pretend to be a Google Bot.", 'wp-simple-firewall' )
|
238 |
.'<br/>'.__( "We can then know that a bot isn't here for anything good and block them.", 'wp-simple-firewall' ),
|
240 |
break;
|
241 |
|
242 |
case 'track_useragent' :
|
243 |
+
$name = __( 'Empty User Agents', 'wp-simple-firewall' );
|
244 |
+
$summary = __( 'Detect Requests With Empty User Agents', 'wp-simple-firewall' );
|
245 |
+
$desc = [
|
246 |
__( "Identify a bot when the user agent is not provided.", 'wp-simple-firewall' ),
|
247 |
sprintf( '%s:<br/><code>%s</code>',
|
248 |
__( 'For example, your browser user agent is', 'wp-simple-firewall' ), Services::Request()
|
255 |
}
|
256 |
|
257 |
return [
|
258 |
+
'name' => $name,
|
259 |
+
'summary' => $summary,
|
260 |
+
'description' => $desc,
|
261 |
+
];
|
262 |
+
}
|
263 |
+
|
264 |
+
public function getBotSignalName( $field ) :string {
|
265 |
+
return $this->getBotSignalNames()[ str_replace( '_at', '', $field ) ] ?? 'Unknown';
|
266 |
+
}
|
267 |
+
|
268 |
+
/**
|
269 |
+
* @return string[]
|
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' ),
|
279 |
+
'btloginfail' => __( 'Login Fail', 'wp-simple-firewall' ),
|
280 |
+
'btua' => __( 'Invalid User Agent', 'wp-simple-firewall' ),
|
281 |
+
'btxml' => __( 'XMLRPC Access', 'wp-simple-firewall' ),
|
282 |
+
'btlogininvalid' => __( 'Invalid Login Username', 'wp-simple-firewall' ),
|
283 |
+
'btinvalidscript' => __( 'Invalid Script Access', 'wp-simple-firewall' ),
|
284 |
+
'cooldown' => __( 'Cooldown Triggered', 'wp-simple-firewall' ),
|
285 |
+
'humanspam' => __( 'Comment Triggered Human SPAM Detection', 'wp-simple-firewall' ),
|
286 |
+
'markspam' => __( 'Comment Marked As SPAM', 'wp-simple-firewall' ),
|
287 |
+
'unmarkspam' => __( 'Comment Unmarked As SPAM', 'wp-simple-firewall' ),
|
288 |
+
'auth' => __( 'Authenticated With Site', 'wp-simple-firewall' ),
|
289 |
+
'ratelimit' => __( 'Rate Limit Exceeded', 'wp-simple-firewall' ),
|
290 |
+
'captchapass' => __( 'Captcha Verification Passed', 'wp-simple-firewall' ),
|
291 |
+
'captchafail' => __( 'Captcha Verification Failed', 'wp-simple-firewall' ),
|
292 |
+
'firewall' => __( 'Firewall Triggered', 'wp-simple-firewall' ),
|
293 |
+
'offense' => __( 'Offense Triggered', 'wp-simple-firewall' ),
|
294 |
+
'blocked' => __( 'IP Blocked', 'wp-simple-firewall' ),
|
295 |
+
'unblocked' => __( 'IP Unblocked', 'wp-simple-firewall' ),
|
296 |
+
'bypass' => __( 'IP Bypassed', 'wp-simple-firewall' ),
|
297 |
];
|
298 |
}
|
299 |
|
325 |
__( '404 detected at "%s".', 'wp-simple-firewall' )
|
326 |
],
|
327 |
'bottrack_fakewebcrawler' => [
|
328 |
+
__( 'Fake Web Crawler detected at "%s".', 'wp-simple-firewall' ),
|
329 |
+
__( 'Fake Crawler misrepresented itself as "%s".', 'wp-simple-firewall' ),
|
330 |
],
|
331 |
'bottrack_linkcheese' => [
|
332 |
__( 'Link cheese access detected at "%s".', 'wp-simple-firewall' )
|
343 |
'bottrack_xmlrpc' => [
|
344 |
__( 'Access to XML-RPC detected at "%s".', 'wp-simple-firewall' )
|
345 |
],
|
346 |
+
'bottrack_invalidscript' => [
|
347 |
+
__( 'Tried to load an invalid WordPress PHP script "%s".', 'wp-simple-firewall' )
|
348 |
+
],
|
349 |
];
|
350 |
}
|
351 |
}
|
src/lib/src/Modules/IPs/UI.php
CHANGED
@@ -66,6 +66,11 @@ class UI extends BaseShield\UI {
|
|
66 |
'href' => $mod->getUrl_AdminPage(),
|
67 |
'title' => __( 'IP Block Settings', 'wp-simple-firewall' ),
|
68 |
],
|
|
|
|
|
|
|
|
|
|
|
69 |
],
|
70 |
'unique_ips_black' => ( new RetrieveIpsForLists() )
|
71 |
->setDbHandler( $mod->getDbHandler_IPs() )
|
66 |
'href' => $mod->getUrl_AdminPage(),
|
67 |
'title' => __( 'IP Block Settings', 'wp-simple-firewall' ),
|
68 |
],
|
69 |
+
[
|
70 |
+
'href' => $mod->createFileDownloadLink( 'db_ip' ),
|
71 |
+
'classes' => [ 'shield_file_download' ],
|
72 |
+
'title' => sprintf( __( 'Download (as %s)', 'wp-simple-firewall' ), 'CSV' ),
|
73 |
+
],
|
74 |
],
|
75 |
'unique_ips_black' => ( new RetrieveIpsForLists() )
|
76 |
->setDbHandler( $mod->getDbHandler_IPs() )
|
src/lib/src/Modules/IPs/Upgrade.php
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
|
4 |
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs;
|
4 |
|
src/lib/src/Modules/IPs/WpCli/BaseAddRemove.php
CHANGED
@@ -9,7 +9,7 @@ class BaseAddRemove extends BaseWpCliCmd {
|
|
9 |
/**
|
10 |
* @return array[]
|
11 |
*/
|
12 |
-
protected function getCommonIpCmdArgs() {
|
13 |
return [
|
14 |
[
|
15 |
'type' => 'assoc',
|
@@ -22,6 +22,8 @@ class BaseAddRemove extends BaseWpCliCmd {
|
|
22 |
'name' => 'list',
|
23 |
'optional' => false,
|
24 |
'options' => [
|
|
|
|
|
25 |
'white',
|
26 |
'black',
|
27 |
],
|
9 |
/**
|
10 |
* @return array[]
|
11 |
*/
|
12 |
+
protected function getCommonIpCmdArgs() :array {
|
13 |
return [
|
14 |
[
|
15 |
'type' => 'assoc',
|
22 |
'name' => 'list',
|
23 |
'optional' => false,
|
24 |
'options' => [
|
25 |
+
'bypass',
|
26 |
+
'block',
|
27 |
'white',
|
28 |
'black',
|
29 |
],
|
src/lib/src/Modules/IPs/WpCli/Remove.php
CHANGED
@@ -29,7 +29,7 @@ class Remove extends BaseAddRemove {
|
|
29 |
$mod = $this->getMod();
|
30 |
|
31 |
$oDel = ( new IPs\Lib\Ops\DeleteIp() )
|
32 |
-
->
|
33 |
->setIP( $aA[ 'ip' ] );
|
34 |
if ( $aA[ 'list' ] === 'white' ) {
|
35 |
$bSuccess = $oDel->fromWhiteList();
|
29 |
$mod = $this->getMod();
|
30 |
|
31 |
$oDel = ( new IPs\Lib\Ops\DeleteIp() )
|
32 |
+
->setMod( $mod )
|
33 |
->setIP( $aA[ 'ip' ] );
|
34 |
if ( $aA[ 'list' ] === 'white' ) {
|
35 |
$bSuccess = $oDel->fromWhiteList();
|
src/lib/src/Modules/Insights/ModCon.php
CHANGED
@@ -22,8 +22,8 @@ class ModCon extends BaseShield\ModCon {
|
|
22 |
|
23 |
private function maybeRedirectToAdmin() {
|
24 |
$con = $this->getCon();
|
25 |
-
$
|
26 |
-
if ( !Services::WpGeneral()->isAjax() && is_admin() && !$con->isModulePage() && $
|
27 |
Services::Response()->redirect( $this->getUrl_AdminPage() );
|
28 |
}
|
29 |
}
|
@@ -39,7 +39,7 @@ class ModCon extends BaseShield\ModCon {
|
|
39 |
);
|
40 |
}
|
41 |
|
42 |
-
protected function renderModulePage( array $
|
43 |
/** @var UI $UI */
|
44 |
$UI = $this->getUIHandler();
|
45 |
return $UI->renderPages();
|
@@ -79,7 +79,6 @@ class ModCon extends BaseShield\ModCon {
|
|
79 |
$iNav = Services::Request()->query( 'inav' );
|
80 |
|
81 |
if ( $con->getIsPage_PluginAdmin() && !empty( $iNav ) ) {
|
82 |
-
$oTourManager = $con->getModule_Plugin()->getTourManager();
|
83 |
switch ( $iNav ) {
|
84 |
|
85 |
case 'importexport':
|
@@ -87,25 +86,24 @@ class ModCon extends BaseShield\ModCon {
|
|
87 |
break;
|
88 |
|
89 |
case 'overview':
|
90 |
-
case 'reports':
|
91 |
-
|
92 |
$enq[ Enqueue::JS ] = [
|
93 |
-
'chartist.min',
|
94 |
-
'chartist-plugin-legend',
|
95 |
-
'charts',
|
96 |
'shuffle',
|
97 |
-
'shield
|
98 |
'ip_detect'
|
99 |
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
100 |
$enq[ Enqueue::CSS ] = [
|
101 |
-
'chartist
|
102 |
-
'chartist-plugin-legend'
|
|
|
103 |
];
|
104 |
-
|
105 |
-
if ( $oTourManager->canShow( 'insights_overview' ) ) {
|
106 |
-
$enq[ Enqueue::JS ][] = 'introjs.min';
|
107 |
-
$enq[ Enqueue::CSS ][] = 'introjs.min';
|
108 |
-
}
|
109 |
break;
|
110 |
|
111 |
case 'notes':
|
@@ -134,10 +132,4 @@ class ModCon extends BaseShield\ModCon {
|
|
134 |
|
135 |
return $enq;
|
136 |
}
|
137 |
-
|
138 |
-
/**
|
139 |
-
* @deprecated 10.2
|
140 |
-
*/
|
141 |
-
private function includeScriptIpDetect() {
|
142 |
-
}
|
143 |
}
|
22 |
|
23 |
private function maybeRedirectToAdmin() {
|
24 |
$con = $this->getCon();
|
25 |
+
$activeFor = $con->getModule_Plugin()->getActivateLength();
|
26 |
+
if ( !Services::WpGeneral()->isAjax() && is_admin() && !$con->isModulePage() && $activeFor < 4 ) {
|
27 |
Services::Response()->redirect( $this->getUrl_AdminPage() );
|
28 |
}
|
29 |
}
|
39 |
);
|
40 |
}
|
41 |
|
42 |
+
protected function renderModulePage( array $data = [] ) :string {
|
43 |
/** @var UI $UI */
|
44 |
$UI = $this->getUIHandler();
|
45 |
return $UI->renderPages();
|
79 |
$iNav = Services::Request()->query( 'inav' );
|
80 |
|
81 |
if ( $con->getIsPage_PluginAdmin() && !empty( $iNav ) ) {
|
|
|
82 |
switch ( $iNav ) {
|
83 |
|
84 |
case 'importexport':
|
86 |
break;
|
87 |
|
88 |
case 'overview':
|
|
|
|
|
89 |
$enq[ Enqueue::JS ] = [
|
|
|
|
|
|
|
90 |
'shuffle',
|
91 |
+
'shield/shuffle',
|
92 |
'ip_detect'
|
93 |
];
|
94 |
+
break;
|
95 |
+
|
96 |
+
case 'reports':
|
97 |
+
$enq[ Enqueue::JS ] = [
|
98 |
+
'chartist',
|
99 |
+
'chartist-plugin-legend',
|
100 |
+
'shield/charts',
|
101 |
+
];
|
102 |
$enq[ Enqueue::CSS ] = [
|
103 |
+
'chartist',
|
104 |
+
'chartist-plugin-legend',
|
105 |
+
'shield/charts'
|
106 |
];
|
|
|
|
|
|
|
|
|
|
|
107 |
break;
|
108 |
|
109 |
case 'notes':
|
132 |
|
133 |
return $enq;
|
134 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
135 |
}
|
src/lib/src/Modules/Insights/Strings.php
CHANGED
@@ -36,6 +36,7 @@ class Strings extends Base\Strings {
|
|
36 |
'conn_kill' => __( 'Connection killed for blocked IP address', 'wp-simple-firewall' ),
|
37 |
'ip_offense' => __( 'Offense registered against IP address', 'wp-simple-firewall' ),
|
38 |
'ip_blocked' => __( 'IP address blocked after too many offenses', 'wp-simple-firewall' ),
|
|
|
39 |
'spam_block_bot' => __( 'Detected comment SPAM from bot', 'wp-simple-firewall' ),
|
40 |
'spam_block_recaptcha' => __( 'Detected comment SPAM from failed reCAPTCHA', 'wp-simple-firewall' ),
|
41 |
'spam_block_human' => __( 'Detected human comment SPAM with suspicious content', 'wp-simple-firewall' ),
|
@@ -56,12 +57,12 @@ class Strings extends Base\Strings {
|
|
56 |
* @inheritDoc
|
57 |
*/
|
58 |
protected function getAdditionalDisplayStrings() :array {
|
59 |
-
$
|
60 |
return [
|
61 |
-
'page_title' => sprintf( __( '%s Security Insights', 'wp-simple-firewall' ), $
|
62 |
'recommendation' => ucfirst( __( 'recommendation', 'wp-simple-firewall' ) ),
|
63 |
'suggestion' => ucfirst( __( 'suggestion', 'wp-simple-firewall' ) ),
|
64 |
-
'box_welcome_title' => sprintf( __( 'Welcome To %s Security Insights Dashboard', 'wp-simple-firewall' ), $
|
65 |
'options' => __( 'Options', 'wp-simple-firewall' ),
|
66 |
'not_available' => __( 'Sorry, this feature is included with Pro subscriptions.', 'wp-simple-firewall' ),
|
67 |
'not_enabled' => __( "This feature isn't currently enabled.", 'wp-simple-firewall' ),
|
36 |
'conn_kill' => __( 'Connection killed for blocked IP address', 'wp-simple-firewall' ),
|
37 |
'ip_offense' => __( 'Offense registered against IP address', 'wp-simple-firewall' ),
|
38 |
'ip_blocked' => __( 'IP address blocked after too many offenses', 'wp-simple-firewall' ),
|
39 |
+
'spam_block_antibot' => __( 'Detected comment SPAM using AntiBot', 'wp-simple-firewall' ),
|
40 |
'spam_block_bot' => __( 'Detected comment SPAM from bot', 'wp-simple-firewall' ),
|
41 |
'spam_block_recaptcha' => __( 'Detected comment SPAM from failed reCAPTCHA', 'wp-simple-firewall' ),
|
42 |
'spam_block_human' => __( 'Detected human comment SPAM with suspicious content', 'wp-simple-firewall' ),
|
57 |
* @inheritDoc
|
58 |
*/
|
59 |
protected function getAdditionalDisplayStrings() :array {
|
60 |
+
$name = $this->getCon()->getHumanName();
|
61 |
return [
|
62 |
+
'page_title' => sprintf( __( '%s Security Insights', 'wp-simple-firewall' ), $name ),
|
63 |
'recommendation' => ucfirst( __( 'recommendation', 'wp-simple-firewall' ) ),
|
64 |
'suggestion' => ucfirst( __( 'suggestion', 'wp-simple-firewall' ) ),
|
65 |
+
'box_welcome_title' => sprintf( __( 'Welcome To %s Security Insights Dashboard', 'wp-simple-firewall' ), $name ),
|
66 |
'options' => __( 'Options', 'wp-simple-firewall' ),
|
67 |
'not_available' => __( 'Sorry, this feature is included with Pro subscriptions.', 'wp-simple-firewall' ),
|
68 |
'not_enabled' => __( "This feature isn't currently enabled.", 'wp-simple-firewall' ),
|
src/lib/src/Modules/Insights/UI.php
CHANGED
@@ -56,16 +56,13 @@ class UI extends BaseShield\UI {
|
|
56 |
$subNavSection = $req->query( 'subnav' );
|
57 |
|
58 |
$modPlugin = $con->getModule_Plugin();
|
59 |
-
$oTourManager = $modPlugin->getTourManager();
|
60 |
-
if ( !$oTourManager->isCompleted( 'insights_overview' ) && $modPlugin->getActivateLength() > 600 ) {
|
61 |
-
$oTourManager->setCompleted( 'insights_overview' );
|
62 |
-
}
|
63 |
|
64 |
switch ( $sNavSection ) {
|
65 |
|
66 |
case 'audit':
|
|
|
67 |
/** @var Shield\Modules\AuditTrail\UI $auditUI */
|
68 |
-
$auditUI = $
|
69 |
$data = [
|
70 |
'content' => [
|
71 |
'table_audit' => $auditUI->renderAuditTrailTable(),
|
@@ -85,14 +82,20 @@ class UI extends BaseShield\UI {
|
|
85 |
'href' => $mod->getUrl_SubInsightsPage( 'traffic' ),
|
86 |
'title' => __( 'Traffic Log', 'wp-simple-firewall' ),
|
87 |
],
|
|
|
|
|
|
|
|
|
|
|
88 |
]
|
89 |
]
|
90 |
];
|
91 |
break;
|
92 |
|
93 |
case 'traffic':
|
|
|
94 |
/** @var Shield\Modules\Traffic\UI $trafficUI */
|
95 |
-
$trafficUI = $
|
96 |
$data = [
|
97 |
'content' => [
|
98 |
'table_traffic' => $trafficUI->renderTrafficTable(),
|
@@ -107,6 +110,11 @@ class UI extends BaseShield\UI {
|
|
107 |
'href' => $mod->getUrl_SubInsightsPage( 'audit' ),
|
108 |
'title' => __( 'Audit Trail', 'wp-simple-firewall' ),
|
109 |
],
|
|
|
|
|
|
|
|
|
|
|
110 |
]
|
111 |
]
|
112 |
];
|
@@ -231,18 +239,14 @@ class UI extends BaseShield\UI {
|
|
231 |
'page_container' => 'page-insights page-'.$sNavSection
|
232 |
],
|
233 |
'flags' => [
|
234 |
-
'is_dashboard'
|
235 |
-
'
|
236 |
-
'tours' => [
|
237 |
-
'insights_overview' => false && $oTourManager->canShow( 'insights_overview' )
|
238 |
-
],
|
239 |
-
'is_advanced' => $modPlugin->isShowAdvanced()
|
240 |
],
|
241 |
'hrefs' => [
|
242 |
'back_to_dash' => $mod->getUrl_SubInsightsPage( 'dashboard' ),
|
243 |
'go_pro' => 'https://shsec.io/shieldgoprofeature',
|
244 |
'nav_home' => $mod->getUrl_AdminPage(),
|
245 |
-
'img_banner' => $con->
|
246 |
],
|
247 |
'strings' => [
|
248 |
'page_title' => $pageTitle
|
56 |
$subNavSection = $req->query( 'subnav' );
|
57 |
|
58 |
$modPlugin = $con->getModule_Plugin();
|
|
|
|
|
|
|
|
|
59 |
|
60 |
switch ( $sNavSection ) {
|
61 |
|
62 |
case 'audit':
|
63 |
+
$modAudit = $con->getModule_AuditTrail();
|
64 |
/** @var Shield\Modules\AuditTrail\UI $auditUI */
|
65 |
+
$auditUI = $modAudit->getUIHandler();
|
66 |
$data = [
|
67 |
'content' => [
|
68 |
'table_audit' => $auditUI->renderAuditTrailTable(),
|
82 |
'href' => $mod->getUrl_SubInsightsPage( 'traffic' ),
|
83 |
'title' => __( 'Traffic Log', 'wp-simple-firewall' ),
|
84 |
],
|
85 |
+
[
|
86 |
+
'href' => $modAudit->createFileDownloadLink( 'db_audit' ),
|
87 |
+
'classes' => [ 'shield_file_download' ],
|
88 |
+
'title' => sprintf( __( 'Download (as %s)', 'wp-simple-firewall' ), 'CSV' ),
|
89 |
+
],
|
90 |
]
|
91 |
]
|
92 |
];
|
93 |
break;
|
94 |
|
95 |
case 'traffic':
|
96 |
+
$modTraffic = $con->getModule_Traffic();
|
97 |
/** @var Shield\Modules\Traffic\UI $trafficUI */
|
98 |
+
$trafficUI = $modTraffic->getUIHandler();
|
99 |
$data = [
|
100 |
'content' => [
|
101 |
'table_traffic' => $trafficUI->renderTrafficTable(),
|
110 |
'href' => $mod->getUrl_SubInsightsPage( 'audit' ),
|
111 |
'title' => __( 'Audit Trail', 'wp-simple-firewall' ),
|
112 |
],
|
113 |
+
[
|
114 |
+
'href' => $modTraffic->createFileDownloadLink( 'db_traffic' ),
|
115 |
+
'classes' => [ 'shield_file_download' ],
|
116 |
+
'title' => sprintf( __( 'Download (as %s)', 'wp-simple-firewall' ), 'CSV' ),
|
117 |
+
],
|
118 |
]
|
119 |
]
|
120 |
];
|
239 |
'page_container' => 'page-insights page-'.$sNavSection
|
240 |
],
|
241 |
'flags' => [
|
242 |
+
'is_dashboard' => $sNavSection === 'dashboard',
|
243 |
+
'is_advanced' => $modPlugin->isShowAdvanced()
|
|
|
|
|
|
|
|
|
244 |
],
|
245 |
'hrefs' => [
|
246 |
'back_to_dash' => $mod->getUrl_SubInsightsPage( 'dashboard' ),
|
247 |
'go_pro' => 'https://shsec.io/shieldgoprofeature',
|
248 |
'nav_home' => $mod->getUrl_AdminPage(),
|
249 |
+
'img_banner' => $con->urls->forImage( 'pluginlogo_banner-170x40.png' )
|
250 |
],
|
251 |
'strings' => [
|
252 |
'page_title' => $pageTitle
|
src/lib/src/Modules/Integrations/Lib/MainWP/Common/MWPExtensionVO.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Common;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Data\Adapter\
|
6 |
use MainWP\Dashboard\MainWP_Extensions_Handler;
|
7 |
|
8 |
/**
|
@@ -10,29 +10,25 @@ use MainWP\Dashboard\MainWP_Extensions_Handler;
|
|
10 |
* @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Common
|
11 |
* @property string $page - e.g. Extensions-Wp-Simple-Firewall
|
12 |
*/
|
13 |
-
class MWPExtensionVO {
|
14 |
-
|
15 |
-
use StdClassAdapter {
|
16 |
-
__get as __adapterGet;
|
17 |
-
}
|
18 |
|
19 |
/**
|
20 |
-
* @param string $
|
21 |
* @return mixed
|
22 |
*/
|
23 |
-
public function __get( $
|
24 |
|
25 |
-
$
|
26 |
|
27 |
-
switch ( $
|
28 |
case 'official_extension_data':
|
29 |
-
$
|
30 |
break;
|
31 |
default:
|
32 |
break;
|
33 |
}
|
34 |
|
35 |
-
return $
|
36 |
}
|
37 |
|
38 |
private function findOfficialExtensionData() :array {
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Common;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
|
6 |
use MainWP\Dashboard\MainWP_Extensions_Handler;
|
7 |
|
8 |
/**
|
10 |
* @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Common
|
11 |
* @property string $page - e.g. Extensions-Wp-Simple-Firewall
|
12 |
*/
|
13 |
+
class MWPExtensionVO extends DynPropertiesClass {
|
|
|
|
|
|
|
|
|
14 |
|
15 |
/**
|
16 |
+
* @param string $key
|
17 |
* @return mixed
|
18 |
*/
|
19 |
+
public function __get( string $key ) {
|
20 |
|
21 |
+
$value = parent::__get( $key );
|
22 |
|
23 |
+
switch ( $key ) {
|
24 |
case 'official_extension_data':
|
25 |
+
$value = $this->findOfficialExtensionData();
|
26 |
break;
|
27 |
default:
|
28 |
break;
|
29 |
}
|
30 |
|
31 |
+
return $value;
|
32 |
}
|
33 |
|
34 |
private function findOfficialExtensionData() :array {
|
src/lib/src/Modules/Integrations/Lib/MainWP/Common/MWPSiteVO.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Common;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Data\Adapter\
|
6 |
use FernleafSystems\Wordpress\Services\Services;
|
7 |
use MainWP\Dashboard\MainWP_DB;
|
8 |
|
@@ -13,11 +13,7 @@ use MainWP\Dashboard\MainWP_DB;
|
|
13 |
* @property array[] $plugins
|
14 |
* @property array[] $themes
|
15 |
*/
|
16 |
-
class MWPSiteVO {
|
17 |
-
|
18 |
-
use StdClassAdapter {
|
19 |
-
__get as __adapterGet;
|
20 |
-
}
|
21 |
|
22 |
/**
|
23 |
* @param int $siteID
|
@@ -35,25 +31,25 @@ class MWPSiteVO {
|
|
35 |
}
|
36 |
|
37 |
/**
|
38 |
-
* @param string $
|
39 |
* @return mixed
|
40 |
*/
|
41 |
-
public function __get( $
|
42 |
|
43 |
-
$
|
44 |
|
45 |
-
switch ( $
|
46 |
case 'siteobj':
|
47 |
-
$
|
48 |
break;
|
49 |
case 'plugins':
|
50 |
case 'themes':
|
51 |
-
$
|
52 |
break;
|
53 |
default:
|
54 |
break;
|
55 |
}
|
56 |
|
57 |
-
return $
|
58 |
}
|
59 |
}
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Common;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
|
6 |
use FernleafSystems\Wordpress\Services\Services;
|
7 |
use MainWP\Dashboard\MainWP_DB;
|
8 |
|
13 |
* @property array[] $plugins
|
14 |
* @property array[] $themes
|
15 |
*/
|
16 |
+
class MWPSiteVO extends DynPropertiesClass {
|
|
|
|
|
|
|
|
|
17 |
|
18 |
/**
|
19 |
* @param int $siteID
|
31 |
}
|
32 |
|
33 |
/**
|
34 |
+
* @param string $key
|
35 |
* @return mixed
|
36 |
*/
|
37 |
+
public function __get( string $key ) {
|
38 |
|
39 |
+
$value = parent::__get( $key );
|
40 |
|
41 |
+
switch ( $key ) {
|
42 |
case 'siteobj':
|
43 |
+
$value = Services::DataManipulation()->convertArrayToStdClass( $this->getRawData() );
|
44 |
break;
|
45 |
case 'plugins':
|
46 |
case 'themes':
|
47 |
+
$value = json_decode( $value ?? '[]', true );
|
48 |
break;
|
49 |
default:
|
50 |
break;
|
51 |
}
|
52 |
|
53 |
+
return $value;
|
54 |
}
|
55 |
}
|
src/lib/src/Modules/Integrations/Lib/MainWP/Common/MainWPVO.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Common;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Data\Adapter\
|
6 |
use MainWP\Dashboard\MainWP_Extensions_Handler;
|
7 |
|
8 |
/**
|
@@ -15,32 +15,28 @@ use MainWP\Dashboard\MainWP_Extensions_Handler;
|
|
15 |
* @property array $official_extension_data
|
16 |
* @property MWPExtensionVO $extension
|
17 |
*/
|
18 |
-
class MainWPVO {
|
19 |
-
|
20 |
-
use StdClassAdapter {
|
21 |
-
__get as __adapterGet;
|
22 |
-
}
|
23 |
|
24 |
/**
|
25 |
-
* @param string $
|
26 |
* @return mixed
|
27 |
*/
|
28 |
-
public function __get( $
|
29 |
|
30 |
-
$
|
31 |
|
32 |
-
switch ( $
|
33 |
case 'official_extension_data':
|
34 |
-
$
|
35 |
break;
|
36 |
case 'extension':
|
37 |
-
$
|
38 |
break;
|
39 |
default:
|
40 |
break;
|
41 |
}
|
42 |
|
43 |
-
return $
|
44 |
}
|
45 |
|
46 |
private function findOfficialExtensionData() :array {
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Common;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
|
6 |
use MainWP\Dashboard\MainWP_Extensions_Handler;
|
7 |
|
8 |
/**
|
15 |
* @property array $official_extension_data
|
16 |
* @property MWPExtensionVO $extension
|
17 |
*/
|
18 |
+
class MainWPVO extends DynPropertiesClass {
|
|
|
|
|
|
|
|
|
19 |
|
20 |
/**
|
21 |
+
* @param string $key
|
22 |
* @return mixed
|
23 |
*/
|
24 |
+
public function __get( string $key ) {
|
25 |
|
26 |
+
$value = parent::__get( $key );
|
27 |
|
28 |
+
switch ( $key ) {
|
29 |
case 'official_extension_data':
|
30 |
+
$value = $this->findOfficialExtensionData();
|
31 |
break;
|
32 |
case 'extension':
|
33 |
+
$value = ( new MWPExtensionVO() )->applyFromArray( $this->official_extension_data );
|
34 |
break;
|
35 |
default:
|
36 |
break;
|
37 |
}
|
38 |
|
39 |
+
return $value;
|
40 |
}
|
41 |
|
42 |
private function findOfficialExtensionData() :array {
|
src/lib/src/Modules/Integrations/Lib/MainWP/Common/SyncMetaVO.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Common;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Data\Adapter\
|
6 |
|
7 |
/**
|
8 |
* Class SyncVO - property should align with Sync Meta
|
@@ -16,5 +16,5 @@ use FernleafSystems\Utilities\Data\Adapter\StdClassAdapter;
|
|
16 |
*/
|
17 |
class SyncMetaVO {
|
18 |
|
19 |
-
use
|
20 |
}
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Common;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Data\Adapter\DynProperties;
|
6 |
|
7 |
/**
|
8 |
* Class SyncVO - property should align with Sync Meta
|
16 |
*/
|
17 |
class SyncMetaVO {
|
18 |
|
19 |
+
use DynProperties;
|
20 |
}
|
src/lib/src/Modules/Integrations/Lib/MainWP/Common/SyncVO.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Common;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Data\Adapter\
|
6 |
|
7 |
/**
|
8 |
* Class SyncVO
|
@@ -10,21 +10,17 @@ use FernleafSystems\Utilities\Data\Adapter\StdClassAdapter;
|
|
10 |
* @property array[] $modules
|
11 |
* @property SyncMetaVO $meta
|
12 |
*/
|
13 |
-
class SyncVO {
|
14 |
-
|
15 |
-
use StdClassAdapter {
|
16 |
-
__get as __adapterGet;
|
17 |
-
}
|
18 |
|
19 |
/**
|
20 |
-
* @param string $
|
21 |
* @return mixed
|
22 |
*/
|
23 |
-
public function __get( $
|
24 |
|
25 |
-
$mValue =
|
26 |
|
27 |
-
switch ( $
|
28 |
case 'meta':
|
29 |
$mValue = ( new SyncMetaVO() )->applyFromArray( $mValue );
|
30 |
break;
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Common;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
|
6 |
|
7 |
/**
|
8 |
* Class SyncVO
|
10 |
* @property array[] $modules
|
11 |
* @property SyncMetaVO $meta
|
12 |
*/
|
13 |
+
class SyncVO extends DynPropertiesClass {
|
|
|
|
|
|
|
|
|
14 |
|
15 |
/**
|
16 |
+
* @param string $key
|
17 |
* @return mixed
|
18 |
*/
|
19 |
+
public function __get( string $key ) {
|
20 |
|
21 |
+
$mValue = parent::__get( $key );
|
22 |
|
23 |
+
switch ( $key ) {
|
24 |
case 'meta':
|
25 |
$mValue = ( new SyncMetaVO() )->applyFromArray( $mValue );
|
26 |
break;
|
src/lib/src/Modules/Integrations/Lib/MainWP/Controller.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Logic\
|
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;
|
@@ -11,7 +11,7 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
|
11 |
class Controller {
|
12 |
|
13 |
use ModConsumer;
|
14 |
-
use
|
15 |
|
16 |
const MIN_VERSION_MAINWP = '4.1';
|
17 |
|
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;
|
11 |
class Controller {
|
12 |
|
13 |
use ModConsumer;
|
14 |
+
use ExecOnce;
|
15 |
|
16 |
const MIN_VERSION_MAINWP = '4.1';
|
17 |
|
src/lib/src/Modules/Integrations/Lib/MainWP/Server/Data/ClientPluginStatus.php
CHANGED
@@ -34,7 +34,7 @@ class ClientPluginStatus {
|
|
34 |
|
35 |
if ( $this->isActive() ) {
|
36 |
|
37 |
-
if ( empty( $sync->
|
38 |
$status = self::NEED_SYNC;
|
39 |
}
|
40 |
elseif ( empty( $m->is_pro ) ) {
|
34 |
|
35 |
if ( $this->isActive() ) {
|
36 |
|
37 |
+
if ( empty( $sync->getRawData() ) ) {
|
38 |
$status = self::NEED_SYNC;
|
39 |
}
|
40 |
elseif ( empty( $m->is_pro ) ) {
|
src/lib/src/Modules/Integrations/Lib/MainWP/Server/Data/LoadShieldSyncData.php
CHANGED
@@ -12,7 +12,7 @@ class LoadShieldSyncData {
|
|
12 |
|
13 |
public static function Load( MWPSiteVO $site ) :SyncVO {
|
14 |
$data = MainWP_DB::instance()->get_website_option(
|
15 |
-
$site->
|
16 |
Controller::GetInstance()->prefix( 'mainwp-sync' )
|
17 |
);
|
18 |
if ( empty( $data ) ) {
|
12 |
|
13 |
public static function Load( MWPSiteVO $site ) :SyncVO {
|
14 |
$data = MainWP_DB::instance()->get_website_option(
|
15 |
+
$site->getRawData(),
|
16 |
Controller::GetInstance()->prefix( 'mainwp-sync' )
|
17 |
);
|
18 |
if ( empty( $data ) ) {
|
src/lib/src/Modules/Integrations/Lib/MainWP/Server/Data/SyncHandler.php
CHANGED
@@ -2,14 +2,14 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Server\Data;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Logic\
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
7 |
use MainWP\Dashboard\MainWP_DB;
|
8 |
|
9 |
class SyncHandler {
|
10 |
|
11 |
use ModConsumer;
|
12 |
-
use
|
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\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 ) {
|
src/lib/src/Modules/Integrations/Lib/MainWP/Server/UI/ExtensionSettingsPage.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Server\UI;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Logic\
|
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;
|
@@ -12,7 +12,7 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
12 |
class ExtensionSettingsPage {
|
13 |
|
14 |
use ModConsumer;
|
15 |
-
use
|
16 |
|
17 |
protected function run() {
|
18 |
|
@@ -41,7 +41,7 @@ class ExtensionSettingsPage {
|
|
41 |
// wp_enqueue_style( 'semantic-ui-datatables-select' );
|
42 |
}
|
43 |
return $enqueues;
|
44 |
-
}, 10,2 );
|
45 |
}
|
46 |
|
47 |
/**
|
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;
|
12 |
class ExtensionSettingsPage {
|
13 |
|
14 |
use ModConsumer;
|
15 |
+
use ExecOnce;
|
16 |
|
17 |
protected function run() {
|
18 |
|
41 |
// wp_enqueue_style( 'semantic-ui-datatables-select' );
|
42 |
}
|
43 |
return $enqueues;
|
44 |
+
}, 10, 2 );
|
45 |
}
|
46 |
|
47 |
/**
|
src/lib/src/Modules/Integrations/Lib/MainWP/Server/UI/ManageSites/SitesListTableHandler.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Server\UI\ManageSites;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Logic\
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Common\MWPSiteVO;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Server\Data\ClientPluginStatus;
|
8 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Server\Data\LoadShieldSyncData;
|
@@ -13,7 +13,7 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
13 |
class SitesListTableHandler extends BaseRender {
|
14 |
|
15 |
use ModConsumer;
|
16 |
-
use
|
17 |
|
18 |
/**
|
19 |
* @var MWPSiteVO
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Server\UI\ManageSites;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Logic\ExecOnce;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Common\MWPSiteVO;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Server\Data\ClientPluginStatus;
|
8 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\MainWP\Server\Data\LoadShieldSyncData;
|
13 |
class SitesListTableHandler extends BaseRender {
|
14 |
|
15 |
use ModConsumer;
|
16 |
+
use ExecOnce;
|
17 |
|
18 |
/**
|
19 |
* @var MWPSiteVO
|
src/lib/src/Modules/Integrations/Lib/MainWP/Server/UI/PageRender/SitesList.php
CHANGED
@@ -28,7 +28,7 @@ class SitesList extends BaseRender {
|
|
28 |
$sync = LoadShieldSyncData::Load( $mwpSite );
|
29 |
$meta = $sync->meta;
|
30 |
|
31 |
-
$shd = $sync->
|
32 |
$status = ( new ClientPluginStatus() )
|
33 |
->setMod( $this->getMod() )
|
34 |
->setMwpSite( $mwpSite )
|
28 |
$sync = LoadShieldSyncData::Load( $mwpSite );
|
29 |
$meta = $sync->meta;
|
30 |
|
31 |
+
$shd = $sync->getRawData();
|
32 |
$status = ( new ClientPluginStatus() )
|
33 |
->setMod( $this->getMod() )
|
34 |
->setMwpSite( $mwpSite )
|
src/lib/src/Modules/Integrations/Lib/Spam/Handlers/Base.php
ADDED
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
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 |
+
|
16 |
+
protected function canRun() :bool {
|
17 |
+
return $this->getCon()->isPremiumActive() && $this->isEnabled() && $this->isProviderAvailable();
|
18 |
+
}
|
19 |
+
|
20 |
+
public function isSpam() :bool {
|
21 |
+
$isSpam = $this->isSpam_Bot();
|
22 |
+
$this->getCon()->fireEvent(
|
23 |
+
sprintf( 'spam_form_%s', $isSpam ? 'fail' : 'pass' ),
|
24 |
+
[
|
25 |
+
'audit' => [
|
26 |
+
'form_provider' => $this->getProviderName(),
|
27 |
+
]
|
28 |
+
]
|
29 |
+
);
|
30 |
+
return $isSpam;
|
31 |
+
}
|
32 |
+
|
33 |
+
protected function isSpam_Bot() :bool {
|
34 |
+
return $this->getCon()
|
35 |
+
->getModule_IPs()
|
36 |
+
->getBotSignalsController()
|
37 |
+
->isBot( Services::IP()->getRequestIp() );
|
38 |
+
}
|
39 |
+
|
40 |
+
protected function isSpam_Human() :bool {
|
41 |
+
return false;
|
42 |
+
}
|
43 |
+
|
44 |
+
protected function isEnabled() :bool {
|
45 |
+
return in_array( $this->getProviderSlug(), $this->getOptions()->getOpt( 'form_spam_providers', [] ) );
|
46 |
+
}
|
47 |
+
|
48 |
+
protected function isProviderAvailable() :bool {
|
49 |
+
return false;
|
50 |
+
}
|
51 |
+
|
52 |
+
protected function getProviderName() :string {
|
53 |
+
return '';
|
54 |
+
}
|
55 |
+
|
56 |
+
protected function getProviderSlug() :string {
|
57 |
+
try {
|
58 |
+
$slug = strtolower( ( new \ReflectionClass( $this ) )->getShortName() );
|
59 |
+
}
|
60 |
+
catch ( \Exception $e ) {
|
61 |
+
$slug = '';
|
62 |
+
}
|
63 |
+
return $slug;
|
64 |
+
}
|
65 |
+
}
|
src/lib/src/Modules/Integrations/Lib/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\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 |
+
protected function isProviderAvailable() :bool {
|
18 |
+
return defined( 'WPCF7_TEXT_DOMAIN' ) && WPCF7_TEXT_DOMAIN === 'contact-form-7';
|
19 |
+
}
|
20 |
+
}
|
src/lib/src/Modules/Integrations/Lib/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\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 |
+
protected function isProviderAvailable() :bool {
|
24 |
+
return defined( 'ELEMENTOR_PRO_VERSION' ) && @function_exists( 'elementor_pro_load_plugin' );
|
25 |
+
}
|
26 |
+
}
|
src/lib/src/Modules/Integrations/Lib/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\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\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 |
+
protected function isProviderAvailable() :bool {
|
26 |
+
return defined( 'FLUENTFORM' ) && @class_exists( '\FluentForm\Framework\Foundation\Bootstrap' );
|
27 |
+
}
|
28 |
+
}
|
src/lib/src/Modules/Integrations/Lib/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\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 |
+
protected function isProviderAvailable() :bool {
|
27 |
+
return function_exists( 'load_formidable_forms' ) && @class_exists( '\FrmHooksController' );
|
28 |
+
}
|
29 |
+
}
|
src/lib/src/Modules/Integrations/Lib/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\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 |
+
protected function isProviderAvailable() :bool {
|
18 |
+
return defined( 'FORMINATOR_VERSION' ) && @class_exists( '\Forminator' );
|
19 |
+
}
|
20 |
+
}
|
src/lib/src/Modules/Integrations/Lib/Spam/Handlers/GravityForms.php
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\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 |
+
protected function isProviderAvailable() :bool {
|
18 |
+
return @class_exists( 'GFForms' ) && isset( GFForms::$version )
|
19 |
+
&& version_compare( GFForms::$version, '2.4.17', '>=' );
|
20 |
+
}
|
21 |
+
}
|
src/lib/src/Modules/Integrations/Lib/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\Spam\Handlers\Helpers;
|
4 |
+
|
5 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\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/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\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 |
+
protected function isProviderAvailable() :bool {
|
25 |
+
return defined( 'KALIFORMS_PLUGIN_FILE' ) && @class_exists( '\KaliForms\Inc\KaliForms' );
|
26 |
+
}
|
27 |
+
}
|
src/lib/src/Modules/Integrations/Lib/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\Spam\Handlers;
|
4 |
+
|
5 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\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\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 |
+
protected function isProviderAvailable() :bool {
|
46 |
+
return @class_exists( '\Ninja_Forms' );
|
47 |
+
}
|
48 |
+
}
|
src/lib/src/Modules/Integrations/Lib/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\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 |
+
protected function isProviderAvailable() :bool {
|
35 |
+
return defined( 'WPFORMS_VERSION' ) && function_exists( 'wpforms' );
|
36 |
+
}
|
37 |
+
}
|
src/lib/src/Modules/Integrations/Lib/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\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, $forum ) {
|
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, 2 );
|
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 |
+
protected function isProviderAvailable() :bool {
|
38 |
+
return function_exists( 'WPF' ) && @class_exists( 'wpForo' ) && !empty( WPF()->tools_antispam[ 'spam_filter' ] );
|
39 |
+
}
|
40 |
+
}
|
src/lib/src/Modules/Integrations/Lib/Spam/SpamController.php
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Integrations\Lib\Spam;
|
4 |
+
|
5 |
+
use FernleafSystems\Utilities\Logic\ExecOnce;
|
6 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
7 |
+
|
8 |
+
class SpamController {
|
9 |
+
|
10 |
+
use ModConsumer;
|
11 |
+
use ExecOnce;
|
12 |
+
|
13 |
+
protected function canRun() :bool {
|
14 |
+
return $this->isEnabledSpamDetect();
|
15 |
+
}
|
16 |
+
|
17 |
+
protected function run() {
|
18 |
+
foreach ( $this->enumProviders() as $provider ) {
|
19 |
+
$provider->setMod( $this->getMod() )->execute();
|
20 |
+
}
|
21 |
+
}
|
22 |
+
|
23 |
+
private function isEnabledSpamDetect() :bool {
|
24 |
+
$opts = $this->getOptions();
|
25 |
+
return ( $opts->isOpt( 'enable_spam_antibot', 'Y' ) || $opts->isOpt( 'enable_spam_human', 'Y' ) )
|
26 |
+
&& !empty( $opts->getOpt( 'form_spam_providers' ) );
|
27 |
+
}
|
28 |
+
|
29 |
+
/**
|
30 |
+
* @return Handlers\Base[]
|
31 |
+
*/
|
32 |
+
private function enumProviders() :array {
|
33 |
+
return [
|
34 |
+
new Handlers\ContactForm7(),
|
35 |
+
new Handlers\ElementorPro(),
|
36 |
+
new Handlers\FormidableForms(),
|
37 |
+
new Handlers\FluentForms(),
|
38 |
+
new Handlers\Forminator(),
|
39 |
+
new Handlers\GravityForms(),
|
40 |
+
new Handlers\KaliForms(),
|
41 |
+
new Handlers\NinjaForms(),
|
42 |
+
new Handlers\WPForms(),
|
43 |
+
new Handlers\WpForo(),
|
44 |
+
];
|
45 |
+
}
|
46 |
+
}
|
src/lib/src/Modules/Integrations/Processor.php
CHANGED
@@ -7,9 +7,12 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
|
|
7 |
class Processor extends BaseShield\Processor {
|
8 |
|
9 |
protected function run() {
|
10 |
-
$
|
11 |
-
|
12 |
-
|
13 |
-
|
|
|
|
|
|
|
14 |
}
|
15 |
}
|
7 |
class Processor extends BaseShield\Processor {
|
8 |
|
9 |
protected function run() {
|
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 |
}
|
src/lib/src/Modules/Integrations/Strings.php
CHANGED
@@ -6,6 +6,20 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base;
|
|
6 |
|
7 |
class Strings extends Base\Strings {
|
8 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
/**
|
10 |
* @param string $section
|
11 |
* @return array
|
6 |
|
7 |
class Strings extends Base\Strings {
|
8 |
|
9 |
+
/**
|
10 |
+
* @inheritDoc
|
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 |
+
|
23 |
/**
|
24 |
* @param string $section
|
25 |
* @return array
|
src/lib/src/Modules/License/Lib/LicenseHandler.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\License\Lib;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Logic\
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\License\EddLicenseVO;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules;
|
8 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\License\ModCon;
|
@@ -12,7 +12,7 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
12 |
class LicenseHandler {
|
13 |
|
14 |
use Modules\ModConsumer;
|
15 |
-
use
|
16 |
|
17 |
protected function run() {
|
18 |
add_action( $this->getCon()->prefix( 'shield_action' ), function ( $action ) {
|
@@ -21,12 +21,12 @@ class LicenseHandler {
|
|
21 |
|
22 |
case 'keyless_handshake':
|
23 |
case 'snapi_handshake':
|
24 |
-
$
|
25 |
-
if ( !empty( $
|
26 |
die( json_encode( [
|
27 |
'success' => ( new HandshakingNonce() )
|
28 |
->setMod( $this->getMod() )
|
29 |
-
->verify( $
|
30 |
] ) );
|
31 |
}
|
32 |
break;
|
@@ -85,33 +85,21 @@ class LicenseHandler {
|
|
85 |
add_filter( $this->getCon()->prefix( 'force_options_resave' ), '__return_true' );
|
86 |
}
|
87 |
|
88 |
-
|
89 |
-
|
90 |
-
*/
|
91 |
-
protected function getActivatedAt() {
|
92 |
-
return $this->getOptions()->getOpt( 'license_activated_at' );
|
93 |
}
|
94 |
|
95 |
-
|
96 |
-
|
97 |
-
*/
|
98 |
-
protected function getDeactivatedAt() {
|
99 |
-
return $this->getOptions()->getOpt( 'license_deactivated_at' );
|
100 |
}
|
101 |
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
public function getLicense() {
|
106 |
-
$aData = $this->getOptions()->getOpt( 'license_data', [] );
|
107 |
-
return ( new EddLicenseVO() )->applyFromArray( is_array( $aData ) ? $aData : [] );
|
108 |
}
|
109 |
|
110 |
-
|
111 |
-
|
112 |
-
*/
|
113 |
-
public function getLicenseNotCheckedForInterval() {
|
114 |
-
return Services::Request()->ts() - $this->getOptions()->getOpt( 'license_last_checked_at' );
|
115 |
}
|
116 |
|
117 |
/**
|
@@ -121,7 +109,7 @@ class LicenseHandler {
|
|
121 |
* plus the grace period.
|
122 |
* @return int
|
123 |
*/
|
124 |
-
public function getRegistrationExpiresAt() {
|
125 |
/** @var ModCon $mod */
|
126 |
$mod = $this->getMod();
|
127 |
$opts = $this->getOptions();
|
@@ -151,36 +139,24 @@ class LicenseHandler {
|
|
151 |
return $oLic->isValid() && $this->isActive();
|
152 |
}
|
153 |
|
154 |
-
|
155 |
-
* @return bool
|
156 |
-
*/
|
157 |
-
public function isActive() {
|
158 |
return ( $this->getActivatedAt() > 0 )
|
159 |
&& ( $this->getDeactivatedAt() < $this->getActivatedAt() );
|
160 |
}
|
161 |
|
162 |
-
|
163 |
-
* @return bool
|
164 |
-
*/
|
165 |
-
public function isLastVerifiedExpired() {
|
166 |
return ( Services::Request()->ts() - $this->getLicense()->last_verified_at )
|
167 |
> $this->getOptions()->getDef( 'lic_verify_expire_days' )*DAY_IN_SECONDS;
|
168 |
}
|
169 |
|
170 |
-
|
171 |
-
* @return bool
|
172 |
-
*/
|
173 |
-
public function isLastVerifiedGraceExpired() {
|
174 |
$oOpts = $this->getOptions();
|
175 |
$nGracePeriod = ( $oOpts->getDef( 'lic_verify_expire_days' )
|
176 |
+ $oOpts->getDef( 'lic_verify_expire_grace_days' ) )*DAY_IN_SECONDS;
|
177 |
return ( Services::Request()->ts() - $this->getLicense()->last_verified_at ) > $nGracePeriod;
|
178 |
}
|
179 |
|
180 |
-
|
181 |
-
* @return bool
|
182 |
-
*/
|
183 |
-
private function isMaybeExpiring() {
|
184 |
return $this->isActive() &&
|
185 |
(
|
186 |
abs( Services::Request()->ts() - $this->getLicense()->getExpiresAt() )
|
@@ -188,17 +164,11 @@ class LicenseHandler {
|
|
188 |
);
|
189 |
}
|
190 |
|
191 |
-
|
192 |
-
* @return bool
|
193 |
-
*/
|
194 |
-
public function isWithinVerifiedGraceExpired() {
|
195 |
return $this->isLastVerifiedExpired() && !$this->isLastVerifiedGraceExpired();
|
196 |
}
|
197 |
|
198 |
-
|
199 |
-
* @return bool
|
200 |
-
*/
|
201 |
-
private function isVerifyRequired() {
|
202 |
return ( $this->isMaybeExpiring() && $this->getIsLicenseNotCheckedFor( HOUR_IN_SECONDS*4 ) )
|
203 |
|| ( $this->isActive()
|
204 |
&& !$this->getLicense()->isReady() && $this->getIsLicenseNotCheckedFor( HOUR_IN_SECONDS ) )
|
@@ -220,20 +190,13 @@ class LicenseHandler {
|
|
220 |
return $this;
|
221 |
}
|
222 |
|
223 |
-
|
224 |
-
* @param int $nTimePeriod
|
225 |
-
* @return bool
|
226 |
-
*/
|
227 |
-
private function getIsLicenseNotCheckedFor( $nTimePeriod ) {
|
228 |
return $this->getLicenseNotCheckedForInterval() > $nTimePeriod;
|
229 |
}
|
230 |
|
231 |
-
|
232 |
-
* @return bool
|
233 |
-
*/
|
234 |
-
private function canLicenseCheck_FileFlag() {
|
235 |
$nMtime = (int)Services::WpFs()->getModifiedTime(
|
236 |
-
$this->getCon()->
|
237 |
);
|
238 |
return ( Services::Request()->ts() - $nMtime ) > MINUTE_IN_SECONDS;
|
239 |
}
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\License\Lib;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Logic\ExecOnce;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\License\EddLicenseVO;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules;
|
8 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\License\ModCon;
|
12 |
class LicenseHandler {
|
13 |
|
14 |
use Modules\ModConsumer;
|
15 |
+
use ExecOnce;
|
16 |
|
17 |
protected function run() {
|
18 |
add_action( $this->getCon()->prefix( 'shield_action' ), function ( $action ) {
|
21 |
|
22 |
case 'keyless_handshake':
|
23 |
case 'snapi_handshake':
|
24 |
+
$nonce = Services::Request()->query( 'nonce' );
|
25 |
+
if ( !empty( $nonce ) ) {
|
26 |
die( json_encode( [
|
27 |
'success' => ( new HandshakingNonce() )
|
28 |
->setMod( $this->getMod() )
|
29 |
+
->verify( $nonce )
|
30 |
] ) );
|
31 |
}
|
32 |
break;
|
85 |
add_filter( $this->getCon()->prefix( 'force_options_resave' ), '__return_true' );
|
86 |
}
|
87 |
|
88 |
+
protected function getActivatedAt() :int {
|
89 |
+
return (int)$this->getOptions()->getOpt( 'license_activated_at' );
|
|
|
|
|
|
|
90 |
}
|
91 |
|
92 |
+
protected function getDeactivatedAt() :int {
|
93 |
+
return (int)$this->getOptions()->getOpt( 'license_deactivated_at' );
|
|
|
|
|
|
|
94 |
}
|
95 |
|
96 |
+
public function getLicense() :EddLicenseVO {
|
97 |
+
$data = $this->getOptions()->getOpt( 'license_data', [] );
|
98 |
+
return ( new EddLicenseVO() )->applyFromArray( is_array( $data ) ? $data : [] );
|
|
|
|
|
|
|
99 |
}
|
100 |
|
101 |
+
public function getLicenseNotCheckedForInterval() :int {
|
102 |
+
return (int)( Services::Request()->ts() - $this->getOptions()->getOpt( 'license_last_checked_at' ) );
|
|
|
|
|
|
|
103 |
}
|
104 |
|
105 |
/**
|
109 |
* plus the grace period.
|
110 |
* @return int
|
111 |
*/
|
112 |
+
public function getRegistrationExpiresAt() :int {
|
113 |
/** @var ModCon $mod */
|
114 |
$mod = $this->getMod();
|
115 |
$opts = $this->getOptions();
|
139 |
return $oLic->isValid() && $this->isActive();
|
140 |
}
|
141 |
|
142 |
+
public function isActive() :bool {
|
|
|
|
|
|
|
143 |
return ( $this->getActivatedAt() > 0 )
|
144 |
&& ( $this->getDeactivatedAt() < $this->getActivatedAt() );
|
145 |
}
|
146 |
|
147 |
+
public function isLastVerifiedExpired() :bool {
|
|
|
|
|
|
|
148 |
return ( Services::Request()->ts() - $this->getLicense()->last_verified_at )
|
149 |
> $this->getOptions()->getDef( 'lic_verify_expire_days' )*DAY_IN_SECONDS;
|
150 |
}
|
151 |
|
152 |
+
public function isLastVerifiedGraceExpired() :bool {
|
|
|
|
|
|
|
153 |
$oOpts = $this->getOptions();
|
154 |
$nGracePeriod = ( $oOpts->getDef( 'lic_verify_expire_days' )
|
155 |
+ $oOpts->getDef( 'lic_verify_expire_grace_days' ) )*DAY_IN_SECONDS;
|
156 |
return ( Services::Request()->ts() - $this->getLicense()->last_verified_at ) > $nGracePeriod;
|
157 |
}
|
158 |
|
159 |
+
private function isMaybeExpiring() :bool {
|
|
|
|
|
|
|
160 |
return $this->isActive() &&
|
161 |
(
|
162 |
abs( Services::Request()->ts() - $this->getLicense()->getExpiresAt() )
|
164 |
);
|
165 |
}
|
166 |
|
167 |
+
public function isWithinVerifiedGraceExpired() :bool {
|
|
|
|
|
|
|
168 |
return $this->isLastVerifiedExpired() && !$this->isLastVerifiedGraceExpired();
|
169 |
}
|
170 |
|
171 |
+
private function isVerifyRequired() :bool {
|
|
|
|
|
|
|
172 |
return ( $this->isMaybeExpiring() && $this->getIsLicenseNotCheckedFor( HOUR_IN_SECONDS*4 ) )
|
173 |
|| ( $this->isActive()
|
174 |
&& !$this->getLicense()->isReady() && $this->getIsLicenseNotCheckedFor( HOUR_IN_SECONDS ) )
|
190 |
return $this;
|
191 |
}
|
192 |
|
193 |
+
private function getIsLicenseNotCheckedFor( $nTimePeriod ) :bool {
|
|
|
|
|
|
|
|
|
194 |
return $this->getLicenseNotCheckedForInterval() > $nTimePeriod;
|
195 |
}
|
196 |
|
197 |
+
private function canLicenseCheck_FileFlag() :bool {
|
|
|
|
|
|
|
198 |
$nMtime = (int)Services::WpFs()->getModifiedTime(
|
199 |
+
$this->getCon()->paths->forFlag( 'license_check' )
|
200 |
);
|
201 |
return ( Services::Request()->ts() - $nMtime ) > MINUTE_IN_SECONDS;
|
202 |
}
|
src/lib/src/Modules/License/Lib/PluginNameSuffix.php
CHANGED
@@ -2,16 +2,16 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\License\Lib;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Logic\
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin;
|
8 |
|
9 |
class PluginNameSuffix {
|
10 |
|
11 |
use Modules\ModConsumer;
|
12 |
-
use
|
13 |
|
14 |
-
protected function canRun() {
|
15 |
$con = $this->getCon();
|
16 |
/** @var SecurityAdmin\Options $optsSecAdmin */
|
17 |
$optsSecAdmin = $con->getModule_SecAdmin()->getOptions();
|
2 |
|
3 |
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 |
|
11 |
use Modules\ModConsumer;
|
12 |
+
use ExecOnce;
|
13 |
|
14 |
+
protected function canRun() :bool {
|
15 |
$con = $this->getCon();
|
16 |
/** @var SecurityAdmin\Options $optsSecAdmin */
|
17 |
$optsSecAdmin = $con->getModule_SecAdmin()->getOptions();
|
src/lib/src/Modules/License/Lib/Verify.php
CHANGED
@@ -85,10 +85,10 @@ class Verify {
|
|
85 |
}
|
86 |
|
87 |
private function preVerify() {
|
88 |
-
/** @var License\Options $
|
89 |
-
$
|
90 |
-
Services::WpFs()->touch( $this->getCon()->
|
91 |
-
$
|
92 |
$this->getMod()->saveModOptions();
|
93 |
}
|
94 |
}
|
85 |
}
|
86 |
|
87 |
private function preVerify() {
|
88 |
+
/** @var License\Options $opts */
|
89 |
+
$opts = $this->getOptions();
|
90 |
+
Services::WpFs()->touch( $this->getCon()->paths->forFlag( 'license_check' ) );
|
91 |
+
$opts->setOptAt( 'license_last_checked_at' );
|
92 |
$this->getMod()->saveModOptions();
|
93 |
}
|
94 |
}
|
src/lib/src/Modules/License/Lib/WpHashes/ApiTokenManager.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\License\Lib\WpHashes;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Logic\
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules;
|
7 |
use FernleafSystems\Wordpress\Services\Services;
|
8 |
use FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes\Token;
|
@@ -10,7 +10,7 @@ use FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes\Token;
|
|
10 |
class ApiTokenManager {
|
11 |
|
12 |
use Modules\ModConsumer;
|
13 |
-
use
|
14 |
|
15 |
/**
|
16 |
* @var bool
|
@@ -18,8 +18,8 @@ class ApiTokenManager {
|
|
18 |
private $bCanRequestOverride = false;
|
19 |
|
20 |
protected function run() {
|
21 |
-
add_action( $this->getCon()->prefix( 'event' ), function ( $
|
22 |
-
switch ( $
|
23 |
case 'lic_check_success':
|
24 |
$this->setCanRequestOverride( true )->getToken();
|
25 |
break;
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\License\Lib\WpHashes;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Logic\ExecOnce;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules;
|
7 |
use FernleafSystems\Wordpress\Services\Services;
|
8 |
use FernleafSystems\Wordpress\Services\Utilities\Integrations\WpHashes\Token;
|
10 |
class ApiTokenManager {
|
11 |
|
12 |
use Modules\ModConsumer;
|
13 |
+
use ExecOnce;
|
14 |
|
15 |
/**
|
16 |
* @var bool
|
18 |
private $bCanRequestOverride = false;
|
19 |
|
20 |
protected function run() {
|
21 |
+
add_action( $this->getCon()->prefix( 'event' ), function ( $eventTag ) {
|
22 |
+
switch ( $eventTag ) {
|
23 |
case 'lic_check_success':
|
24 |
$this->setCanRequestOverride( true )->getToken();
|
25 |
break;
|
src/lib/src/Modules/License/WpCli/License.php
CHANGED
@@ -117,8 +117,7 @@ class License extends Base\WpCli\BaseWpCliCmd {
|
|
117 |
* or you're premium and you haven't switched it off (parent).
|
118 |
* @inheritDoc
|
119 |
*/
|
120 |
-
protected function canRun() {
|
121 |
-
return !$this->getCon()->isPremiumActive()
|
122 |
-
|| parent::canRun();
|
123 |
}
|
124 |
}
|
117 |
* or you're premium and you haven't switched it off (parent).
|
118 |
* @inheritDoc
|
119 |
*/
|
120 |
+
protected function canRun() :bool {
|
121 |
+
return !$this->getCon()->isPremiumActive() || parent::canRun();
|
|
|
122 |
}
|
123 |
}
|
src/lib/src/Modules/Lockdown/Lib/CleanRubbish.php
CHANGED
@@ -2,33 +2,29 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Lockdown\Lib;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Logic\
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
7 |
use FernleafSystems\Wordpress\Services\Services;
|
8 |
|
9 |
class CleanRubbish {
|
10 |
|
11 |
use ModConsumer;
|
12 |
-
use
|
|
|
|
|
|
|
|
|
13 |
|
14 |
protected function run() {
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
$
|
19 |
-
|
20 |
-
if ( in_array( basename( $file ), $this->getFilesToClean() ) ) {
|
21 |
-
$FS->deleteFile( $file );
|
22 |
-
}
|
23 |
-
}
|
24 |
-
} );
|
25 |
}
|
26 |
}
|
27 |
|
28 |
-
|
29 |
-
* @return string[]
|
30 |
-
*/
|
31 |
-
private function getFilesToClean() {
|
32 |
return [
|
33 |
'wp-config-sample.php',
|
34 |
'readme.html',
|
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' );
|
16 |
+
}
|
17 |
|
18 |
protected function run() {
|
19 |
+
$FS = Services::WpFs();
|
20 |
+
foreach ( $FS->getAllFilesInDir( ABSPATH, false ) as $file ) {
|
21 |
+
if ( in_array( basename( $file ), $this->getFilesToClean() ) ) {
|
22 |
+
$FS->deleteFile( $file );
|
23 |
+
}
|
|
|
|
|
|
|
|
|
|
|
24 |
}
|
25 |
}
|
26 |
|
27 |
+
private function getFilesToClean() :array {
|
|
|
|
|
|
|
28 |
return [
|
29 |
'wp-config-sample.php',
|
30 |
'readme.html',
|
src/lib/src/Modules/Lockdown/Processor.php
CHANGED
@@ -26,18 +26,18 @@ class Processor extends BaseShield\Processor {
|
|
26 |
remove_action( 'wp_head', 'wp_generator' );
|
27 |
}
|
28 |
|
29 |
-
if ( $opts->isOpt( 'clean_wp_rubbish', 'Y' ) ) {
|
30 |
-
( new Lib\CleanRubbish() )
|
31 |
-
->setMod( $this->getMod() )
|
32 |
-
->execute();
|
33 |
-
}
|
34 |
-
|
35 |
if ( $opts->isXmlrpcDisabled() ) {
|
36 |
add_filter( 'xmlrpc_enabled', [ $this, 'disableXmlrpc' ], 1000, 0 );
|
37 |
add_filter( 'xmlrpc_methods', [ $this, 'disableXmlrpc' ], 1000, 0 );
|
38 |
}
|
39 |
}
|
40 |
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
private function blockFileEditing() {
|
42 |
if ( !defined( 'DISALLOW_FILE_EDIT' ) ) {
|
43 |
define( 'DISALLOW_FILE_EDIT', true );
|
26 |
remove_action( 'wp_head', 'wp_generator' );
|
27 |
}
|
28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
if ( $opts->isXmlrpcDisabled() ) {
|
30 |
add_filter( 'xmlrpc_enabled', [ $this, 'disableXmlrpc' ], 1000, 0 );
|
31 |
add_filter( 'xmlrpc_methods', [ $this, 'disableXmlrpc' ], 1000, 0 );
|
32 |
}
|
33 |
}
|
34 |
|
35 |
+
public function runDailyCron() {
|
36 |
+
( new Lib\CleanRubbish() )
|
37 |
+
->setMod( $this->getMod() )
|
38 |
+
->execute();
|
39 |
+
}
|
40 |
+
|
41 |
private function blockFileEditing() {
|
42 |
if ( !defined( 'DISALLOW_FILE_EDIT' ) ) {
|
43 |
define( 'DISALLOW_FILE_EDIT', true );
|
src/lib/src/Modules/LoginGuard/Insights/OverviewCards.php
CHANGED
@@ -25,31 +25,31 @@ class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
|
|
25 |
$cards[ 'mod' ] = $this->getModDisabledCard();
|
26 |
}
|
27 |
else {
|
28 |
-
$
|
29 |
|
30 |
-
$
|
31 |
-
$
|
32 |
-
$
|
33 |
$cards[ 'bot_login' ] = [
|
34 |
'name' => __( 'Brute Force Login', 'wp-simple-firewall' ),
|
35 |
-
'state' => $
|
36 |
-
'summary' => $
|
37 |
__( 'Login forms are protected against bot attacks', 'wp-simple-firewall' )
|
38 |
: __( "Login forms aren't protected against brute force bot attacks", 'wp-simple-firewall' ),
|
39 |
'href' => $mod->getUrl_DirectLinkToOption( 'bot_protection_locations' ),
|
40 |
];
|
41 |
$cards[ 'bot_register' ] = [
|
42 |
'name' => __( 'Bot User Register', 'wp-simple-firewall' ),
|
43 |
-
'state' => $
|
44 |
-
'summary' => $
|
45 |
__( 'Registration forms are protected against bot attacks', 'wp-simple-firewall' )
|
46 |
: __( "Registration forms aren't protected against automated bots", 'wp-simple-firewall' ),
|
47 |
'href' => $mod->getUrl_DirectLinkToOption( 'bot_protection_locations' ),
|
48 |
];
|
49 |
$cards[ 'bot_password' ] = [
|
50 |
'name' => __( 'Brute Force Lost Password', 'wp-simple-firewall' ),
|
51 |
-
'state' => $
|
52 |
-
'summary' => $
|
53 |
__( 'Lost Password forms are protected against bot attacks', 'wp-simple-firewall' )
|
54 |
: __( "Lost Password forms aren't protected against automated bots", 'wp-simple-firewall' ),
|
55 |
'href' => $mod->getUrl_DirectLinkToOption( 'bot_protection_locations' ),
|
25 |
$cards[ 'mod' ] = $this->getModDisabledCard();
|
26 |
}
|
27 |
else {
|
28 |
+
$hasBotCheck = $opts->isEnabledAntiBot() || $opts->isEnabledGaspCheck() || $mod->isEnabledCaptcha();
|
29 |
|
30 |
+
$boLogin = $hasBotCheck && $opts->isProtectLogin();
|
31 |
+
$botReg = $hasBotCheck && $opts->isProtectRegister();
|
32 |
+
$botPassword = $hasBotCheck && $opts->isProtectLostPassword();
|
33 |
$cards[ 'bot_login' ] = [
|
34 |
'name' => __( 'Brute Force Login', 'wp-simple-firewall' ),
|
35 |
+
'state' => $boLogin ? 1 : -1,
|
36 |
+
'summary' => $boLogin ?
|
37 |
__( 'Login forms are protected against bot attacks', 'wp-simple-firewall' )
|
38 |
: __( "Login forms aren't protected against brute force bot attacks", 'wp-simple-firewall' ),
|
39 |
'href' => $mod->getUrl_DirectLinkToOption( 'bot_protection_locations' ),
|
40 |
];
|
41 |
$cards[ 'bot_register' ] = [
|
42 |
'name' => __( 'Bot User Register', 'wp-simple-firewall' ),
|
43 |
+
'state' => $botReg ? 1 : -1,
|
44 |
+
'summary' => $botReg ?
|
45 |
__( 'Registration forms are protected against bot attacks', 'wp-simple-firewall' )
|
46 |
: __( "Registration forms aren't protected against automated bots", 'wp-simple-firewall' ),
|
47 |
'href' => $mod->getUrl_DirectLinkToOption( 'bot_protection_locations' ),
|
48 |
];
|
49 |
$cards[ 'bot_password' ] = [
|
50 |
'name' => __( 'Brute Force Lost Password', 'wp-simple-firewall' ),
|
51 |
+
'state' => $botPassword ? 1 : -1,
|
52 |
+
'summary' => $botPassword ?
|
53 |
__( 'Lost Password forms are protected against bot attacks', 'wp-simple-firewall' )
|
54 |
: __( "Lost Password forms aren't protected against automated bots", 'wp-simple-firewall' ),
|
55 |
'href' => $mod->getUrl_DirectLinkToOption( 'bot_protection_locations' ),
|
src/lib/src/Modules/LoginGuard/Lib/AntiBot/AntibotSetup.php
CHANGED
@@ -2,6 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\AntiBot;
|
4 |
|
|
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\AntiBot;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
@@ -11,49 +12,51 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
11 |
class AntibotSetup {
|
12 |
|
13 |
use ModConsumer;
|
|
|
14 |
|
15 |
-
|
16 |
-
|
17 |
}
|
18 |
|
19 |
-
|
20 |
-
if ( !Services::WpUsers()->isUserLoggedIn() ) {
|
21 |
-
$this->run();
|
22 |
-
}
|
23 |
-
}
|
24 |
-
|
25 |
-
private function run() {
|
26 |
/** @var LoginGuard\ModCon $mod */
|
27 |
$mod = $this->getMod();
|
28 |
/** @var LoginGuard\Options $opts */
|
29 |
$opts = $this->getOptions();
|
30 |
|
31 |
-
$
|
32 |
if ( $opts->isEnabledCooldown() && $mod->canCacheDirWrite() ) {
|
33 |
-
$
|
34 |
->setMod( $mod );
|
35 |
}
|
36 |
|
37 |
-
if ( $opts->
|
38 |
-
$
|
39 |
->setMod( $mod );
|
40 |
}
|
|
|
41 |
|
42 |
-
|
43 |
-
|
44 |
-
if ( $cfg->provider === CaptchaConfigVO::PROV_GOOGLE_RECAP2 ) {
|
45 |
-
$aProtectionProviders[] = ( new AntiBot\ProtectionProviders\GoogleRecaptcha() )
|
46 |
->setMod( $mod );
|
47 |
}
|
48 |
-
|
49 |
-
|
50 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
}
|
52 |
}
|
53 |
|
54 |
-
if ( !empty( $
|
55 |
|
56 |
-
AntiBot\FormProviders\WordPress::SetProviders( $
|
57 |
/** @var AntiBot\FormProviders\BaseFormProvider[] $aFormProviders */
|
58 |
$aFormProviders = [
|
59 |
new AntiBot\FormProviders\WordPress()
|
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;
|
12 |
class AntibotSetup {
|
13 |
|
14 |
use ModConsumer;
|
15 |
+
use ExecOnce;
|
16 |
|
17 |
+
protected function canRun() :bool {
|
18 |
+
return !Services::WpUsers()->isUserLoggedIn();
|
19 |
}
|
20 |
|
21 |
+
protected function run() {
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
/** @var LoginGuard\ModCon $mod */
|
23 |
$mod = $this->getMod();
|
24 |
/** @var LoginGuard\Options $opts */
|
25 |
$opts = $this->getOptions();
|
26 |
|
27 |
+
$providers = [];
|
28 |
if ( $opts->isEnabledCooldown() && $mod->canCacheDirWrite() ) {
|
29 |
+
$providers[] = ( new AntiBot\ProtectionProviders\CoolDown() )
|
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 );
|
42 |
}
|
43 |
+
|
44 |
+
if ( $mod->isEnabledCaptcha() ) {
|
45 |
+
$cfg = $mod->getCaptchaCfg();
|
46 |
+
if ( $cfg->provider === CaptchaConfigVO::PROV_GOOGLE_RECAP2 ) {
|
47 |
+
$providers[] = ( new AntiBot\ProtectionProviders\GoogleRecaptcha() )
|
48 |
+
->setMod( $mod );
|
49 |
+
}
|
50 |
+
elseif ( $cfg->provider === CaptchaConfigVO::PROV_HCAPTCHA ) {
|
51 |
+
$providers[] = ( new AntiBot\ProtectionProviders\HCaptcha() )
|
52 |
+
->setMod( $mod );
|
53 |
+
}
|
54 |
}
|
55 |
}
|
56 |
|
57 |
+
if ( !empty( $providers ) ) {
|
58 |
|
59 |
+
AntiBot\FormProviders\WordPress::SetProviders( $providers );
|
60 |
/** @var AntiBot\FormProviders\BaseFormProvider[] $aFormProviders */
|
61 |
$aFormProviders = [
|
62 |
new AntiBot\FormProviders\WordPress()
|
src/lib/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/BaseFormProvider.php
CHANGED
@@ -79,27 +79,22 @@ abstract class BaseFormProvider {
|
|
79 |
* @return string
|
80 |
*/
|
81 |
public function formInsertsAppend( $sToAppend ) {
|
82 |
-
return $sToAppend.$this->
|
83 |
}
|
84 |
|
85 |
-
|
86 |
-
* @return string
|
87 |
-
*/
|
88 |
-
public function formInsertsBuild() {
|
89 |
$aInserts = [];
|
90 |
if ( is_array( self::$aProtectionProviders ) ) {
|
91 |
foreach ( self::$aProtectionProviders as $oProvider ) {
|
92 |
$aInserts[] = $oProvider->buildFormInsert( $this );
|
|
|
93 |
}
|
94 |
}
|
95 |
return implode( "\n", $aInserts );
|
96 |
}
|
97 |
|
98 |
-
|
99 |
-
|
100 |
-
*/
|
101 |
-
public function formInsertsPrint() {
|
102 |
-
echo $this->formInsertsBuild();
|
103 |
}
|
104 |
|
105 |
/**
|
79 |
* @return string
|
80 |
*/
|
81 |
public function formInsertsAppend( $sToAppend ) {
|
82 |
+
return $sToAppend.$this->buildFormInsert();
|
83 |
}
|
84 |
|
85 |
+
public function buildFormInsert() :string {
|
|
|
|
|
|
|
86 |
$aInserts = [];
|
87 |
if ( is_array( self::$aProtectionProviders ) ) {
|
88 |
foreach ( self::$aProtectionProviders as $oProvider ) {
|
89 |
$aInserts[] = $oProvider->buildFormInsert( $this );
|
90 |
+
$oProvider->setAsInsertBuilt();
|
91 |
}
|
92 |
}
|
93 |
return implode( "\n", $aInserts );
|
94 |
}
|
95 |
|
96 |
+
public function printFormInsert() {
|
97 |
+
echo $this->buildFormInsert();
|
|
|
|
|
|
|
98 |
}
|
99 |
|
100 |
/**
|
src/lib/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/BuddyPress.php
CHANGED
@@ -5,7 +5,7 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\AntiBot
|
|
5 |
class BuddyPress extends BaseFormProvider {
|
6 |
|
7 |
protected function register() {
|
8 |
-
add_action( 'bp_before_registration_submit_buttons', [ $this, '
|
9 |
add_action( 'bp_signup_validate', [ $this, 'checkRegister' ], 10 );
|
10 |
}
|
11 |
|
5 |
class BuddyPress extends BaseFormProvider {
|
6 |
|
7 |
protected function register() {
|
8 |
+
add_action( 'bp_before_registration_submit_buttons', [ $this, 'printFormInsert' ], 10 );
|
9 |
add_action( 'bp_signup_validate', [ $this, 'checkRegister' ], 10 );
|
10 |
}
|
11 |
|
src/lib/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/EasyDigitalDownloads.php
CHANGED
@@ -5,11 +5,11 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\AntiBot
|
|
5 |
class EasyDigitalDownloads extends BaseFormProvider {
|
6 |
|
7 |
protected function login() {
|
8 |
-
add_action( 'edd_login_fields_after', [ $this, '
|
9 |
}
|
10 |
|
11 |
protected function register() {
|
12 |
-
add_action( 'edd_register_form_fields_before_submit', [ $this, '
|
13 |
add_action( 'edd_process_register_form', [ $this, 'checkRegister' ], 10 );
|
14 |
}
|
15 |
|
5 |
class EasyDigitalDownloads extends BaseFormProvider {
|
6 |
|
7 |
protected function login() {
|
8 |
+
add_action( 'edd_login_fields_after', [ $this, 'printFormInsert' ], 10 );
|
9 |
}
|
10 |
|
11 |
protected function register() {
|
12 |
+
add_action( 'edd_register_form_fields_before_submit', [ $this, 'printFormInsert' ], 10 );
|
13 |
add_action( 'edd_process_register_form', [ $this, 'checkRegister' ], 10 );
|
14 |
}
|
15 |
|
src/lib/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/LearnPress.php
CHANGED
@@ -10,13 +10,13 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\AntiBot
|
|
10 |
class LearnPress extends BaseFormProvider {
|
11 |
|
12 |
protected function login() {
|
13 |
-
add_action( 'learn-press/after-form-login-fields', [ $this, '
|
14 |
-
add_action( 'learn-press/before-checkout-form-login-button', [ $this, '
|
15 |
add_filter( 'learn-press/login-validate-field', [ $this, 'checkLogin' ], 100 );
|
16 |
}
|
17 |
|
18 |
protected function register() {
|
19 |
-
add_action( 'learn-press/after-form-register-fields', [ $this, '
|
20 |
add_filter( 'learn-press/register-validate-field', [ $this, 'checkRegister' ], 100, 1 );
|
21 |
}
|
22 |
|
10 |
class LearnPress extends BaseFormProvider {
|
11 |
|
12 |
protected function login() {
|
13 |
+
add_action( 'learn-press/after-form-login-fields', [ $this, 'printFormInsert' ], 100 );
|
14 |
+
add_action( 'learn-press/before-checkout-form-login-button', [ $this, 'printFormInsert' ], 100 );
|
15 |
add_filter( 'learn-press/login-validate-field', [ $this, 'checkLogin' ], 100 );
|
16 |
}
|
17 |
|
18 |
protected function register() {
|
19 |
+
add_action( 'learn-press/after-form-register-fields', [ $this, 'printFormInsert' ], 100 );
|
20 |
add_filter( 'learn-press/register-validate-field', [ $this, 'checkRegister' ], 100, 1 );
|
21 |
}
|
22 |
|
src/lib/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/MemberPress.php
CHANGED
@@ -5,23 +5,23 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\AntiBot
|
|
5 |
class MemberPress extends BaseFormProvider {
|
6 |
|
7 |
protected function login() {
|
8 |
-
add_action( 'mepr-login-form-before-submit', [ $this, '
|
9 |
add_filter( 'mepr-validate-login', [ $this, 'checkLogin' ], 100 );
|
10 |
/**
|
11 |
* We have to add a checkbox to the password reset form because MemberPress attempts to
|
12 |
* login the given user upon success of password update. Without this checkbox being present
|
13 |
* the login will fail (though the password update will not).
|
14 |
*/
|
15 |
-
add_action( 'mepr-reset-password-after-password-fields', [ $this, '
|
16 |
}
|
17 |
|
18 |
protected function register() {
|
19 |
-
add_action( 'mepr-checkout-before-submit', [ $this, '
|
20 |
add_filter( 'mepr-validate-signup', [ $this, 'checkRegister' ], 10, 2 );
|
21 |
}
|
22 |
|
23 |
protected function lostpassword() {
|
24 |
-
add_action( 'mepr-forgot-password-form', [ $this, '
|
25 |
add_filter( 'mepr-validate-forgot-password', [ $this, 'checkLostPassword' ], 100 );
|
26 |
}
|
27 |
|
5 |
class MemberPress extends BaseFormProvider {
|
6 |
|
7 |
protected function login() {
|
8 |
+
add_action( 'mepr-login-form-before-submit', [ $this, 'printFormInsert' ], 100 );
|
9 |
add_filter( 'mepr-validate-login', [ $this, 'checkLogin' ], 100 );
|
10 |
/**
|
11 |
* We have to add a checkbox to the password reset form because MemberPress attempts to
|
12 |
* login the given user upon success of password update. Without this checkbox being present
|
13 |
* the login will fail (though the password update will not).
|
14 |
*/
|
15 |
+
add_action( 'mepr-reset-password-after-password-fields', [ $this, 'printFormInsert' ], 100 );
|
16 |
}
|
17 |
|
18 |
protected function register() {
|
19 |
+
add_action( 'mepr-checkout-before-submit', [ $this, 'printFormInsert' ], 10 );
|
20 |
add_filter( 'mepr-validate-signup', [ $this, 'checkRegister' ], 10, 2 );
|
21 |
}
|
22 |
|
23 |
protected function lostpassword() {
|
24 |
+
add_action( 'mepr-forgot-password-form', [ $this, 'printFormInsert' ], 100 );
|
25 |
add_filter( 'mepr-validate-forgot-password', [ $this, 'checkLostPassword' ], 100 );
|
26 |
}
|
27 |
|
src/lib/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/PaidMemberSubscriptions.php
CHANGED
@@ -10,7 +10,7 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\AntiBot
|
|
10 |
class PaidMemberSubscriptions extends BaseFormProvider {
|
11 |
|
12 |
protected function register() {
|
13 |
-
add_action( 'pms_register_form_after_fields', [ $this, '
|
14 |
add_filter( 'pms_register_form_validation', [ $this, 'checkRegister' ], 100 );
|
15 |
}
|
16 |
|
10 |
class PaidMemberSubscriptions extends BaseFormProvider {
|
11 |
|
12 |
protected function register() {
|
13 |
+
add_action( 'pms_register_form_after_fields', [ $this, 'printFormInsert' ], 100 );
|
14 |
add_filter( 'pms_register_form_validation', [ $this, 'checkRegister' ], 100 );
|
15 |
}
|
16 |
|
src/lib/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/ProfileBuilder.php
CHANGED
@@ -10,7 +10,7 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\AntiBot
|
|
10 |
class ProfileBuilder extends BaseFormProvider {
|
11 |
|
12 |
protected function register() {
|
13 |
-
add_action( 'wppb_form_before_submit_button', [ $this, '
|
14 |
add_filter( 'wppb_output_field_errors_filter', [ $this, 'checkRegister' ], 100 );
|
15 |
}
|
16 |
|
10 |
class ProfileBuilder extends BaseFormProvider {
|
11 |
|
12 |
protected function register() {
|
13 |
+
add_action( 'wppb_form_before_submit_button', [ $this, 'printFormInsert' ], 100 );
|
14 |
add_filter( 'wppb_output_field_errors_filter', [ $this, 'checkRegister' ], 100 );
|
15 |
}
|
16 |
|
src/lib/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/UltimateMember.php
CHANGED
@@ -10,17 +10,17 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\AntiBot
|
|
10 |
class UltimateMember extends BaseFormProvider {
|
11 |
|
12 |
protected function login() {
|
13 |
-
add_action( 'um_after_login_fields', [ $this, '
|
14 |
add_action( 'um_submit_form_login', [ $this, 'checkLogin' ], 100 );
|
15 |
}
|
16 |
|
17 |
protected function register() {
|
18 |
-
add_action( 'um_after_register_fields', [ $this, '
|
19 |
add_action( 'um_submit_form_register', [ $this, 'checkRegister' ], 5, 0 );
|
20 |
}
|
21 |
|
22 |
protected function lostpassword() {
|
23 |
-
add_action( 'um_after_password_reset_fields', [ $this, '
|
24 |
add_action( 'um_submit_form_password_reset', [ $this, 'checkLostPassword' ], 5, 0 );
|
25 |
}
|
26 |
|
10 |
class UltimateMember extends BaseFormProvider {
|
11 |
|
12 |
protected function login() {
|
13 |
+
add_action( 'um_after_login_fields', [ $this, 'printFormInsert' ], 100 );
|
14 |
add_action( 'um_submit_form_login', [ $this, 'checkLogin' ], 100 );
|
15 |
}
|
16 |
|
17 |
protected function register() {
|
18 |
+
add_action( 'um_after_register_fields', [ $this, 'printFormInsert' ], 100 );
|
19 |
add_action( 'um_submit_form_register', [ $this, 'checkRegister' ], 5, 0 );
|
20 |
}
|
21 |
|
22 |
protected function lostpassword() {
|
23 |
+
add_action( 'um_after_password_reset_fields', [ $this, 'printFormInsert' ], 100 );
|
24 |
add_action( 'um_submit_form_password_reset', [ $this, 'checkLostPassword' ], 5, 0 );
|
25 |
}
|
26 |
|
src/lib/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/UserRegistration.php
CHANGED
@@ -11,16 +11,16 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\AntiBot
|
|
11 |
class UserRegistration extends BaseFormProvider {
|
12 |
|
13 |
protected function register() {
|
14 |
-
add_action( 'user_registration_after_form_fields', [ $this, '
|
15 |
add_action( 'user_registration_response_array', [ $this, 'checkRegister' ], 5, 3 );
|
16 |
}
|
17 |
|
18 |
/**
|
19 |
* @return void
|
20 |
*/
|
21 |
-
public function
|
22 |
echo '<div class="ur-form-grid">';
|
23 |
-
echo preg_replace( '#class="(.*)"#i', 'class="\\1 ur-frontend-field"', $this->
|
24 |
echo '</div>';
|
25 |
}
|
26 |
|
11 |
class UserRegistration extends BaseFormProvider {
|
12 |
|
13 |
protected function register() {
|
14 |
+
add_action( 'user_registration_after_form_fields', [ $this, 'printFormInsert' ], 100 );
|
15 |
add_action( 'user_registration_response_array', [ $this, 'checkRegister' ], 5, 3 );
|
16 |
}
|
17 |
|
18 |
/**
|
19 |
* @return void
|
20 |
*/
|
21 |
+
public function printFormInsert() {
|
22 |
echo '<div class="ur-form-grid">';
|
23 |
+
echo preg_replace( '#class="(.*)"#i', 'class="\\1 ur-frontend-field"', $this->buildFormInsert() );
|
24 |
echo '</div>';
|
25 |
}
|
26 |
|
src/lib/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/WooCommerce.php
CHANGED
@@ -28,7 +28,7 @@ class WooCommerce extends BaseFormProvider {
|
|
28 |
}
|
29 |
|
30 |
protected function lostpassword() {
|
31 |
-
add_action( 'woocommerce_lostpassword_form', [ $this, '
|
32 |
}
|
33 |
|
34 |
protected function woocheckout() {
|
@@ -52,7 +52,7 @@ class WooCommerce extends BaseFormProvider {
|
|
52 |
public function formInsertsPrint_WooLogin() {
|
53 |
/** @var LoginGuard\ModCon $mod */
|
54 |
$mod = $this->getMod();
|
55 |
-
$sInserts = $this->
|
56 |
if ( $mod->getCaptchaCfg()->invisible ) {
|
57 |
$sInserts .= '<input type="hidden" name="login" value="Log in" />';
|
58 |
}
|
@@ -65,7 +65,7 @@ class WooCommerce extends BaseFormProvider {
|
|
65 |
public function formInsertsPrint_WooRegister() {
|
66 |
/** @var LoginGuard\ModCon $mod */
|
67 |
$mod = $this->getMod();
|
68 |
-
$sInserts = $this->
|
69 |
if ( $mod->getCaptchaCfg()->invisible ) {
|
70 |
$sInserts .= '<input type="hidden" name="register" value="Register" />';
|
71 |
}
|
@@ -79,7 +79,7 @@ class WooCommerce extends BaseFormProvider {
|
|
79 |
*/
|
80 |
public function formInsertsPrintCheckout( $oCheckout ) {
|
81 |
if ( $oCheckout instanceof \WC_Checkout && $oCheckout->is_registration_enabled() ) {
|
82 |
-
$this->
|
83 |
}
|
84 |
}
|
85 |
|
28 |
}
|
29 |
|
30 |
protected function lostpassword() {
|
31 |
+
add_action( 'woocommerce_lostpassword_form', [ $this, 'printFormInsert' ] );
|
32 |
}
|
33 |
|
34 |
protected function woocheckout() {
|
52 |
public function formInsertsPrint_WooLogin() {
|
53 |
/** @var LoginGuard\ModCon $mod */
|
54 |
$mod = $this->getMod();
|
55 |
+
$sInserts = $this->buildFormInsert();
|
56 |
if ( $mod->getCaptchaCfg()->invisible ) {
|
57 |
$sInserts .= '<input type="hidden" name="login" value="Log in" />';
|
58 |
}
|
65 |
public function formInsertsPrint_WooRegister() {
|
66 |
/** @var LoginGuard\ModCon $mod */
|
67 |
$mod = $this->getMod();
|
68 |
+
$sInserts = $this->buildFormInsert();
|
69 |
if ( $mod->getCaptchaCfg()->invisible ) {
|
70 |
$sInserts .= '<input type="hidden" name="register" value="Register" />';
|
71 |
}
|
79 |
*/
|
80 |
public function formInsertsPrintCheckout( $oCheckout ) {
|
81 |
if ( $oCheckout instanceof \WC_Checkout && $oCheckout->is_registration_enabled() ) {
|
82 |
+
$this->printFormInsert();
|
83 |
}
|
84 |
}
|
85 |
|
src/lib/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/WordPress.php
CHANGED
@@ -7,21 +7,19 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
7 |
class WordPress extends BaseFormProvider {
|
8 |
|
9 |
protected function login() {
|
10 |
-
add_action( 'login_form', [ $this, '
|
11 |
add_filter( 'login_form_middle', [ $this, 'formInsertsAppend' ], 100 );
|
12 |
-
|
13 |
// We give it a priority of 10 so that we can jump in before WordPress does its own validation.
|
14 |
add_filter( 'authenticate', [ $this, 'checkLogin' ], 10, 2 );
|
15 |
}
|
16 |
|
17 |
protected function register() {
|
18 |
-
add_action( 'register_form', [ $this, '
|
19 |
-
|
20 |
add_filter( 'registration_errors', [ $this, 'checkRegister' ], 10, 2 );
|
21 |
}
|
22 |
|
23 |
protected function lostpassword() {
|
24 |
-
add_action( 'lostpassword_form', [ $this, '
|
25 |
add_action( 'lostpassword_post', [ $this, 'checkLostPassword' ], 10, 1 );
|
26 |
}
|
27 |
|
@@ -48,37 +46,37 @@ class WordPress extends BaseFormProvider {
|
|
48 |
}
|
49 |
|
50 |
/**
|
51 |
-
* @param \WP_Error $
|
52 |
* @return \WP_Error
|
53 |
*/
|
54 |
-
public function checkLostPassword( $
|
55 |
try {
|
56 |
$this->setUserToAudit( sanitize_user( Services::Request()->post( 'user_login', '' ) ) )
|
57 |
->setActionToAudit( 'reset-password' )
|
58 |
->checkProviders();
|
59 |
}
|
60 |
catch ( \Exception $e ) {
|
61 |
-
$
|
62 |
-
$
|
63 |
}
|
64 |
-
return $
|
65 |
}
|
66 |
|
67 |
/**
|
68 |
-
* @param \WP_Error $
|
69 |
* @param string $sUsername
|
70 |
* @return \WP_Error
|
71 |
*/
|
72 |
-
public function checkRegister( $
|
73 |
try {
|
74 |
$this->setUserToAudit( $sUsername )
|
75 |
->setActionToAudit( 'register' )
|
76 |
->checkProviders();
|
77 |
}
|
78 |
catch ( \Exception $e ) {
|
79 |
-
$
|
80 |
-
$
|
81 |
}
|
82 |
-
return $
|
83 |
}
|
84 |
}
|
7 |
class WordPress extends BaseFormProvider {
|
8 |
|
9 |
protected function login() {
|
10 |
+
add_action( 'login_form', [ $this, 'printFormInsert' ], 100 );
|
11 |
add_filter( 'login_form_middle', [ $this, 'formInsertsAppend' ], 100 );
|
|
|
12 |
// We give it a priority of 10 so that we can jump in before WordPress does its own validation.
|
13 |
add_filter( 'authenticate', [ $this, 'checkLogin' ], 10, 2 );
|
14 |
}
|
15 |
|
16 |
protected function register() {
|
17 |
+
add_action( 'register_form', [ $this, 'printFormInsert' ] );
|
|
|
18 |
add_filter( 'registration_errors', [ $this, 'checkRegister' ], 10, 2 );
|
19 |
}
|
20 |
|
21 |
protected function lostpassword() {
|
22 |
+
add_action( 'lostpassword_form', [ $this, 'printFormInsert' ] );
|
23 |
add_action( 'lostpassword_post', [ $this, 'checkLostPassword' ], 10, 1 );
|
24 |
}
|
25 |
|
46 |
}
|
47 |
|
48 |
/**
|
49 |
+
* @param \WP_Error $wpError
|
50 |
* @return \WP_Error
|
51 |
*/
|
52 |
+
public function checkLostPassword( $wpError ) {
|
53 |
try {
|
54 |
$this->setUserToAudit( sanitize_user( Services::Request()->post( 'user_login', '' ) ) )
|
55 |
->setActionToAudit( 'reset-password' )
|
56 |
->checkProviders();
|
57 |
}
|
58 |
catch ( \Exception $e ) {
|
59 |
+
$wpError = $this->giveMeWpError( $wpError );
|
60 |
+
$wpError->add( $this->getCon()->prefix( rand() ), $e->getMessage() );
|
61 |
}
|
62 |
+
return $wpError;
|
63 |
}
|
64 |
|
65 |
/**
|
66 |
+
* @param \WP_Error $wpError
|
67 |
* @param string $sUsername
|
68 |
* @return \WP_Error
|
69 |
*/
|
70 |
+
public function checkRegister( $wpError, $sUsername ) {
|
71 |
try {
|
72 |
$this->setUserToAudit( $sUsername )
|
73 |
->setActionToAudit( 'register' )
|
74 |
->checkProviders();
|
75 |
}
|
76 |
catch ( \Exception $e ) {
|
77 |
+
$wpError = $this->giveMeWpError( $wpError );
|
78 |
+
$wpError->add( $this->getCon()->prefix( rand() ), $e->getMessage() );
|
79 |
}
|
80 |
+
return $wpError;
|
81 |
}
|
82 |
}
|
src/lib/src/Modules/LoginGuard/Lib/AntiBot/ProtectionProviders/AntiBot.php
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\AntiBot\ProtectionProviders;
|
4 |
+
|
5 |
+
use FernleafSystems\Wordpress\Services\Services;
|
6 |
+
|
7 |
+
class AntiBot extends BaseProtectionProvider {
|
8 |
+
|
9 |
+
/**
|
10 |
+
* @inheritDoc
|
11 |
+
*/
|
12 |
+
public function performCheck( $oForm ) {
|
13 |
+
if ( $this->isFactorTested() ) {
|
14 |
+
return;
|
15 |
+
}
|
16 |
+
$isBot = $this->getCon()
|
17 |
+
->getModule_IPs()
|
18 |
+
->getBotSignalsController()
|
19 |
+
->isBot( Services::IP()->getRequestIp() );
|
20 |
+
if ( $isBot ) {
|
21 |
+
$this->processFailure();
|
22 |
+
throw new \Exception( __( 'Failed AntiBot Test', 'wp-simple-firewall' ) );
|
23 |
+
}
|
24 |
+
}
|
25 |
+
|
26 |
+
public function buildFormInsert( $oFormProvider ) {
|
27 |
+
return '';
|
28 |
+
}
|
29 |
+
}
|
src/lib/src/Modules/LoginGuard/Lib/AntiBot/ProtectionProviders/BaseProtectionProvider.php
CHANGED
@@ -9,23 +9,25 @@ abstract class BaseProtectionProvider {
|
|
9 |
|
10 |
use ModConsumer;
|
11 |
|
|
|
|
|
|
|
|
|
12 |
/**
|
13 |
-
* @var
|
14 |
*/
|
15 |
-
|
16 |
|
17 |
public function __construct() {
|
18 |
add_action( 'wp_loaded', [ $this, 'setup' ], 0 ); // 0 to ensure WPS Hide Login doesn't fire before us.
|
|
|
19 |
}
|
20 |
|
21 |
public function setup() {
|
22 |
}
|
23 |
|
24 |
-
|
25 |
-
|
26 |
-
*/
|
27 |
-
public function isFactorTested() {
|
28 |
-
return (bool)$this->bFactorTested;
|
29 |
}
|
30 |
|
31 |
/**
|
@@ -34,6 +36,11 @@ abstract class BaseProtectionProvider {
|
|
34 |
*/
|
35 |
abstract public function buildFormInsert( $oFormProvider );
|
36 |
|
|
|
|
|
|
|
|
|
|
|
37 |
/**
|
38 |
* @param LoginGuard\Lib\AntiBot\FormProviders\BaseFormProvider $oForm
|
39 |
* @throws \Exception
|
@@ -41,11 +48,11 @@ abstract class BaseProtectionProvider {
|
|
41 |
abstract public function performCheck( $oForm );
|
42 |
|
43 |
/**
|
44 |
-
* @param bool $
|
45 |
* @return $this
|
46 |
*/
|
47 |
-
public function setFactorTested( $
|
48 |
-
$this->
|
49 |
return $this;
|
50 |
}
|
51 |
|
@@ -58,4 +65,16 @@ abstract class BaseProtectionProvider {
|
|
58 |
$this->getCon()->fireEvent( 'login_block' );
|
59 |
return $this;
|
60 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
}
|
9 |
|
10 |
use ModConsumer;
|
11 |
|
12 |
+
private $factorTested = false;
|
13 |
+
|
14 |
+
protected $factorBuilt = false;
|
15 |
+
|
16 |
/**
|
17 |
+
* @var string[]
|
18 |
*/
|
19 |
+
protected $enqueueHandles = [];
|
20 |
|
21 |
public function __construct() {
|
22 |
add_action( 'wp_loaded', [ $this, 'setup' ], 0 ); // 0 to ensure WPS Hide Login doesn't fire before us.
|
23 |
+
add_action( 'wp_footer', [ $this, 'maybeDequeueScript' ] );
|
24 |
}
|
25 |
|
26 |
public function setup() {
|
27 |
}
|
28 |
|
29 |
+
public function isFactorTested() :bool {
|
30 |
+
return $this->factorTested;
|
|
|
|
|
|
|
31 |
}
|
32 |
|
33 |
/**
|
36 |
*/
|
37 |
abstract public function buildFormInsert( $oFormProvider );
|
38 |
|
39 |
+
public function setAsInsertBuilt() :self {
|
40 |
+
$this->factorBuilt = true;
|
41 |
+
return $this;
|
42 |
+
}
|
43 |
+
|
44 |
/**
|
45 |
* @param LoginGuard\Lib\AntiBot\FormProviders\BaseFormProvider $oForm
|
46 |
* @throws \Exception
|
48 |
abstract public function performCheck( $oForm );
|
49 |
|
50 |
/**
|
51 |
+
* @param bool $tested
|
52 |
* @return $this
|
53 |
*/
|
54 |
+
public function setFactorTested( bool $tested ) {
|
55 |
+
$this->factorTested = $tested;
|
56 |
return $this;
|
57 |
}
|
58 |
|
65 |
$this->getCon()->fireEvent( 'login_block' );
|
66 |
return $this;
|
67 |
}
|
68 |
+
|
69 |
+
public function maybeDequeueScript() {
|
70 |
+
if ( !$this->isFactorJsRequired() ) {
|
71 |
+
foreach ( $this->enqueueHandles as $handle ) {
|
72 |
+
wp_dequeue_script( $handle );
|
73 |
+
}
|
74 |
+
}
|
75 |
+
}
|
76 |
+
|
77 |
+
protected function isFactorJsRequired() :bool {
|
78 |
+
return $this->factorBuilt;
|
79 |
+
}
|
80 |
}
|
src/lib/src/Modules/LoginGuard/Lib/AntiBot/ProtectionProviders/GaspJs.php
CHANGED
@@ -2,6 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\AntiBot\ProtectionProviders;
|
4 |
|
|
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
|
6 |
use FernleafSystems\Wordpress\Services\Services;
|
7 |
|
@@ -9,11 +10,51 @@ class GaspJs extends BaseProtectionProvider {
|
|
9 |
|
10 |
public function setup() {
|
11 |
if ( Services::Request()->query( 'wp_service_worker', 0 ) != 1 ) {
|
12 |
-
add_action( '
|
13 |
-
add_action( '
|
14 |
}
|
15 |
}
|
16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
/**
|
18 |
* @inheritDoc
|
19 |
*/
|
@@ -24,88 +65,51 @@ class GaspJs extends BaseProtectionProvider {
|
|
24 |
|
25 |
/** @var LoginGuard\ModCon $mod */
|
26 |
$mod = $this->getMod();
|
|
|
|
|
27 |
$this->setFactorTested( true );
|
28 |
|
29 |
-
$
|
30 |
-
$sGaspCheckBox = $req->post( $mod->getGaspKey() );
|
31 |
-
$sHoney = $req->post( 'icwp_wpsf_login_email' );
|
32 |
|
33 |
-
$
|
34 |
-
$
|
35 |
|
36 |
-
$
|
37 |
-
$
|
38 |
-
if ( empty( $
|
39 |
$this->getCon()->fireEvent(
|
40 |
'botbox_fail',
|
41 |
[
|
42 |
'audit' => [
|
43 |
-
'user_login' => $
|
44 |
-
'action' => $
|
45 |
]
|
46 |
]
|
47 |
);
|
48 |
-
$
|
49 |
}
|
50 |
-
elseif ( !empty( $
|
51 |
$this->getCon()->fireEvent(
|
52 |
'honeypot_fail',
|
53 |
[
|
54 |
'audit' => [
|
55 |
-
'user_login' => $
|
56 |
-
'action' => $
|
57 |
]
|
58 |
]
|
59 |
);
|
60 |
-
$
|
61 |
}
|
62 |
else {
|
63 |
-
$
|
64 |
}
|
65 |
|
66 |
-
if ( !$
|
67 |
$this->processFailure();
|
68 |
-
throw new \Exception( $
|
69 |
}
|
70 |
}
|
71 |
|
72 |
-
public function onWpEnqueueJs() {
|
73 |
-
$con = $this->getCon();
|
74 |
-
/** @var LoginGuard\ModCon $mod */
|
75 |
-
$mod = $this->getMod();
|
76 |
-
/** @var LoginGuard\Options $opts */
|
77 |
-
$opts = $this->getOptions();
|
78 |
-
|
79 |
-
$asset = 'shield-antibot';
|
80 |
-
$uniq = $con->prefix( $asset );
|
81 |
-
wp_register_script(
|
82 |
-
$uniq,
|
83 |
-
$con->getPluginUrl_Js( $asset ),
|
84 |
-
[ 'jquery' ],
|
85 |
-
$con->getVersion()
|
86 |
-
);
|
87 |
-
wp_enqueue_script( $uniq );
|
88 |
-
|
89 |
-
wp_localize_script(
|
90 |
-
$uniq,
|
91 |
-
'icwp_wpsf_vars_lpantibot',
|
92 |
-
[
|
93 |
-
'form_selectors' => implode( ',', $opts->getAntiBotFormSelectors() ),
|
94 |
-
'uniq' => preg_replace( '#[^a-zA-Z0-9]#', '', apply_filters( 'icwp_shield_lp_gasp_uniqid', uniqid() ) ),
|
95 |
-
'cbname' => $mod->getGaspKey(),
|
96 |
-
'strings' => [
|
97 |
-
'label' => $mod->getTextImAHuman(),
|
98 |
-
'alert' => $mod->getTextPleaseCheckBox(),
|
99 |
-
'loading' => __( 'Loading', 'wp-simple-firewall' )
|
100 |
-
],
|
101 |
-
'flags' => [
|
102 |
-
'gasp' => $opts->isEnabledGaspCheck(),
|
103 |
-
'captcha' => $mod->isEnabledCaptcha(),
|
104 |
-
]
|
105 |
-
]
|
106 |
-
);
|
107 |
-
}
|
108 |
-
|
109 |
/**
|
110 |
* @inheritDoc
|
111 |
*/
|
@@ -119,4 +123,10 @@ class GaspJs extends BaseProtectionProvider {
|
|
119 |
]
|
120 |
);
|
121 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
122 |
}
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\AntiBot\ProtectionProviders;
|
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 |
|
10 |
|
11 |
public function setup() {
|
12 |
if ( Services::Request()->query( 'wp_service_worker', 0 ) != 1 ) {
|
13 |
+
add_action( 'wp', [ $this, 'enqueueJS' ] );
|
14 |
+
add_action( 'login_init', [ $this, 'enqueueJS' ] );
|
15 |
}
|
16 |
}
|
17 |
|
18 |
+
public function enqueueJS() {
|
19 |
+
add_filter( 'shield/custom_enqueues', function ( array $enqueues ) {
|
20 |
+
$enqueues[ Enqueue::JS ][] = 'shield/loginbot';
|
21 |
+
|
22 |
+
add_filter( 'shield/custom_localisations', function ( array $localz ) {
|
23 |
+
/** @var LoginGuard\ModCon $mod */
|
24 |
+
$mod = $this->getMod();
|
25 |
+
/** @var LoginGuard\Options $opts */
|
26 |
+
$opts = $this->getOptions();
|
27 |
+
|
28 |
+
$ts = Services::Request()->ts();
|
29 |
+
$nonce = $mod->getAjaxActionData( 'comment_token'.Services::IP()->getRequestIp() );
|
30 |
+
$nonce[ 'ts' ] = $ts;
|
31 |
+
$nonce[ 'post_id' ] = Services::WpPost()->getCurrentPostId();
|
32 |
+
|
33 |
+
$localz[] = [
|
34 |
+
'shield/loginbot',
|
35 |
+
'icwp_wpsf_vars_lpantibot',
|
36 |
+
[
|
37 |
+
'form_selectors' => implode( ',', $opts->getAntiBotFormSelectors() ),
|
38 |
+
'uniq' => preg_replace( '#[^a-zA-Z0-9]#', '', apply_filters( 'icwp_shield_lp_gasp_uniqid', uniqid() ) ),
|
39 |
+
'cbname' => $mod->getGaspKey(),
|
40 |
+
'strings' => [
|
41 |
+
'label' => $mod->getTextImAHuman(),
|
42 |
+
'alert' => $mod->getTextPleaseCheckBox(),
|
43 |
+
'loading' => __( 'Loading', 'wp-simple-firewall' )
|
44 |
+
],
|
45 |
+
'flags' => [
|
46 |
+
'gasp' => $opts->isEnabledGaspCheck(),
|
47 |
+
'captcha' => $mod->isEnabledCaptcha(),
|
48 |
+
]
|
49 |
+
]
|
50 |
+
];
|
51 |
+
return $localz;
|
52 |
+
} );
|
53 |
+
|
54 |
+
return $enqueues;
|
55 |
+
} );
|
56 |
+
}
|
57 |
+
|
58 |
/**
|
59 |
* @inheritDoc
|
60 |
*/
|
65 |
|
66 |
/** @var LoginGuard\ModCon $mod */
|
67 |
$mod = $this->getMod();
|
68 |
+
$req = Services::Request();
|
69 |
+
|
70 |
$this->setFactorTested( true );
|
71 |
|
72 |
+
$gasp = $req->post( $mod->getGaspKey() );
|
|
|
|
|
73 |
|
74 |
+
$username = $oForm->getUserToAudit();
|
75 |
+
$action = $oForm->getActionToAudit();
|
76 |
|
77 |
+
$valid = false;
|
78 |
+
$errorMsg = '';
|
79 |
+
if ( empty( $gasp ) ) {
|
80 |
$this->getCon()->fireEvent(
|
81 |
'botbox_fail',
|
82 |
[
|
83 |
'audit' => [
|
84 |
+
'user_login' => $username,
|
85 |
+
'action' => $action,
|
86 |
]
|
87 |
]
|
88 |
);
|
89 |
+
$errorMsg = __( "Please check that box to say you're human, and not a bot.", 'wp-simple-firewall' );
|
90 |
}
|
91 |
+
elseif ( !empty( $req->post( 'icwp_wpsf_login_email' ) ) ) {
|
92 |
$this->getCon()->fireEvent(
|
93 |
'honeypot_fail',
|
94 |
[
|
95 |
'audit' => [
|
96 |
+
'user_login' => $username,
|
97 |
+
'action' => $action,
|
98 |
]
|
99 |
]
|
100 |
);
|
101 |
+
$errorMsg = __( 'You appear to be a bot.', 'wp-simple-firewall' );
|
102 |
}
|
103 |
else {
|
104 |
+
$valid = true;
|
105 |
}
|
106 |
|
107 |
+
if ( !$valid ) {
|
108 |
$this->processFailure();
|
109 |
+
throw new \Exception( $errorMsg );
|
110 |
}
|
111 |
}
|
112 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
113 |
/**
|
114 |
* @inheritDoc
|
115 |
*/
|
123 |
]
|
124 |
);
|
125 |
}
|
126 |
+
|
127 |
+
protected function isFactorJsRequired() :bool {
|
128 |
+
/** @var LoginGuard\Options $opts */
|
129 |
+
$opts = $this->getOptions();
|
130 |
+
return parent::isFactorJsRequired() || !empty( $opts->getAntiBotFormSelectors() );
|
131 |
+
}
|
132 |
}
|
src/lib/src/Modules/LoginGuard/Lib/CooldownFlagFile.php
CHANGED
@@ -5,10 +5,6 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib;
|
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules;
|
6 |
use FernleafSystems\Wordpress\Services\Services;
|
7 |
|
8 |
-
/**
|
9 |
-
* Class CooldownFlagFile
|
10 |
-
* @package FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib
|
11 |
-
*/
|
12 |
class CooldownFlagFile {
|
13 |
|
14 |
use Modules\ModConsumer;
|
@@ -33,16 +29,16 @@ class CooldownFlagFile {
|
|
33 |
* @return string
|
34 |
*/
|
35 |
public function getFlagFilePath() {
|
36 |
-
return
|
37 |
}
|
38 |
|
39 |
/**
|
40 |
* @return int
|
41 |
*/
|
42 |
public function getSecondsSinceLastLogin() {
|
43 |
-
$
|
44 |
-
$
|
45 |
-
$nLastLogin = $
|
46 |
return ( Services::Request()->ts() - $nLastLogin );
|
47 |
}
|
48 |
|
@@ -50,10 +46,10 @@ class CooldownFlagFile {
|
|
50 |
* @return $this
|
51 |
*/
|
52 |
public function updateCooldownFlag() {
|
53 |
-
$
|
54 |
-
$
|
55 |
-
$
|
56 |
-
$
|
57 |
return $this;
|
58 |
}
|
59 |
}
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules;
|
6 |
use FernleafSystems\Wordpress\Services\Services;
|
7 |
|
|
|
|
|
|
|
|
|
8 |
class CooldownFlagFile {
|
9 |
|
10 |
use Modules\ModConsumer;
|
29 |
* @return string
|
30 |
*/
|
31 |
public function getFlagFilePath() {
|
32 |
+
return $this->getCon()->getPluginCachePath( 'mode.login_throttled' );
|
33 |
}
|
34 |
|
35 |
/**
|
36 |
* @return int
|
37 |
*/
|
38 |
public function getSecondsSinceLastLogin() {
|
39 |
+
$FS = Services::WpFs();
|
40 |
+
$file = $this->getFlagFilePath();
|
41 |
+
$nLastLogin = $FS->exists( $file ) ? $FS->getModifiedTime( $file ) : 0;
|
42 |
return ( Services::Request()->ts() - $nLastLogin );
|
43 |
}
|
44 |
|
46 |
* @return $this
|
47 |
*/
|
48 |
public function updateCooldownFlag() {
|
49 |
+
$FS = Services::WpFs();
|
50 |
+
$file = $this->getFlagFilePath();
|
51 |
+
$FS->deleteFile( $file );
|
52 |
+
$FS->touch( $file, Services::Request()->ts() );
|
53 |
return $this;
|
54 |
}
|
55 |
}
|
src/lib/src/Modules/LoginGuard/Lib/Rename/RenameLogin.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\Rename;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Logic\
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
|
8 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Options;
|
@@ -11,13 +11,9 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
11 |
class RenameLogin {
|
12 |
|
13 |
use Modules\ModConsumer;
|
14 |
-
use
|
15 |
|
16 |
-
protected function
|
17 |
-
add_action( 'init', [ $this, 'onWpInit' ], 9 );
|
18 |
-
}
|
19 |
-
|
20 |
-
protected function canRun() {
|
21 |
/** @var Options $opts */
|
22 |
$opts = $this->getOptions();
|
23 |
return !Services::IP()->isLoopback()
|
@@ -25,6 +21,10 @@ class RenameLogin {
|
|
25 |
&& !$this->hasPluginConflict() && !$this->hasUnsupportedConfiguration();
|
26 |
}
|
27 |
|
|
|
|
|
|
|
|
|
28 |
public function onWpInit() {
|
29 |
/** @var LoginGuard\ModCon $mod */
|
30 |
$mod = $this->getMod();
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\Rename;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Logic\ExecOnce;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard;
|
8 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Options;
|
11 |
class RenameLogin {
|
12 |
|
13 |
use Modules\ModConsumer;
|
14 |
+
use ExecOnce;
|
15 |
|
16 |
+
protected function canRun() :bool {
|
|
|
|
|
|
|
|
|
17 |
/** @var Options $opts */
|
18 |
$opts = $this->getOptions();
|
19 |
return !Services::IP()->isLoopback()
|
21 |
&& !$this->hasPluginConflict() && !$this->hasUnsupportedConfiguration();
|
22 |
}
|
23 |
|
24 |
+
protected function run() {
|
25 |
+
add_action( 'init', [ $this, 'onWpInit' ], 9 );
|
26 |
+
}
|
27 |
+
|
28 |
public function onWpInit() {
|
29 |
/** @var LoginGuard\ModCon $mod */
|
30 |
$mod = $this->getMod();
|
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/LoginIntentPage.php
CHANGED
@@ -96,7 +96,7 @@ class LoginIntentPage {
|
|
96 |
],
|
97 |
'flags' => [
|
98 |
'can_skip_mfa' => $opts->isMfaSkip(),
|
99 |
-
'show_branded_links' => !$
|
100 |
]
|
101 |
];
|
102 |
|
@@ -130,8 +130,8 @@ class LoginIntentPage {
|
|
130 |
'time_remaining' => $nTimeRemaining,
|
131 |
],
|
132 |
'hrefs' => [
|
133 |
-
'css_bootstrap' => $con->urls->forCss( '
|
134 |
-
'js_bootstrap' => $con->urls->forJs( '
|
135 |
'shield_logo' => 'https://ps.w.org/wp-simple-firewall/assets/banner-772x250.png',
|
136 |
'what_is_this' => 'https://support.getshieldsecurity.com/support/solutions/articles/3000064840',
|
137 |
],
|
@@ -140,7 +140,7 @@ class LoginIntentPage {
|
|
140 |
'favicon' => $con->urls->forImage( 'pluginlogo_24x24.png' ),
|
141 |
],
|
142 |
'flags' => [
|
143 |
-
'show_branded_links' => !$
|
144 |
'has_u2f' => isset( $oIC->getProvidersForUser(
|
145 |
Services::WpUsers()->getCurrentWpUser(), true )[ LoginGuard\Lib\TwoFactor\Provider\U2F::SLUG ] )
|
146 |
],
|
96 |
],
|
97 |
'flags' => [
|
98 |
'can_skip_mfa' => $opts->isMfaSkip(),
|
99 |
+
'show_branded_links' => !$mod->isEnabledWhitelabel(), // white label mitigation
|
100 |
]
|
101 |
];
|
102 |
|
130 |
'time_remaining' => $nTimeRemaining,
|
131 |
],
|
132 |
'hrefs' => [
|
133 |
+
'css_bootstrap' => $con->urls->forCss( 'bootstrap' ),
|
134 |
+
'js_bootstrap' => $con->urls->forJs( 'bootstrap' ),
|
135 |
'shield_logo' => 'https://ps.w.org/wp-simple-firewall/assets/banner-772x250.png',
|
136 |
'what_is_this' => 'https://support.getshieldsecurity.com/support/solutions/articles/3000064840',
|
137 |
],
|
140 |
'favicon' => $con->urls->forImage( 'pluginlogo_24x24.png' ),
|
141 |
],
|
142 |
'flags' => [
|
143 |
+
'show_branded_links' => !$mod->isEnabledWhitelabel(), // white label mitigation
|
144 |
'has_u2f' => isset( $oIC->getProvidersForUser(
|
145 |
Services::WpUsers()->getCurrentWpUser(), true )[ LoginGuard\Lib\TwoFactor\Provider\U2F::SLUG ] )
|
146 |
],
|
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Profiles/CustomForms.php
CHANGED
@@ -2,14 +2,14 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\LoginGuard\Lib\TwoFactor\Profiles;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Logic\
|
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
|
13 |
use MfaControllerConsumer;
|
14 |
use WpUserConsumer;
|
15 |
|
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 |
|
src/lib/src/Modules/LoginGuard/Lib/TwoFactor/Provider/Yubikey.php
CHANGED
@@ -13,7 +13,6 @@ class Yubikey extends BaseProvider {
|
|
13 |
const URL_YUBIKEY_VERIFY = 'https://api.yubico.com/wsapi/2.0/verify';
|
14 |
|
15 |
public function setupProfile() {
|
16 |
-
|
17 |
add_filter( 'shield/custom_enqueues', function ( array $enqueues, $hook ) {
|
18 |
if ( in_array( $hook, [ 'profile.php', ] ) ) {
|
19 |
$enqueues[ Enqueue::JS ][] = 'shield/userprofile';
|
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';
|
src/lib/src/Modules/LoginGuard/ModCon.php
CHANGED
@@ -29,20 +29,25 @@ class ModCon extends BaseShield\ModCon {
|
|
29 |
->sendEmailVerifyCanSend();
|
30 |
}
|
31 |
|
32 |
-
$
|
33 |
-
foreach ( $
|
34 |
-
$
|
35 |
-
if ( empty( $
|
36 |
-
unset( $
|
37 |
}
|
38 |
else {
|
39 |
-
$
|
40 |
}
|
41 |
}
|
42 |
-
$opts->setOpt( 'antibot_form_ids', array_values( array_unique( $
|
43 |
|
44 |
$this->cleanLoginUrlPath();
|
45 |
$this->ensureCorrectCaptchaConfig();
|
|
|
|
|
|
|
|
|
|
|
46 |
}
|
47 |
|
48 |
public function ensureCorrectCaptchaConfig() {
|
@@ -69,6 +74,7 @@ class ModCon extends BaseShield\ModCon {
|
|
69 |
$this->processEmailSendVerify();
|
70 |
break;
|
71 |
default:
|
|
|
72 |
break;
|
73 |
}
|
74 |
}
|
29 |
->sendEmailVerifyCanSend();
|
30 |
}
|
31 |
|
32 |
+
$IDs = $opts->getOpt( 'antibot_form_ids', [] );
|
33 |
+
foreach ( $IDs as $nKey => $id ) {
|
34 |
+
$id = trim( strip_tags( $id ) );
|
35 |
+
if ( empty( $id ) ) {
|
36 |
+
unset( $IDs[ $nKey ] );
|
37 |
}
|
38 |
else {
|
39 |
+
$IDs[ $nKey ] = $id;
|
40 |
}
|
41 |
}
|
42 |
+
$opts->setOpt( 'antibot_form_ids', array_values( array_unique( $IDs ) ) );
|
43 |
|
44 |
$this->cleanLoginUrlPath();
|
45 |
$this->ensureCorrectCaptchaConfig();
|
46 |
+
|
47 |
+
if ( $opts->isEnabledAntiBot() ) {
|
48 |
+
$opts->setOpt( 'enable_google_recaptcha_login', 'disabled' );
|
49 |
+
$opts->setOpt( 'enable_login_gasp_check', 'N' );
|
50 |
+
}
|
51 |
}
|
52 |
|
53 |
public function ensureCorrectCaptchaConfig() {
|
74 |
$this->processEmailSendVerify();
|
75 |
break;
|
76 |
default:
|
77 |
+
parent::handleModAction( $action );
|
78 |
break;
|
79 |
}
|
80 |
}
|
src/lib/src/Modules/LoginGuard/Options.php
CHANGED
@@ -26,10 +26,7 @@ class Options extends BaseShield\Options {
|
|
26 |
return (string)$this->getOpt( 'rename_wplogin_path', '' );
|
27 |
}
|
28 |
|
29 |
-
|
30 |
-
* @return array
|
31 |
-
*/
|
32 |
-
public function getEmail2FaRoles() {
|
33 |
/** @var ModCon $mod */
|
34 |
$mod = $this->getMod();
|
35 |
$roles = $this->getOpt( 'two_factor_auth_user_roles', [] );
|
@@ -76,7 +73,12 @@ class Options extends BaseShield\Options {
|
|
76 |
}
|
77 |
|
78 |
public function isEnabledGaspCheck() :bool {
|
79 |
-
return $this->isOpt( 'enable_login_gasp_check', 'Y' )
|
|
|
|
|
|
|
|
|
|
|
80 |
}
|
81 |
|
82 |
public function isEnabledEmailAuthAnyUserSet() :bool {
|
@@ -103,17 +105,11 @@ class Options extends BaseShield\Options {
|
|
103 |
return $this->isProtect( 'login' );
|
104 |
}
|
105 |
|
106 |
-
|
107 |
-
* @return bool
|
108 |
-
*/
|
109 |
-
public function isProtectLostPassword() {
|
110 |
return $this->isProtect( 'password' );
|
111 |
}
|
112 |
|
113 |
-
|
114 |
-
* @return bool
|
115 |
-
*/
|
116 |
-
public function isProtectRegister() {
|
117 |
return $this->isProtect( 'register' );
|
118 |
}
|
119 |
|
@@ -121,9 +117,9 @@ class Options extends BaseShield\Options {
|
|
121 |
* @param string $location - see config for keys, e.g. login, register, password, checkout_woo
|
122 |
* @return bool
|
123 |
*/
|
124 |
-
public function isProtect( $location ) {
|
125 |
-
$
|
126 |
-
return in_array( $location, is_array( $
|
127 |
}
|
128 |
|
129 |
public function isUseLoginIntentPage() :bool {
|
26 |
return (string)$this->getOpt( 'rename_wplogin_path', '' );
|
27 |
}
|
28 |
|
29 |
+
public function getEmail2FaRoles() :array {
|
|
|
|
|
|
|
30 |
/** @var ModCon $mod */
|
31 |
$mod = $this->getMod();
|
32 |
$roles = $this->getOpt( 'two_factor_auth_user_roles', [] );
|
73 |
}
|
74 |
|
75 |
public function isEnabledGaspCheck() :bool {
|
76 |
+
return $this->isOpt( 'enable_login_gasp_check', 'Y' )
|
77 |
+
&& !$this->isEnabledAntiBot();
|
78 |
+
}
|
79 |
+
|
80 |
+
public function isEnabledAntiBot() :bool {
|
81 |
+
return $this->isOpt( 'enable_antibot_check', 'Y' );
|
82 |
}
|
83 |
|
84 |
public function isEnabledEmailAuthAnyUserSet() :bool {
|
105 |
return $this->isProtect( 'login' );
|
106 |
}
|
107 |
|
108 |
+
public function isProtectLostPassword() :bool {
|
|
|
|
|
|
|
109 |
return $this->isProtect( 'password' );
|
110 |
}
|
111 |
|
112 |
+
public function isProtectRegister() :bool {
|
|
|
|
|
|
|
113 |
return $this->isProtect( 'register' );
|
114 |
}
|
115 |
|
117 |
* @param string $location - see config for keys, e.g. login, register, password, checkout_woo
|
118 |
* @return bool
|
119 |
*/
|
120 |
+
public function isProtect( $location ) :bool {
|
121 |
+
$locs = $this->getOpt( 'bot_protection_locations' );
|
122 |
+
return in_array( $location, is_array( $locs ) ? $locs : $this->getOptDefault( 'bot_protection_locations' ) );
|
123 |
}
|
124 |
|
125 |
public function isUseLoginIntentPage() :bool {
|
src/lib/src/Modules/LoginGuard/Processor.php
CHANGED
@@ -21,8 +21,18 @@ class Processor extends BaseShield\Processor {
|
|
21 |
->execute();
|
22 |
|
23 |
if ( !$mod->isVisitorWhitelisted() ) {
|
24 |
-
|
|
|
|
|
|
|
|
|
25 |
$mod->getLoginIntentController()->run();
|
26 |
}
|
27 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
}
|
21 |
->execute();
|
22 |
|
23 |
if ( !$mod->isVisitorWhitelisted() ) {
|
24 |
+
|
25 |
+
add_action( 'init', function () {
|
26 |
+
$this->launchAntiBot();
|
27 |
+
}, -100 );
|
28 |
+
|
29 |
$mod->getLoginIntentController()->run();
|
30 |
}
|
31 |
}
|
32 |
+
|
33 |
+
private function launchAntiBot() {
|
34 |
+
( new Lib\AntiBot\AntibotSetup() )
|
35 |
+
->setMod( $this->getMod() )
|
36 |
+
->execute();
|
37 |
+
}
|
38 |
}
|
src/lib/src/Modules/LoginGuard/Strings.php
CHANGED
@@ -218,6 +218,18 @@ class Strings extends Base\Strings {
|
|
218 |
.'<br/><strong>'.sprintf( '%s - %s', __( 'Important', 'wp-simple-firewall' ), __( "Some forms are more dynamic than others so if you experience problems, please use non-Invisible CAPTCHA.", 'wp-simple-firewall' ) ).'</strong>';
|
219 |
break;
|
220 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
221 |
case 'bot_protection_locations' :
|
222 |
$name = __( 'Protection Locations', 'wp-simple-firewall' );
|
223 |
$summary = __( 'Which Forms Should Be Protected', 'wp-simple-firewall' );
|
218 |
.'<br/><strong>'.sprintf( '%s - %s', __( 'Important', 'wp-simple-firewall' ), __( "Some forms are more dynamic than others so if you experience problems, please use non-Invisible CAPTCHA.", 'wp-simple-firewall' ) ).'</strong>';
|
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' ) )
|
230 |
+
];
|
231 |
+
break;
|
232 |
+
|
233 |
case 'bot_protection_locations' :
|
234 |
$name = __( 'Protection Locations', 'wp-simple-firewall' );
|
235 |
$summary = __( 'Which Forms Should Be Protected', 'wp-simple-firewall' );
|
src/lib/src/Modules/Plugin/AjaxHandler.php
CHANGED
@@ -12,58 +12,58 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
|
|
12 |
protected function processAjaxAction( string $action ) :array {
|
13 |
switch ( $action ) {
|
14 |
case 'bulk_action':
|
15 |
-
$
|
16 |
break;
|
17 |
|
18 |
case 'delete_forceoff':
|
19 |
-
$
|
20 |
break;
|
21 |
|
22 |
case 'render_table_adminnotes':
|
23 |
-
$
|
24 |
break;
|
25 |
|
26 |
case 'note_delete':
|
27 |
-
$
|
28 |
break;
|
29 |
|
30 |
case 'note_insert':
|
31 |
-
$
|
32 |
break;
|
33 |
|
34 |
case 'import_from_site':
|
35 |
-
$
|
36 |
break;
|
37 |
|
38 |
case 'plugin_badge_close':
|
39 |
-
$
|
40 |
break;
|
41 |
|
42 |
case 'set_plugin_tracking':
|
43 |
-
$
|
44 |
break;
|
45 |
|
46 |
case 'send_deactivate_survey':
|
47 |
-
$
|
48 |
break;
|
49 |
|
50 |
case 'sgoptimizer_turnoff':
|
51 |
-
$
|
52 |
break;
|
53 |
|
54 |
case 'ipdetect':
|
55 |
-
$
|
56 |
break;
|
57 |
|
58 |
case 'mark_tour_finished':
|
59 |
-
$
|
60 |
break;
|
61 |
|
62 |
default:
|
63 |
-
$
|
64 |
}
|
65 |
|
66 |
-
return $
|
67 |
}
|
68 |
|
69 |
private function ajaxExec_SendDeactivateSurvey() :array {
|
@@ -234,19 +234,19 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
|
|
234 |
/** @var ModCon $mod */
|
235 |
$mod = $this->getMod();
|
236 |
$success = false;
|
237 |
-
$
|
238 |
|
239 |
-
$
|
240 |
if ( !$mod->getCanAdminNotes() ) {
|
241 |
$msg = __( "Sorry, the Admin Notes feature isn't available.", 'wp-simple-firewall' );
|
242 |
}
|
243 |
-
elseif ( empty( $
|
244 |
$msg = __( 'Sorry, but it appears your note was empty.', 'wp-simple-firewall' );
|
245 |
}
|
246 |
else {
|
247 |
-
/** @var Shield\Databases\AdminNotes\Insert $
|
248 |
-
$
|
249 |
-
$success = $
|
250 |
$msg = $success ? __( 'Note created successfully.', 'wp-simple-firewall' ) : __( 'Note could not be created.', 'wp-simple-firewall' );
|
251 |
}
|
252 |
return [
|
12 |
protected function processAjaxAction( string $action ) :array {
|
13 |
switch ( $action ) {
|
14 |
case 'bulk_action':
|
15 |
+
$response = $this->ajaxExec_BulkItemAction();
|
16 |
break;
|
17 |
|
18 |
case 'delete_forceoff':
|
19 |
+
$response = $this->ajaxExec_DeleteForceOff();
|
20 |
break;
|
21 |
|
22 |
case 'render_table_adminnotes':
|
23 |
+
$response = $this->ajaxExec_RenderTableAdminNotes();
|
24 |
break;
|
25 |
|
26 |
case 'note_delete':
|
27 |
+
$response = $this->ajaxExec_AdminNotesDelete();
|
28 |
break;
|
29 |
|
30 |
case 'note_insert':
|
31 |
+
$response = $this->ajaxExec_AdminNotesInsert();
|
32 |
break;
|
33 |
|
34 |
case 'import_from_site':
|
35 |
+
$response = $this->ajaxExec_ImportFromSite();
|
36 |
break;
|
37 |
|
38 |
case 'plugin_badge_close':
|
39 |
+
$response = $this->ajaxExec_PluginBadgeClose();
|
40 |
break;
|
41 |
|
42 |
case 'set_plugin_tracking':
|
43 |
+
$response = $this->ajaxExec_SetPluginTrackingPerm();
|
44 |
break;
|
45 |
|
46 |
case 'send_deactivate_survey':
|
47 |
+
$response = $this->ajaxExec_SendDeactivateSurvey();
|
48 |
break;
|
49 |
|
50 |
case 'sgoptimizer_turnoff':
|
51 |
+
$response = $this->ajaxExec_TurnOffSiteGroundOptions();
|
52 |
break;
|
53 |
|
54 |
case 'ipdetect':
|
55 |
+
$response = $this->ajaxExec_IpDetect();
|
56 |
break;
|
57 |
|
58 |
case 'mark_tour_finished':
|
59 |
+
$response = $this->ajaxExec_MarkTourFinished();
|
60 |
break;
|
61 |
|
62 |
default:
|
63 |
+
$response = parent::processAjaxAction( $action );
|
64 |
}
|
65 |
|
66 |
+
return $response;
|
67 |
}
|
68 |
|
69 |
private function ajaxExec_SendDeactivateSurvey() :array {
|
234 |
/** @var ModCon $mod */
|
235 |
$mod = $this->getMod();
|
236 |
$success = false;
|
237 |
+
$formParams = $this->getAjaxFormParams();
|
238 |
|
239 |
+
$note = trim( $formParams[ 'admin_note' ] ?? '' );
|
240 |
if ( !$mod->getCanAdminNotes() ) {
|
241 |
$msg = __( "Sorry, the Admin Notes feature isn't available.", 'wp-simple-firewall' );
|
242 |
}
|
243 |
+
elseif ( empty( $note ) ) {
|
244 |
$msg = __( 'Sorry, but it appears your note was empty.', 'wp-simple-firewall' );
|
245 |
}
|
246 |
else {
|
247 |
+
/** @var Shield\Databases\AdminNotes\Insert $inserter */
|
248 |
+
$inserter = $mod->getDbHandler_Notes()->getQueryInserter();
|
249 |
+
$success = $inserter->create( $note );
|
250 |
$msg = $success ? __( 'Note created successfully.', 'wp-simple-firewall' ) : __( 'Note could not be created.', 'wp-simple-firewall' );
|
251 |
}
|
252 |
return [
|
src/lib/src/Modules/Plugin/Components/PluginBadge.php
CHANGED
@@ -74,7 +74,7 @@ class PluginBadge {
|
|
74 |
else {
|
75 |
$badgeUrl = 'https://shsec.io/wpsecurityfirewall';
|
76 |
$name = $con->getHumanName();
|
77 |
-
$logo = $con->
|
78 |
|
79 |
$lic = $con->getModule_License()
|
80 |
->getLicenseHandler()
|
74 |
else {
|
75 |
$badgeUrl = 'https://shsec.io/wpsecurityfirewall';
|
76 |
$name = $con->getHumanName();
|
77 |
+
$logo = $con->urls->forImage( 'shield/shield-security-logo-colour-32px.png' );
|
78 |
|
79 |
$lic = $con->getModule_License()
|
80 |
->getLicenseHandler()
|
src/lib/src/Modules/Plugin/Debug.php
CHANGED
@@ -3,18 +3,10 @@
|
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin;
|
4 |
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules;
|
6 |
-
use FernleafSystems\Wordpress\Services\Utilities\Net\IpIdentify;
|
7 |
|
8 |
class Debug extends Modules\Base\Debug {
|
9 |
|
10 |
public function run() {
|
11 |
-
$this->ipID();
|
12 |
die();
|
13 |
}
|
14 |
-
|
15 |
-
private function ipID() {
|
16 |
-
$id = ( new IpIdentify( '198.61.176.9' ) )
|
17 |
-
->run();
|
18 |
-
var_dump( $id );
|
19 |
-
}
|
20 |
}
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin;
|
4 |
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules;
|
|
|
6 |
|
7 |
class Debug extends Modules\Base\Debug {
|
8 |
|
9 |
public function run() {
|
|
|
10 |
die();
|
11 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
}
|
src/lib/src/Modules/Plugin/Insights/DashboardCards.php
CHANGED
@@ -48,14 +48,17 @@ class DashboardCards {
|
|
48 |
/** @var Plugin\ModCon $mod */
|
49 |
$mod = $this->getMod();
|
50 |
|
|
|
|
|
51 |
return $mod->renderTemplate(
|
52 |
'/wpadmin_pages/insights/dashboard/card_settings.twig',
|
53 |
[
|
54 |
'c' => [
|
55 |
'title' => __( 'Shield Settings', 'wp-simple-firewall' ),
|
56 |
-
'img' => $con->
|
|
|
57 |
'paras' => [
|
58 |
-
sprintf( __( "%s settings are arranged into modules.", 'wp-simple-firewall' ), $
|
59 |
.' '.__( 'Choose the module you need from the dropdown.', 'wp-simple-firewall' )
|
60 |
],
|
61 |
'actions' => [
|
@@ -81,7 +84,7 @@ class DashboardCards {
|
|
81 |
);
|
82 |
}
|
83 |
|
84 |
-
protected function renderStandardCard( $card ) {
|
85 |
/** @var Plugin\ModCon $mod */
|
86 |
$mod = $this->getMod();
|
87 |
return $mod->renderTemplate(
|
@@ -97,6 +100,8 @@ class DashboardCards {
|
|
97 |
$modInsights = $con->getModule_Insights();
|
98 |
$modPlugin = $con->getModule_Plugin();
|
99 |
|
|
|
|
|
100 |
/** @var AdminNotes\EntryVO $note */
|
101 |
$note = $modPlugin->getDbHandler_Notes()->getQuerySelector()->first();
|
102 |
$latestNote = $note instanceof AdminNotes\EntryVO ?
|
@@ -107,9 +112,10 @@ class DashboardCards {
|
|
107 |
|
108 |
'overview' => [
|
109 |
'title' => __( 'Security Overview', 'wp-simple-firewall' ),
|
110 |
-
'img' => $con->
|
|
|
111 |
'paras' => [
|
112 |
-
sprintf( __( "Review your entire
|
113 |
],
|
114 |
'actions' => [
|
115 |
[
|
@@ -121,10 +127,11 @@ class DashboardCards {
|
|
121 |
|
122 |
'scans' => [
|
123 |
'title' => __( 'Scans and Protection', 'wp-simple-firewall' ),
|
124 |
-
'img' => $con->
|
|
|
125 |
'paras' => [
|
126 |
-
sprintf( __( "Use %s Scans to automatically detect and repair intrusions on your site.", 'wp-simple-firewall' ), $
|
127 |
-
sprintf( __( "%s scans WordPress core files, plugins, themes and will detect Malware (ShieldPRO).", 'wp-simple-firewall' ), $
|
128 |
],
|
129 |
'actions' => [
|
130 |
[
|
@@ -140,9 +147,10 @@ class DashboardCards {
|
|
140 |
|
141 |
'sec_admin' => [
|
142 |
'title' => __( 'Security Admin', 'wp-simple-firewall' ),
|
143 |
-
'img' => $con->
|
|
|
144 |
'paras' => [
|
145 |
-
sprintf( __( "Restrict access to %s itself and prevent unwanted changes to your site by other administrators.", 'wp-simple-firewall' ), $
|
146 |
],
|
147 |
'actions' => [
|
148 |
[
|
@@ -152,9 +160,24 @@ class DashboardCards {
|
|
152 |
]
|
153 |
],
|
154 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
155 |
'free_trial' => [
|
156 |
'title' => __( 'Free ShieldPRO Trial', 'wp-simple-firewall' ),
|
157 |
-
'img' => $con->
|
158 |
'paras' => [
|
159 |
__( "Full, unrestricted access to ShieldPRO with no obligation.", 'wp-simple-firewall' ),
|
160 |
__( "Turn-on the ShieldPRO trial within 60 seconds.", 'wp-simple-firewall' )
|
@@ -171,7 +194,8 @@ class DashboardCards {
|
|
171 |
|
172 |
'ips' => [
|
173 |
'title' => __( 'IP Blocking and Bypass', 'wp-simple-firewall' ),
|
174 |
-
'img' => $con->
|
|
|
175 |
'paras' => [
|
176 |
__( "Shield automatically detects and blocks bad IP addresses based on your security settings.", 'wp-simple-firewall' ),
|
177 |
__( "The IP Analysis Tool shows you all information for a given IP as it relates to your site.", 'wp-simple-firewall' ),
|
@@ -190,7 +214,8 @@ class DashboardCards {
|
|
190 |
|
191 |
'audit_trail' => [
|
192 |
'title' => __( 'Audit Trail', 'wp-simple-firewall' ),
|
193 |
-
'img' => $con->
|
|
|
194 |
'paras' => [
|
195 |
__( "Provides in-depth logging for all major WordPress events.", 'wp-simple-firewall' ),
|
196 |
],
|
@@ -208,7 +233,8 @@ class DashboardCards {
|
|
208 |
|
209 |
'traffic' => [
|
210 |
'title' => __( 'Traffic Logging', 'wp-simple-firewall' ),
|
211 |
-
'img' => $con->
|
|
|
212 |
'paras' => [
|
213 |
__( "Use traffic logging to monitor visitor requests to your site.", 'wp-simple-firewall' ),
|
214 |
__( "Traffic Rate Limiting lets you throttle requests from any single visitor.", 'wp-simple-firewall' ),
|
@@ -227,25 +253,27 @@ class DashboardCards {
|
|
227 |
|
228 |
'users' => [
|
229 |
'title' => __( 'WordPress Users', 'wp-simple-firewall' ),
|
230 |
-
'img' => $con->
|
|
|
231 |
'paras' => [
|
232 |
__( "Adds fine control over user sessions, account re-use, password strength and expiration, and user suspension.", 'wp-simple-firewall' ),
|
233 |
],
|
234 |
'actions' => [
|
235 |
[
|
236 |
-
'text' => __(
|
237 |
-
'href' => $
|
238 |
],
|
239 |
[
|
240 |
-
'text' => __(
|
241 |
-
'href' => $
|
242 |
],
|
243 |
]
|
244 |
],
|
245 |
|
246 |
'comments' => [
|
247 |
'title' => __( 'Comment SPAM', 'wp-simple-firewall' ),
|
248 |
-
'img' => $con->
|
|
|
249 |
'paras' => [
|
250 |
__( "Shield blocks 100% of all automated comments by bots (the most common type of SPAM).", 'wp-simple-firewall' ).
|
251 |
' '.__( "The Human SPAM filter will look for common spam words and content.", 'wp-simple-firewall' ),
|
@@ -268,7 +296,7 @@ class DashboardCards {
|
|
268 |
|
269 |
'import' => [
|
270 |
'title' => __( 'Import/Export', 'wp-simple-firewall' ),
|
271 |
-
'img' => $con->
|
272 |
'paras' => [
|
273 |
__( "Use the import/export feature to quickly setup a new site based on the settings of another site.", 'wp-simple-firewall' ),
|
274 |
__( "You can also setup automatic syncing of settings between sites.", 'wp-simple-firewall' ),
|
@@ -287,7 +315,7 @@ class DashboardCards {
|
|
287 |
|
288 |
'license' => [
|
289 |
'title' => __( 'Go PRO!', 'wp-simple-firewall' ),
|
290 |
-
'img' => $con->
|
291 |
'paras' => [
|
292 |
__( "By upgrading to ShieldPRO, you support ongoing Shield development and get access to exclusive PRO features.", 'wp-simple-firewall' ),
|
293 |
],
|
@@ -307,7 +335,8 @@ class DashboardCards {
|
|
307 |
|
308 |
'notes' => [
|
309 |
'title' => __( 'Admin Notes', 'wp-simple-firewall' ),
|
310 |
-
'img' => $con->
|
|
|
311 |
'paras' => [
|
312 |
__( "Use these to keep note of important items or to-dos.", 'wp-simple-firewall' ),
|
313 |
$latestNote
|
@@ -322,7 +351,7 @@ class DashboardCards {
|
|
322 |
|
323 |
'whitelabel' => [
|
324 |
'title' => __( 'Whitelabel', 'wp-simple-firewall' ),
|
325 |
-
'img' => $con->
|
326 |
'paras' => [
|
327 |
__( "Re-brand the Shield Security plugin your image.", 'wp-simple-firewall' ),
|
328 |
__( "Use this to enhance and solidify your brand with your clients and visitors.", 'wp-simple-firewall' ),
|
@@ -338,7 +367,8 @@ class DashboardCards {
|
|
338 |
|
339 |
'integrations' => [
|
340 |
'title' => __( '3rd Party Integrations', 'wp-simple-firewall' ),
|
341 |
-
'
|
|
|
342 |
'paras' => [
|
343 |
__( "Shield integrates with 3rd party plugins and services.", 'wp-simple-firewall' ),
|
344 |
__( "Determine what integrations Shield should use and manage the settings for them.", 'wp-simple-firewall' ),
|
@@ -353,9 +383,9 @@ class DashboardCards {
|
|
353 |
|
354 |
'docs' => [
|
355 |
'title' => __( 'Docs', 'wp-simple-firewall' ),
|
356 |
-
'img' => $con->
|
357 |
'paras' => [
|
358 |
-
sprintf( __( "Important information about %s releases and changes.", 'wp-simple-firewall' ), $
|
359 |
],
|
360 |
'actions' => [
|
361 |
[
|
@@ -367,7 +397,7 @@ class DashboardCards {
|
|
367 |
|
368 |
'debug' => [
|
369 |
'title' => __( 'Debug Info', 'wp-simple-firewall' ),
|
370 |
-
'img' => $con->
|
371 |
'paras' => [
|
372 |
__( "If you contact support, they may ask you to show them your Debug Information page.", 'wp-simple-firewall' ),
|
373 |
__( "It's also an interesting place to see a summary of your WordPress configuration in 1 place.", 'wp-simple-firewall' ),
|
@@ -393,6 +423,7 @@ class DashboardCards {
|
|
393 |
'scans',
|
394 |
'free_trial',
|
395 |
'sec_admin',
|
|
|
396 |
'ips',
|
397 |
'audit_trail',
|
398 |
'traffic',
|
48 |
/** @var Plugin\ModCon $mod */
|
49 |
$mod = $this->getMod();
|
50 |
|
51 |
+
$name = $con->getHumanName();
|
52 |
+
|
53 |
return $mod->renderTemplate(
|
54 |
'/wpadmin_pages/insights/dashboard/card_settings.twig',
|
55 |
[
|
56 |
'c' => [
|
57 |
'title' => __( 'Shield Settings', 'wp-simple-firewall' ),
|
58 |
+
'img' => $con->urls->forImage( 'bootstrap/sliders.svg' ),
|
59 |
+
'introjs' => sprintf( __( "%s is a big plugin split into modules, and each with their own options - use these jump-off points to find the specific option you need.", 'wp-simple-firewall' ), $name ),
|
60 |
'paras' => [
|
61 |
+
sprintf( __( "%s settings are arranged into modules.", 'wp-simple-firewall' ), $name )
|
62 |
.' '.__( 'Choose the module you need from the dropdown.', 'wp-simple-firewall' )
|
63 |
],
|
64 |
'actions' => [
|
84 |
);
|
85 |
}
|
86 |
|
87 |
+
protected function renderStandardCard( array $card ) :string {
|
88 |
/** @var Plugin\ModCon $mod */
|
89 |
$mod = $this->getMod();
|
90 |
return $mod->renderTemplate(
|
100 |
$modInsights = $con->getModule_Insights();
|
101 |
$modPlugin = $con->getModule_Plugin();
|
102 |
|
103 |
+
$name = $con->getHumanName();
|
104 |
+
|
105 |
/** @var AdminNotes\EntryVO $note */
|
106 |
$note = $modPlugin->getDbHandler_Notes()->getQuerySelector()->first();
|
107 |
$latestNote = $note instanceof AdminNotes\EntryVO ?
|
112 |
|
113 |
'overview' => [
|
114 |
'title' => __( 'Security Overview', 'wp-simple-firewall' ),
|
115 |
+
'img' => $con->urls->forImage( 'bootstrap/binoculars.svg' ),
|
116 |
+
'introjs' => sprintf( __( "Review your entire Shield Security configuration at a glance to see what's working and what's not.", 'wp-simple-firewall' ), $name ),
|
117 |
'paras' => [
|
118 |
+
sprintf( __( "Review your entire %s security configuration at a glance to see what's working and what's not.", 'wp-simple-firewall' ), $name ),
|
119 |
],
|
120 |
'actions' => [
|
121 |
[
|
127 |
|
128 |
'scans' => [
|
129 |
'title' => __( 'Scans and Protection', 'wp-simple-firewall' ),
|
130 |
+
'img' => $con->urls->forImage( 'bootstrap/shield-shaded.svg' ),
|
131 |
+
'introjs' => sprintf( __( "Run a %s scan at any time, or view the results from the latest scan.", 'wp-simple-firewall' ), $name ),
|
132 |
'paras' => [
|
133 |
+
sprintf( __( "Use %s Scans to automatically detect and repair intrusions on your site.", 'wp-simple-firewall' ), $name ),
|
134 |
+
sprintf( __( "%s scans WordPress core files, plugins, themes and will detect Malware (ShieldPRO).", 'wp-simple-firewall' ), $name ),
|
135 |
],
|
136 |
'actions' => [
|
137 |
[
|
147 |
|
148 |
'sec_admin' => [
|
149 |
'title' => __( 'Security Admin', 'wp-simple-firewall' ),
|
150 |
+
'img' => $con->urls->forImage( 'bootstrap/person-badge.svg' ),
|
151 |
+
'introjs' => sprintf( __( "Lock down access to %s itself to specific WP Administrators.", 'wp-simple-firewall' ), $name ),
|
152 |
'paras' => [
|
153 |
+
sprintf( __( "Restrict access to %s itself and prevent unwanted changes to your site by other administrators.", 'wp-simple-firewall' ), $name ),
|
154 |
],
|
155 |
'actions' => [
|
156 |
[
|
160 |
]
|
161 |
],
|
162 |
|
163 |
+
'reports' => [
|
164 |
+
'title' => __( 'Reports and Stats', 'wp-simple-firewall' ),
|
165 |
+
'img' => $con->urls->forImage( 'bootstrap/graph-up.svg' ),
|
166 |
+
'introjs' => sprintf( __( "See the effect on your site security by %s in numbers", 'wp-simple-firewall' ), $name ),
|
167 |
+
'paras' => [
|
168 |
+
sprintf( __( "Display charts to see how %s is performing over time and in which areas your site has been most impacted.", 'wp-simple-firewall' ), $name ),
|
169 |
+
],
|
170 |
+
'actions' => [
|
171 |
+
[
|
172 |
+
'text' => __( "View Reports and Stats", 'wp-simple-firewall' ),
|
173 |
+
'href' => $modInsights->getUrl_SubInsightsPage( 'reports' ),
|
174 |
+
],
|
175 |
+
]
|
176 |
+
],
|
177 |
+
|
178 |
'free_trial' => [
|
179 |
'title' => __( 'Free ShieldPRO Trial', 'wp-simple-firewall' ),
|
180 |
+
'img' => $con->urls->forImage( 'bootstrap/emoji-smile.svg' ),
|
181 |
'paras' => [
|
182 |
__( "Full, unrestricted access to ShieldPRO with no obligation.", 'wp-simple-firewall' ),
|
183 |
__( "Turn-on the ShieldPRO trial within 60 seconds.", 'wp-simple-firewall' )
|
194 |
|
195 |
'ips' => [
|
196 |
'title' => __( 'IP Blocking and Bypass', 'wp-simple-firewall' ),
|
197 |
+
'img' => $con->urls->forImage( 'bootstrap/diagram-3.svg' ),
|
198 |
+
'introjs' => __( "Protection begins by detecting bad bots - Review and Analyse all visitor IPs that have an impact on your site.", 'wp-simple-firewall' ),
|
199 |
'paras' => [
|
200 |
__( "Shield automatically detects and blocks bad IP addresses based on your security settings.", 'wp-simple-firewall' ),
|
201 |
__( "The IP Analysis Tool shows you all information for a given IP as it relates to your site.", 'wp-simple-firewall' ),
|
214 |
|
215 |
'audit_trail' => [
|
216 |
'title' => __( 'Audit Trail', 'wp-simple-firewall' ),
|
217 |
+
'img' => $con->urls->forImage( 'bootstrap/person-lines-fill.svg' ),
|
218 |
+
'introjs' => __( "Track and review all important actions taken on your site - see the Who, What and When.", 'wp-simple-firewall' ),
|
219 |
'paras' => [
|
220 |
__( "Provides in-depth logging for all major WordPress events.", 'wp-simple-firewall' ),
|
221 |
],
|
233 |
|
234 |
'traffic' => [
|
235 |
'title' => __( 'Traffic Logging', 'wp-simple-firewall' ),
|
236 |
+
'img' => $con->urls->forImage( 'bootstrap/stoplights.svg' ),
|
237 |
+
'introjs' => __( "Monitor and watch traffic as it hits your site.", 'wp-simple-firewall' ),
|
238 |
'paras' => [
|
239 |
__( "Use traffic logging to monitor visitor requests to your site.", 'wp-simple-firewall' ),
|
240 |
__( "Traffic Rate Limiting lets you throttle requests from any single visitor.", 'wp-simple-firewall' ),
|
253 |
|
254 |
'users' => [
|
255 |
'title' => __( 'WordPress Users', 'wp-simple-firewall' ),
|
256 |
+
'img' => $con->urls->forImage( 'bootstrap/people.svg' ),
|
257 |
+
'introjs' => __( "Set user session timeouts and passwords requirements.", 'wp-simple-firewall' ),
|
258 |
'paras' => [
|
259 |
__( "Adds fine control over user sessions, account re-use, password strength and expiration, and user suspension.", 'wp-simple-firewall' ),
|
260 |
],
|
261 |
'actions' => [
|
262 |
[
|
263 |
+
'text' => __( 'View User Sessions', 'wp-simple-firewall' ),
|
264 |
+
'href' => $modInsights->getUrl_SubInsightsPage( 'users' ),
|
265 |
],
|
266 |
[
|
267 |
+
'text' => __( 'User Settings', 'wp-simple-firewall' ),
|
268 |
+
'href' => $con->getModule_UserManagement()->getUrl_AdminPage(),
|
269 |
],
|
270 |
]
|
271 |
],
|
272 |
|
273 |
'comments' => [
|
274 |
'title' => __( 'Comment SPAM', 'wp-simple-firewall' ),
|
275 |
+
'img' => $con->urls->forImage( 'bootstrap/chat-right-dots-fill.svg' ),
|
276 |
+
'introjs' => __( "Block all Comment SPAM from bots and even detect SPAMMY human comments.", 'wp-simple-firewall' ),
|
277 |
'paras' => [
|
278 |
__( "Shield blocks 100% of all automated comments by bots (the most common type of SPAM).", 'wp-simple-firewall' ).
|
279 |
' '.__( "The Human SPAM filter will look for common spam words and content.", 'wp-simple-firewall' ),
|
296 |
|
297 |
'import' => [
|
298 |
'title' => __( 'Import/Export', 'wp-simple-firewall' ),
|
299 |
+
'img' => $con->urls->forImage( 'bootstrap/arrow-down-up.svg' ),
|
300 |
'paras' => [
|
301 |
__( "Use the import/export feature to quickly setup a new site based on the settings of another site.", 'wp-simple-firewall' ),
|
302 |
__( "You can also setup automatic syncing of settings between sites.", 'wp-simple-firewall' ),
|
315 |
|
316 |
'license' => [
|
317 |
'title' => __( 'Go PRO!', 'wp-simple-firewall' ),
|
318 |
+
'img' => $con->urls->forImage( 'bootstrap/award.svg' ),
|
319 |
'paras' => [
|
320 |
__( "By upgrading to ShieldPRO, you support ongoing Shield development and get access to exclusive PRO features.", 'wp-simple-firewall' ),
|
321 |
],
|
335 |
|
336 |
'notes' => [
|
337 |
'title' => __( 'Admin Notes', 'wp-simple-firewall' ),
|
338 |
+
'img' => $con->urls->forImage( 'bootstrap/pencil-square.svg' ),
|
339 |
+
'introjs' => __( "Review and Analyse all visitor IPs that have an impact on your site.", 'wp-simple-firewall' ),
|
340 |
'paras' => [
|
341 |
__( "Use these to keep note of important items or to-dos.", 'wp-simple-firewall' ),
|
342 |
$latestNote
|
351 |
|
352 |
'whitelabel' => [
|
353 |
'title' => __( 'Whitelabel', 'wp-simple-firewall' ),
|
354 |
+
'img' => $con->urls->forImage( 'bootstrap/sticky.svg' ),
|
355 |
'paras' => [
|
356 |
__( "Re-brand the Shield Security plugin your image.", 'wp-simple-firewall' ),
|
357 |
__( "Use this to enhance and solidify your brand with your clients and visitors.", 'wp-simple-firewall' ),
|
367 |
|
368 |
'integrations' => [
|
369 |
'title' => __( '3rd Party Integrations', 'wp-simple-firewall' ),
|
370 |
+
'introjs' => __( "Integrate with your favourite plugins to block SPAM and manage Shield better.", 'wp-simple-firewall' ),
|
371 |
+
'img' => $con->urls->forImage( 'bootstrap/link-45deg.svg' ),
|
372 |
'paras' => [
|
373 |
__( "Shield integrates with 3rd party plugins and services.", 'wp-simple-firewall' ),
|
374 |
__( "Determine what integrations Shield should use and manage the settings for them.", 'wp-simple-firewall' ),
|
383 |
|
384 |
'docs' => [
|
385 |
'title' => __( 'Docs', 'wp-simple-firewall' ),
|
386 |
+
'img' => $con->urls->forImage( 'bootstrap/book-half.svg' ),
|
387 |
'paras' => [
|
388 |
+
sprintf( __( "Important information about %s releases and changes.", 'wp-simple-firewall' ), $name ),
|
389 |
],
|
390 |
'actions' => [
|
391 |
[
|
397 |
|
398 |
'debug' => [
|
399 |
'title' => __( 'Debug Info', 'wp-simple-firewall' ),
|
400 |
+
'img' => $con->urls->forImage( 'bootstrap/bug.svg' ),
|
401 |
'paras' => [
|
402 |
__( "If you contact support, they may ask you to show them your Debug Information page.", 'wp-simple-firewall' ),
|
403 |
__( "It's also an interesting place to see a summary of your WordPress configuration in 1 place.", 'wp-simple-firewall' ),
|
423 |
'scans',
|
424 |
'free_trial',
|
425 |
'sec_admin',
|
426 |
+
'reports',
|
427 |
'ips',
|
428 |
'audit_trail',
|
429 |
'traffic',
|
src/lib/src/Modules/Plugin/Insights/OverviewCards.php
CHANGED
@@ -46,11 +46,11 @@ class OverviewCards extends Shield\Modules\Base\Insights\OverviewCards {
|
|
46 |
'href' => $mod->getUrl_DirectLinkToOption( 'visitor_address_source' ),
|
47 |
];
|
48 |
|
49 |
-
$
|
50 |
$cards[ 'recap' ] = [
|
51 |
'name' => __( 'CAPTCHA', 'wp-simple-firewall' ),
|
52 |
-
'state' => $
|
53 |
-
'summary' => $
|
54 |
__( 'CAPTCHA keys have been provided', 'wp-simple-firewall' )
|
55 |
: __( "CAPTCHA keys haven't been provided", 'wp-simple-firewall' ),
|
56 |
'href' => $mod->getUrl_DirectLinkToSection( 'section_third_party_captcha' ),
|
46 |
'href' => $mod->getUrl_DirectLinkToOption( 'visitor_address_source' ),
|
47 |
];
|
48 |
|
49 |
+
$captchaReady = $mod->getCaptchaCfg()->ready;
|
50 |
$cards[ 'recap' ] = [
|
51 |
'name' => __( 'CAPTCHA', 'wp-simple-firewall' ),
|
52 |
+
'state' => $captchaReady ? 1 : 0,
|
53 |
+
'summary' => $captchaReady ?
|
54 |
__( 'CAPTCHA keys have been provided', 'wp-simple-firewall' )
|
55 |
: __( "CAPTCHA keys haven't been provided", 'wp-simple-firewall' ),
|
56 |
'href' => $mod->getUrl_DirectLinkToSection( 'section_third_party_captcha' ),
|
src/lib/src/Modules/Plugin/Lib/Captcha/CaptchaConfigVO.php
CHANGED
@@ -1,8 +1,8 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Lib\Captcha;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Data\Adapter\
|
6 |
|
7 |
/**
|
8 |
* Class CaptchaConfigVO
|
@@ -16,32 +16,29 @@ use FernleafSystems\Utilities\Data\Adapter\StdClassAdapter;
|
|
16 |
* @property string $url_api
|
17 |
* @property string $js_handle
|
18 |
*/
|
19 |
-
class CaptchaConfigVO {
|
20 |
|
21 |
const PROV_GOOGLE_RECAP2 = 'grecaptcha';
|
22 |
const PROV_HCAPTCHA = 'hcaptcha';
|
23 |
-
use StdClassAdapter {
|
24 |
-
__get as __adapterGet;
|
25 |
-
}
|
26 |
|
27 |
/**
|
28 |
-
* @param string $
|
29 |
* @return mixed
|
30 |
*/
|
31 |
-
public function __get( $
|
32 |
|
33 |
-
$
|
34 |
|
35 |
-
switch ( $
|
36 |
|
37 |
case 'ready':
|
38 |
-
$
|
39 |
break;
|
40 |
|
41 |
default:
|
42 |
break;
|
43 |
}
|
44 |
|
45 |
-
return $
|
46 |
}
|
47 |
}
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Lib\Captcha;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
|
6 |
|
7 |
/**
|
8 |
* Class CaptchaConfigVO
|
16 |
* @property string $url_api
|
17 |
* @property string $js_handle
|
18 |
*/
|
19 |
+
class CaptchaConfigVO extends DynPropertiesClass {
|
20 |
|
21 |
const PROV_GOOGLE_RECAP2 = 'grecaptcha';
|
22 |
const PROV_HCAPTCHA = 'hcaptcha';
|
|
|
|
|
|
|
23 |
|
24 |
/**
|
25 |
+
* @param string $key
|
26 |
* @return mixed
|
27 |
*/
|
28 |
+
public function __get( string $key ) {
|
29 |
|
30 |
+
$value = parent::__get( $key );
|
31 |
|
32 |
+
switch ( $key ) {
|
33 |
|
34 |
case 'ready':
|
35 |
+
$value = !empty( $this->key ) && !empty( $this->secret );
|
36 |
break;
|
37 |
|
38 |
default:
|
39 |
break;
|
40 |
}
|
41 |
|
42 |
+
return $value;
|
43 |
}
|
44 |
}
|
src/lib/src/Modules/Plugin/Lib/Debug/Collate.php
CHANGED
@@ -65,7 +65,7 @@ class Collate {
|
|
65 |
$diff = ( new WorldTimeApi() )->diffServerWithReal();
|
66 |
}
|
67 |
catch ( \Exception $e ) {
|
68 |
-
$diff = 'failed';
|
69 |
}
|
70 |
|
71 |
return [
|
@@ -173,6 +173,11 @@ class Collate {
|
|
173 |
sprintf( '%s (rows: ~%s)', 'Ready', $dbh->getQuerySelector()->count() )
|
174 |
: 'Missing';
|
175 |
|
|
|
|
|
|
|
|
|
|
|
176 |
$dbh = $con->getModule_HackGuard()->getDbHandler_ScanResults();
|
177 |
$data[ 'DB Table: Scan' ] = $dbh->isReady() ?
|
178 |
sprintf( '%s (rows: ~%s)', 'Ready', $dbh->getQuerySelector()->count() )
|
@@ -195,20 +200,25 @@ class Collate {
|
|
195 |
$con = $this->getCon();
|
196 |
$modPlug = $con->getModule_Plugin();
|
197 |
|
198 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
199 |
$data = [
|
200 |
-
|
201 |
-
'Handshake ShieldNET'
|
202 |
-
|
203 |
-
'WP Hashes Ping'
|
204 |
];
|
205 |
|
206 |
-
$
|
207 |
-
$
|
208 |
-
$data[ 'Ping License Server' ] = $
|
209 |
|
210 |
-
$
|
211 |
-
$data[ 'Write TMP DIR' ] = empty( $sTmpPath ) ? 'No' : 'Yes: '.$sTmpPath;
|
212 |
|
213 |
return $data;
|
214 |
}
|
65 |
$diff = ( new WorldTimeApi() )->diffServerWithReal();
|
66 |
}
|
67 |
catch ( \Exception $e ) {
|
68 |
+
$diff = 'failed: '.$e->getMessage();
|
69 |
}
|
70 |
|
71 |
return [
|
173 |
sprintf( '%s (rows: ~%s)', 'Ready', $dbh->getQuerySelector()->count() )
|
174 |
: 'Missing';
|
175 |
|
176 |
+
$dbh = $con->getModule_IPs()->getDbHandler_BotSignals();
|
177 |
+
$data[ 'DB Table: Bot Signals' ] = $dbh->isReady() ?
|
178 |
+
sprintf( '%s (rows: ~%s)', 'Ready', $dbh->getQuerySelector()->count() )
|
179 |
+
: 'Missing';
|
180 |
+
|
181 |
$dbh = $con->getModule_HackGuard()->getDbHandler_ScanResults();
|
182 |
$data[ 'DB Table: Scan' ] = $dbh->isReady() ?
|
183 |
sprintf( '%s (rows: ~%s)', 'Ready', $dbh->getQuerySelector()->count() )
|
200 |
$con = $this->getCon();
|
201 |
$modPlug = $con->getModule_Plugin();
|
202 |
|
203 |
+
try {
|
204 |
+
$loopback = $modPlug->canSiteLoopback() ? 'Yes' : 'No';
|
205 |
+
}
|
206 |
+
catch ( \Exception $e ) {
|
207 |
+
$loopback = 'Unknown - requires WP v5.4+';
|
208 |
+
}
|
209 |
+
|
210 |
$data = [
|
211 |
+
'Can Loopback Request' => $loopback,
|
212 |
+
'Handshake ShieldNET' => $modPlug->getShieldNetApiController()
|
213 |
+
->canHandshake() ? 'Yes' : 'No',
|
214 |
+
'WP Hashes Ping' => ( new ApiPing() )->ping() ? 'Yes' : 'No',
|
215 |
];
|
216 |
|
217 |
+
$licPing = new Licenses\Keyless\Ping();
|
218 |
+
$licPing->lookup_url_stub = $con->getModule_License()->getOptions()->getDef( 'license_store_url_api' );
|
219 |
+
$data[ 'Ping License Server' ] = $licPing->ping() ? 'Yes' : 'No';
|
220 |
|
221 |
+
$data[ 'Write TMP/Cache DIR' ] = $con->hasCacheDir() ?'Yes: '.$con->getPluginCachePath() : 'No' ;
|
|
|
222 |
|
223 |
return $data;
|
224 |
}
|
src/lib/src/Modules/Plugin/Lib/ImportExport/Export.php
CHANGED
@@ -106,9 +106,8 @@ class Export {
|
|
106 |
}
|
107 |
|
108 |
public function toFile() {
|
109 |
-
$aData = $this->toStandardArray();
|
110 |
Services::Response()->downloadStringAsFile(
|
111 |
-
implode( "\n", $
|
112 |
sprintf( 'shieldexport-%s-%s.json',
|
113 |
Services::Data()->urlStripSchema( Services::WpGeneral()->getHomeUrl() ),
|
114 |
date( 'Ymd_His' )
|
106 |
}
|
107 |
|
108 |
public function toFile() {
|
|
|
109 |
Services::Response()->downloadStringAsFile(
|
110 |
+
implode( "\n", $this->toStandardArray() ),
|
111 |
sprintf( 'shieldexport-%s-%s.json',
|
112 |
Services::Data()->urlStripSchema( Services::WpGeneral()->getHomeUrl() ),
|
113 |
date( 'Ymd_His' )
|
src/lib/src/Modules/Plugin/Lib/ImportExport/ImportExportController.php
CHANGED
@@ -130,7 +130,7 @@ class ImportExportController {
|
|
130 |
'can_importexport' => $this->getCon()->isPremiumActive(),
|
131 |
],
|
132 |
'hrefs' => [
|
133 |
-
'export_file_download' => $
|
134 |
],
|
135 |
'strings' => [
|
136 |
'tab_by_file' => __( 'Import From File', 'wp-simple-firewall' ),
|
@@ -173,14 +173,4 @@ class ImportExportController {
|
|
173 |
]
|
174 |
];
|
175 |
}
|
176 |
-
|
177 |
-
/**
|
178 |
-
* @return string
|
179 |
-
*/
|
180 |
-
private function createExportFileDownloadLink() {
|
181 |
-
return add_query_arg(
|
182 |
-
$this->getMod()->getNonceActionData( 'export_file_download' ),
|
183 |
-
$this->getMod()->getUrl_AdminPage()
|
184 |
-
);
|
185 |
-
}
|
186 |
}
|
130 |
'can_importexport' => $this->getCon()->isPremiumActive(),
|
131 |
],
|
132 |
'hrefs' => [
|
133 |
+
'export_file_download' => $mod->createFileDownloadLink( 'plugin_export' )
|
134 |
],
|
135 |
'strings' => [
|
136 |
'tab_by_file' => __( 'Import From File', 'wp-simple-firewall' ),
|
173 |
]
|
174 |
];
|
175 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
176 |
}
|
src/lib/src/Modules/Plugin/Lib/PluginTelemetry.php
CHANGED
@@ -2,7 +2,8 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Lib;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Logic\
|
|
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Databases\Events\Select;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\ModCon;
|
8 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
@@ -12,9 +13,10 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
12 |
class PluginTelemetry {
|
13 |
|
14 |
use ModConsumer;
|
15 |
-
use
|
|
|
16 |
|
17 |
-
protected function canRun() {
|
18 |
/** @var Plugin\Options $opts */
|
19 |
$opts = $this->getOptions();
|
20 |
return $opts->isTrackingEnabled() || !$opts->isTrackingPermissionSet();
|
@@ -36,7 +38,7 @@ class PluginTelemetry {
|
|
36 |
break;
|
37 |
}
|
38 |
|
39 |
-
|
40 |
}
|
41 |
|
42 |
public function runDailyCron() {
|
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;
|
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();
|
38 |
break;
|
39 |
}
|
40 |
|
41 |
+
$this->setupCronHooks();
|
42 |
}
|
43 |
|
44 |
public function runDailyCron() {
|
src/lib/src/Modules/Plugin/Lib/TestCacheDirWrite.php
CHANGED
@@ -5,10 +5,6 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Lib;
|
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
6 |
use FernleafSystems\Wordpress\Services\Services;
|
7 |
|
8 |
-
/**
|
9 |
-
* Class TestCacheDirWrite
|
10 |
-
* @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Lib
|
11 |
-
*/
|
12 |
class TestCacheDirWrite {
|
13 |
|
14 |
use ModConsumer;
|
@@ -21,67 +17,67 @@ class TestCacheDirWrite {
|
|
21 |
* @return $this
|
22 |
*/
|
23 |
protected function run() {
|
24 |
-
$
|
25 |
-
$
|
26 |
|
27 |
-
if ( ( $
|
28 |
-
&& ( $
|
29 |
|
30 |
-
$
|
31 |
-
$
|
32 |
-
|
33 |
-
|
34 |
|
35 |
-
$
|
36 |
-
$
|
37 |
-
$this->getOptions()->setOpt( 'cache_dir_write_test', $
|
38 |
}
|
39 |
return $this;
|
40 |
}
|
41 |
|
42 |
private function canCreateWriteDeleteDir() :bool {
|
43 |
-
$
|
44 |
|
45 |
-
$
|
46 |
|
47 |
-
$
|
48 |
-
$
|
49 |
-
if ( $
|
50 |
-
$sFile = path_join( $
|
51 |
-
$
|
52 |
-
$
|
53 |
-
$
|
54 |
}
|
55 |
-
return $
|
56 |
}
|
57 |
|
58 |
private function canCreateWriteDeleteFile() :bool {
|
59 |
-
$
|
60 |
|
61 |
-
$
|
62 |
|
63 |
-
$
|
64 |
-
$
|
65 |
|
66 |
-
if ( $
|
67 |
-
$
|
68 |
-
$
|
69 |
-
if ( $
|
70 |
-
$
|
71 |
-
$
|
72 |
}
|
73 |
}
|
74 |
-
return $
|
75 |
}
|
76 |
|
77 |
private function getTestData() :array {
|
78 |
-
$
|
79 |
return array_merge(
|
80 |
[
|
81 |
'last_test_at' => 0,
|
82 |
'last_success_at' => 0,
|
83 |
],
|
84 |
-
is_array( $
|
85 |
);
|
86 |
}
|
87 |
}
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
6 |
use FernleafSystems\Wordpress\Services\Services;
|
7 |
|
|
|
|
|
|
|
|
|
8 |
class TestCacheDirWrite {
|
9 |
|
10 |
use ModConsumer;
|
17 |
* @return $this
|
18 |
*/
|
19 |
protected function run() {
|
20 |
+
$data = $this->getTestData();
|
21 |
+
$now = Services::Request()->ts();
|
22 |
|
23 |
+
if ( ( $data[ 'last_success_at' ] === 0 || $now - WEEK_IN_SECONDS > $data[ 'last_success_at' ] )
|
24 |
+
&& ( $now - HOUR_IN_SECONDS > $data[ 'last_test_at' ] ) ) {
|
25 |
|
26 |
+
$rootDir = $this->getCon()->getPluginCachePath();
|
27 |
+
$canWrite = !empty( $rootDir )
|
28 |
+
&& $this->canCreateWriteDeleteFile()
|
29 |
+
&& $this->canCreateWriteDeleteDir();
|
30 |
|
31 |
+
$data[ 'last_success_at' ] = $canWrite ? $now : 0;
|
32 |
+
$data[ 'last_test_at' ] = $now;
|
33 |
+
$this->getOptions()->setOpt( 'cache_dir_write_test', $data );
|
34 |
}
|
35 |
return $this;
|
36 |
}
|
37 |
|
38 |
private function canCreateWriteDeleteDir() :bool {
|
39 |
+
$canWrite = false;
|
40 |
|
41 |
+
$FS = Services::WpFs();
|
42 |
|
43 |
+
$testDir = $this->getCon()->getPluginCachePath( uniqid() );
|
44 |
+
$FS->mkdir( $testDir );
|
45 |
+
if ( $FS->isDir( $testDir ) ) {
|
46 |
+
$sFile = path_join( $testDir, uniqid() );
|
47 |
+
$FS->touch( $sFile );
|
48 |
+
$FS->deleteDir( $testDir );
|
49 |
+
$canWrite = !$FS->isDir( $testDir );
|
50 |
}
|
51 |
+
return $canWrite;
|
52 |
}
|
53 |
|
54 |
private function canCreateWriteDeleteFile() :bool {
|
55 |
+
$canWrite = false;
|
56 |
|
57 |
+
$FS = Services::WpFs();
|
58 |
|
59 |
+
$testFile = $this->getCon()->getPluginCachePath( 'test_write_file.txt' );
|
60 |
+
$FS->touch( $testFile );
|
61 |
|
62 |
+
if ( $FS->exists( $testFile ) ) {
|
63 |
+
$uniq = uniqid();
|
64 |
+
$FS->putFileContent( $testFile, $uniq );
|
65 |
+
if ( $FS->getFileContent( $testFile ) == $uniq ) {
|
66 |
+
$FS->deleteFile( $testFile );
|
67 |
+
$canWrite = !$FS->exists( $testFile );
|
68 |
}
|
69 |
}
|
70 |
+
return $canWrite;
|
71 |
}
|
72 |
|
73 |
private function getTestData() :array {
|
74 |
+
$data = $this->getOptions()->getOpt( 'cache_dir_write_test' );
|
75 |
return array_merge(
|
76 |
[
|
77 |
'last_test_at' => 0,
|
78 |
'last_success_at' => 0,
|
79 |
],
|
80 |
+
is_array( $data ) ? $data : []
|
81 |
);
|
82 |
}
|
83 |
}
|
src/lib/src/Modules/Plugin/Lib/TourManager.php
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Lib;
|
4 |
|
@@ -13,22 +13,20 @@ class TourManager {
|
|
13 |
|
14 |
use ModConsumer;
|
15 |
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
public function canShow( $sTourKey ) {
|
21 |
-
return !Services::WpGeneral()->isMobile() && !$this->isCompleted( $sTourKey );
|
22 |
}
|
23 |
|
24 |
/**
|
25 |
-
* @param string $
|
26 |
* @return bool
|
27 |
*/
|
28 |
-
public function isCompleted( $
|
29 |
try {
|
30 |
-
$
|
31 |
-
$shown = isset( $
|
32 |
}
|
33 |
catch ( \Exception $e ) {
|
34 |
$shown = true; // in-case there's a meta saving issue.
|
@@ -36,34 +34,38 @@ class TourManager {
|
|
36 |
return $shown;
|
37 |
}
|
38 |
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
*/
|
43 |
-
public function setCompleted( $sTourKey ) {
|
44 |
-
$sTourKey = sanitize_key( $sTourKey );
|
45 |
-
if ( !empty( $sTourKey ) ) {
|
46 |
try {
|
47 |
-
$
|
48 |
-
$
|
49 |
-
$this->getCon()
|
50 |
-
->getCurrentUserMeta()->tours = $aTrs;
|
51 |
}
|
52 |
catch ( \Exception $e ) {
|
53 |
}
|
54 |
}
|
55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
}
|
57 |
|
58 |
/**
|
59 |
* @return array
|
60 |
* @throws \Exception
|
61 |
*/
|
62 |
-
|
63 |
-
$
|
64 |
-
if ( empty( $
|
65 |
throw new \Exception( 'Not logged in or invalid user meta' );
|
66 |
}
|
67 |
-
return is_array( $
|
68 |
}
|
69 |
}
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin\Lib;
|
4 |
|
13 |
|
14 |
use ModConsumer;
|
15 |
|
16 |
+
public function getAllTours() :array {
|
17 |
+
return [
|
18 |
+
'dashboard_v1'
|
19 |
+
];
|
|
|
|
|
20 |
}
|
21 |
|
22 |
/**
|
23 |
+
* @param string $tourKey
|
24 |
* @return bool
|
25 |
*/
|
26 |
+
public function isCompleted( string $tourKey ) :bool {
|
27 |
try {
|
28 |
+
$tours = $this->loadUserTourStates();
|
29 |
+
$shown = isset( $tours[ $tourKey ] ) && $tours[ $tourKey ] > 0;
|
30 |
}
|
31 |
catch ( \Exception $e ) {
|
32 |
$shown = true; // in-case there's a meta saving issue.
|
34 |
return $shown;
|
35 |
}
|
36 |
|
37 |
+
public function setCompleted( string $tourKey ) {
|
38 |
+
$tourKey = sanitize_key( $tourKey );
|
39 |
+
if ( !empty( $tourKey ) ) {
|
|
|
|
|
|
|
|
|
40 |
try {
|
41 |
+
$tours = $this->loadUserTourStates();
|
42 |
+
$tours[ $tourKey ] = Services::Request()->ts();
|
43 |
+
$this->getCon()->getCurrentUserMeta()->tours = $tours;
|
|
|
44 |
}
|
45 |
catch ( \Exception $e ) {
|
46 |
}
|
47 |
}
|
48 |
+
}
|
49 |
+
|
50 |
+
public function getUserTourStates() :array {
|
51 |
+
try {
|
52 |
+
$tours = $this->loadUserTourStates();
|
53 |
+
}
|
54 |
+
catch ( \Exception $e ) {
|
55 |
+
$tours = [];
|
56 |
+
}
|
57 |
+
return $tours;
|
58 |
}
|
59 |
|
60 |
/**
|
61 |
* @return array
|
62 |
* @throws \Exception
|
63 |
*/
|
64 |
+
private function loadUserTourStates() :array {
|
65 |
+
$meta = $this->getCon()->getCurrentUserMeta();
|
66 |
+
if ( empty( $meta ) ) {
|
67 |
throw new \Exception( 'Not logged in or invalid user meta' );
|
68 |
}
|
69 |
+
return is_array( $meta->tours ) ? $meta->tours : [];
|
70 |
}
|
71 |
}
|
src/lib/src/Modules/Plugin/ModCon.php
CHANGED
@@ -104,16 +104,19 @@ class ModCon extends BaseShield\ModCon {
|
|
104 |
}
|
105 |
}
|
106 |
|
107 |
-
protected function
|
108 |
-
switch ( $
|
109 |
-
|
110 |
-
case 'export_file_download':
|
111 |
-
header( 'Set-Cookie: fileDownload=true; path=/' );
|
112 |
( new Lib\ImportExport\Export() )
|
113 |
->setMod( $this )
|
114 |
->toFile();
|
115 |
break;
|
|
|
|
|
116 |
|
|
|
|
|
|
|
117 |
case 'import_file_upload':
|
118 |
try {
|
119 |
( new Lib\ImportExport\Import() )
|
@@ -133,30 +136,42 @@ class ModCon extends BaseShield\ModCon {
|
|
133 |
break;
|
134 |
|
135 |
default:
|
|
|
136 |
break;
|
137 |
}
|
138 |
}
|
139 |
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
144 |
}
|
145 |
|
146 |
public function getActivePluginFeatures() :array {
|
147 |
-
$
|
148 |
|
149 |
-
$
|
150 |
-
if (
|
151 |
|
152 |
-
foreach ( $
|
153 |
-
if ( isset( $
|
154 |
continue;
|
155 |
}
|
156 |
-
$
|
157 |
}
|
158 |
}
|
159 |
-
return $
|
160 |
}
|
161 |
|
162 |
public function getLinkToTrackingDataDump() :string {
|
@@ -318,15 +333,6 @@ class ModCon extends BaseShield\ModCon {
|
|
318 |
return Services::Request()->ts() - (int)$this->getOptions()->getOpt( 'activated_at', 0 );
|
319 |
}
|
320 |
|
321 |
-
/**
|
322 |
-
* hidden 20200121
|
323 |
-
* @return bool
|
324 |
-
*/
|
325 |
-
public function getIfShowIntroVideo() :bool {
|
326 |
-
return false && ( $this->getActivateLength() < 8 )
|
327 |
-
&& ( Services::Request()->ts() - $this->getInstallDate() < 15 );
|
328 |
-
}
|
329 |
-
|
330 |
public function getTourManager() :Lib\TourManager {
|
331 |
return ( new Lib\TourManager() )->setMod( $this );
|
332 |
}
|
@@ -503,10 +509,15 @@ class ModCon extends BaseShield\ModCon {
|
|
503 |
];
|
504 |
}
|
505 |
|
|
|
506 |
$locals[] = [
|
507 |
-
'
|
508 |
-
'
|
509 |
-
[
|
|
|
|
|
|
|
|
|
510 |
];
|
511 |
|
512 |
$locals[] = [
|
104 |
}
|
105 |
}
|
106 |
|
107 |
+
protected function handleFileDownload( string $downloadID ) {
|
108 |
+
switch ( $downloadID ) {
|
109 |
+
case 'plugin_export':
|
|
|
|
|
110 |
( new Lib\ImportExport\Export() )
|
111 |
->setMod( $this )
|
112 |
->toFile();
|
113 |
break;
|
114 |
+
}
|
115 |
+
}
|
116 |
|
117 |
+
protected function handleModAction( string $action ) {
|
118 |
+
|
119 |
+
switch ( $action ) {
|
120 |
case 'import_file_upload':
|
121 |
try {
|
122 |
( new Lib\ImportExport\Import() )
|
136 |
break;
|
137 |
|
138 |
default:
|
139 |
+
parent::handleModAction( $action );
|
140 |
break;
|
141 |
}
|
142 |
}
|
143 |
|
144 |
+
/**
|
145 |
+
* @return bool
|
146 |
+
* @throws \Exception
|
147 |
+
*/
|
148 |
+
public function canSiteLoopback() :bool {
|
149 |
+
$canLoopback = false;
|
150 |
+
if ( class_exists( '\WP_Site_Health' ) && method_exists( '\WP_Site_Health', 'get_instance' ) ) {
|
151 |
+
$canLoopback = \WP_Site_Health::get_instance()->get_test_loopback_requests()[ 'status' ] === 'good';
|
152 |
+
}
|
153 |
+
if ( !$canLoopback ) {
|
154 |
+
$canLoopback = Services::HttpRequest()->post( site_url( 'wp-cron.php' ), [
|
155 |
+
'timeout' => 10
|
156 |
+
] );
|
157 |
+
}
|
158 |
+
return $canLoopback;
|
159 |
}
|
160 |
|
161 |
public function getActivePluginFeatures() :array {
|
162 |
+
$features = $this->getDef( 'active_plugin_features' );
|
163 |
|
164 |
+
$available = [];
|
165 |
+
if ( is_array( $features ) ) {
|
166 |
|
167 |
+
foreach ( $features as $feature ) {
|
168 |
+
if ( isset( $feature[ 'hidden' ] ) && $feature[ 'hidden' ] ) {
|
169 |
continue;
|
170 |
}
|
171 |
+
$available[ $feature[ 'slug' ] ] = $feature;
|
172 |
}
|
173 |
}
|
174 |
+
return $available;
|
175 |
}
|
176 |
|
177 |
public function getLinkToTrackingDataDump() :string {
|
333 |
return Services::Request()->ts() - (int)$this->getOptions()->getOpt( 'activated_at', 0 );
|
334 |
}
|
335 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
336 |
public function getTourManager() :Lib\TourManager {
|
337 |
return ( new Lib\TourManager() )->setMod( $this );
|
338 |
}
|
509 |
];
|
510 |
}
|
511 |
|
512 |
+
$tourManager = $this->getTourManager();
|
513 |
$locals[] = [
|
514 |
+
'shield/tours',
|
515 |
+
'shield_vars_tourmanager',
|
516 |
+
[
|
517 |
+
'ajax' => $this->getAjaxActionData( 'mark_tour_finished' ),
|
518 |
+
'tour_states' => $tourManager->getUserTourStates(),
|
519 |
+
'tours' => $tourManager->getAllTours(),
|
520 |
+
]
|
521 |
];
|
522 |
|
523 |
$locals[] = [
|
src/lib/src/Modules/Plugin/Processor.php
CHANGED
@@ -24,7 +24,7 @@ class Processor extends BaseShield\Processor {
|
|
24 |
$mod->getPluginBadgeCon()->run();
|
25 |
|
26 |
( new PluginTelemetry() )
|
27 |
-
->setMod( $
|
28 |
->execute();
|
29 |
|
30 |
if ( $opts->isImportExportPermitted() ) {
|
@@ -62,13 +62,13 @@ class Processor extends BaseShield\Processor {
|
|
62 |
public function runDailyCron() {
|
63 |
$this->getCon()->fireEvent( 'test_cron_run' );
|
64 |
|
65 |
-
/** @var Options $
|
66 |
-
$
|
67 |
-
if ( $
|
68 |
try {
|
69 |
( new Lib\ImportExport\Import() )
|
70 |
->setMod( $this->getMod() )
|
71 |
-
->fromSite( $
|
72 |
}
|
73 |
catch ( \Exception $e ) {
|
74 |
}
|
24 |
$mod->getPluginBadgeCon()->run();
|
25 |
|
26 |
( new PluginTelemetry() )
|
27 |
+
->setMod( $this->getMod() )
|
28 |
->execute();
|
29 |
|
30 |
if ( $opts->isImportExportPermitted() ) {
|
62 |
public function runDailyCron() {
|
63 |
$this->getCon()->fireEvent( 'test_cron_run' );
|
64 |
|
65 |
+
/** @var Options $opts */
|
66 |
+
$opts = $this->getOptions();
|
67 |
+
if ( $opts->isImportExportPermitted() ) {
|
68 |
try {
|
69 |
( new Lib\ImportExport\Import() )
|
70 |
->setMod( $this->getMod() )
|
71 |
+
->fromSite( $opts->getImportExportMasterImportUrl() );
|
72 |
}
|
73 |
catch ( \Exception $e ) {
|
74 |
}
|
src/lib/src/Modules/Plugin/Strings.php
CHANGED
@@ -56,6 +56,12 @@ class Strings extends Base\Strings {
|
|
56 |
'recaptcha_fail' => [
|
57 |
__( 'CAPTCHA Test Fail', 'wp-simple-firewall' )
|
58 |
],
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
];
|
60 |
}
|
61 |
|
@@ -72,7 +78,7 @@ class Strings extends Base\Strings {
|
|
72 |
case 'section_global_security_options' :
|
73 |
$title = __( 'Global Security Plugin Disable', 'wp-simple-firewall' );
|
74 |
$titleShort = sprintf( __( 'Disable %s', 'wp-simple-firewall' ), $sPlugName );
|
75 |
-
$
|
76 |
sprintf( '%s - %s', __( 'Purpose', 'wp-simple-firewall' ), __( 'Use this option to completely disable all active Shield Protection.', 'wp-simple-firewall' ) ),
|
77 |
];
|
78 |
break;
|
@@ -80,18 +86,18 @@ class Strings extends Base\Strings {
|
|
80 |
case 'section_defaults' :
|
81 |
$title = __( 'Plugin Defaults', 'wp-simple-firewall' );
|
82 |
$titleShort = __( 'Plugin Defaults', 'wp-simple-firewall' );
|
83 |
-
$
|
84 |
sprintf( '%s - %s', __( 'Purpose', 'wp-simple-firewall' ), __( 'Important default settings used throughout the plugin.', 'wp-simple-firewall' ) ),
|
85 |
];
|
86 |
break;
|
87 |
|
88 |
case 'section_importexport' :
|
89 |
$title = sprintf( '%s / %s', __( 'Import', 'wp-simple-firewall' ), __( 'Export', 'wp-simple-firewall' ) );
|
90 |
-
$
|
|
|
91 |
sprintf( '%s - %s', __( 'Purpose', 'wp-simple-firewall' ), __( 'Automatically import options, and deploy configurations across your entire network.', 'wp-simple-firewall' ) ),
|
92 |
sprintf( __( 'This is a Pro-only feature.', 'wp-simple-firewall' ) ),
|
93 |
];
|
94 |
-
$titleShort = sprintf( '%s / %s', __( 'Import', 'wp-simple-firewall' ), __( 'Export', 'wp-simple-firewall' ) );
|
95 |
break;
|
96 |
|
97 |
case 'section_suresend' :
|
@@ -112,7 +118,7 @@ class Strings extends Base\Strings {
|
|
112 |
case 'section_third_party_captcha' :
|
113 |
$title = __( 'CAPTCHA', 'wp-simple-firewall' );
|
114 |
$titleShort = __( 'CAPTCHA', 'wp-simple-firewall' );
|
115 |
-
$
|
116 |
sprintf( '%s - %s', __( 'Purpose', 'wp-simple-firewall' ), sprintf( __( 'Setup CAPTCHA for use across %s.', 'wp-simple-firewall' ), $sPlugName ) ),
|
117 |
sprintf( '%s - %s',
|
118 |
__( 'Recommendation', 'wp-simple-firewall' ),
|
@@ -138,7 +144,7 @@ class Strings extends Base\Strings {
|
|
138 |
return [
|
139 |
'title' => $title,
|
140 |
'title_short' => $titleShort,
|
141 |
-
'summary' => ( isset( $
|
142 |
];
|
143 |
}
|
144 |
|
56 |
'recaptcha_fail' => [
|
57 |
__( 'CAPTCHA Test Fail', 'wp-simple-firewall' )
|
58 |
],
|
59 |
+
'antibot_pass' => [
|
60 |
+
__( 'Request passed the AntiBot Test with a Visitor Score of "%s" (minimum score: %s).', 'wp-simple-firewall' ),
|
61 |
+
],
|
62 |
+
'antibot_fail' => [
|
63 |
+
__( 'Request failed the AntiBot Test with a Visitor Score of "%s" (minimum score: %s).', 'wp-simple-firewall' ),
|
64 |
+
],
|
65 |
];
|
66 |
}
|
67 |
|
78 |
case 'section_global_security_options' :
|
79 |
$title = __( 'Global Security Plugin Disable', 'wp-simple-firewall' );
|
80 |
$titleShort = sprintf( __( 'Disable %s', 'wp-simple-firewall' ), $sPlugName );
|
81 |
+
$summary = [
|
82 |
sprintf( '%s - %s', __( 'Purpose', 'wp-simple-firewall' ), __( 'Use this option to completely disable all active Shield Protection.', 'wp-simple-firewall' ) ),
|
83 |
];
|
84 |
break;
|
86 |
case 'section_defaults' :
|
87 |
$title = __( 'Plugin Defaults', 'wp-simple-firewall' );
|
88 |
$titleShort = __( 'Plugin Defaults', 'wp-simple-firewall' );
|
89 |
+
$summary = [
|
90 |
sprintf( '%s - %s', __( 'Purpose', 'wp-simple-firewall' ), __( 'Important default settings used throughout the plugin.', 'wp-simple-firewall' ) ),
|
91 |
];
|
92 |
break;
|
93 |
|
94 |
case 'section_importexport' :
|
95 |
$title = sprintf( '%s / %s', __( 'Import', 'wp-simple-firewall' ), __( 'Export', 'wp-simple-firewall' ) );
|
96 |
+
$titleShort = sprintf( '%s / %s', __( 'Import', 'wp-simple-firewall' ), __( 'Export', 'wp-simple-firewall' ) );
|
97 |
+
$summary = [
|
98 |
sprintf( '%s - %s', __( 'Purpose', 'wp-simple-firewall' ), __( 'Automatically import options, and deploy configurations across your entire network.', 'wp-simple-firewall' ) ),
|
99 |
sprintf( __( 'This is a Pro-only feature.', 'wp-simple-firewall' ) ),
|
100 |
];
|
|
|
101 |
break;
|
102 |
|
103 |
case 'section_suresend' :
|
118 |
case 'section_third_party_captcha' :
|
119 |
$title = __( 'CAPTCHA', 'wp-simple-firewall' );
|
120 |
$titleShort = __( 'CAPTCHA', 'wp-simple-firewall' );
|
121 |
+
$summary = [
|
122 |
sprintf( '%s - %s', __( 'Purpose', 'wp-simple-firewall' ), sprintf( __( 'Setup CAPTCHA for use across %s.', 'wp-simple-firewall' ), $sPlugName ) ),
|
123 |
sprintf( '%s - %s',
|
124 |
__( 'Recommendation', 'wp-simple-firewall' ),
|
144 |
return [
|
145 |
'title' => $title,
|
146 |
'title_short' => $titleShort,
|
147 |
+
'summary' => ( isset( $summary ) && is_array( $summary ) ) ? $summary : [],
|
148 |
];
|
149 |
}
|
150 |
|
src/lib/src/Modules/Plugin/WpCli/Reset.php
CHANGED
@@ -27,8 +27,8 @@ class Reset extends Base\WpCli\BaseWpCliCmd {
|
|
27 |
] ) );
|
28 |
}
|
29 |
|
30 |
-
public function cmdReset( $null, $
|
31 |
-
if ( !$this->isForceFlag( $
|
32 |
WP_CLI::confirm( __( 'Are you sure you want to reset the Shield plugin to defaults?', 'wp-simple-firewall' ) );
|
33 |
}
|
34 |
( new ResetPlugin() )
|
27 |
] ) );
|
28 |
}
|
29 |
|
30 |
+
public function cmdReset( $null, $args ) {
|
31 |
+
if ( !$this->isForceFlag( $args ) ) {
|
32 |
WP_CLI::confirm( __( 'Are you sure you want to reset the Shield plugin to defaults?', 'wp-simple-firewall' ) );
|
33 |
}
|
34 |
( new ResetPlugin() )
|
src/lib/src/Modules/Plugin/WpCli/ToggleDebug.php
CHANGED
@@ -32,10 +32,10 @@ class ToggleDebug extends BaseWpCliCmd {
|
|
32 |
] ) );
|
33 |
}
|
34 |
|
35 |
-
public function cmdDebugMode( $null, $
|
36 |
$debugMode = ( new DebugMode() )->setCon( $this->getCon() );
|
37 |
|
38 |
-
switch ( $
|
39 |
case 'query':
|
40 |
if ( $debugMode->isActiveViaDefine() ) {
|
41 |
WP_CLI::log( 'Debug mode is active using PHP constant.' );
|
32 |
] ) );
|
33 |
}
|
34 |
|
35 |
+
public function cmdDebugMode( $null, $args ) {
|
36 |
$debugMode = ( new DebugMode() )->setCon( $this->getCon() );
|
37 |
|
38 |
+
switch ( $args[ 'action' ] ) {
|
39 |
case 'query':
|
40 |
if ( $debugMode->isActiveViaDefine() ) {
|
41 |
WP_CLI::log( 'Debug mode is active using PHP constant.' );
|
src/lib/src/Modules/Reporting/AjaxHandler.php
ADDED
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Reporting;
|
4 |
+
|
5 |
+
use FernleafSystems\Wordpress\Plugin\Shield;
|
6 |
+
|
7 |
+
class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
|
8 |
+
|
9 |
+
protected function processAjaxAction( string $action ) :array {
|
10 |
+
|
11 |
+
switch ( $action ) {
|
12 |
+
case 'render_custom_chart':
|
13 |
+
$response = $this->ajaxExec_RenderCustomChart();
|
14 |
+
break;
|
15 |
+
|
16 |
+
case 'render_summary_chart':
|
17 |
+
$response = $this->ajaxExec_RenderSummaryChart();
|
18 |
+
break;
|
19 |
+
|
20 |
+
default:
|
21 |
+
$response = parent::processAjaxAction( $action );
|
22 |
+
}
|
23 |
+
|
24 |
+
return $response;
|
25 |
+
}
|
26 |
+
|
27 |
+
private function ajaxExec_RenderCustomChart() :array {
|
28 |
+
return $this->renderChart( $this->getAjaxFormParams() );
|
29 |
+
}
|
30 |
+
|
31 |
+
private function ajaxExec_RenderSummaryChart() :array {
|
32 |
+
return $this->renderChart( $_POST );
|
33 |
+
}
|
34 |
+
|
35 |
+
/**
|
36 |
+
* @param Shield\Modules\Reporting\Charts\ChartRequestVO $req
|
37 |
+
* @return array
|
38 |
+
*/
|
39 |
+
private function renderChart( array $data ) :array {
|
40 |
+
/** @var ModCon $mod */
|
41 |
+
$mod = $this->getMod();
|
42 |
+
try {
|
43 |
+
$chartData = ( new Charts\CustomChartData() )
|
44 |
+
->setMod( $mod )
|
45 |
+
->setChartRequest( ( new Charts\CustomChartRequestVO() )->applyFromArray( $data ) )
|
46 |
+
->build();
|
47 |
+
$msg = 'No message';
|
48 |
+
$success = true;
|
49 |
+
}
|
50 |
+
catch ( \Exception $e ) {
|
51 |
+
$msg = sprintf( '%s: %s', __( 'Error', 'wp-simple-firewall' ), $e->getMessage() );
|
52 |
+
$success = false;
|
53 |
+
$chartData = [];
|
54 |
+
}
|
55 |
+
|
56 |
+
return [
|
57 |
+
'success' => $success,
|
58 |
+
'message' => $msg,
|
59 |
+
'chart' => $chartData
|
60 |
+
];
|
61 |
+
}
|
62 |
+
}
|
src/lib/src/Modules/Reporting/Charts/BaseBuildChartData.php
ADDED
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Reporting\Charts;
|
4 |
+
|
5 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Databases\Events;
|
6 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Events\Strings;
|
7 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
8 |
+
use FernleafSystems\Wordpress\Services\Services;
|
9 |
+
|
10 |
+
class BaseBuildChartData {
|
11 |
+
|
12 |
+
const LOCATION_SUMMARYCARD = 'insights-overview-statcard';
|
13 |
+
use ModConsumer;
|
14 |
+
use ChartRequestConsumer;
|
15 |
+
|
16 |
+
/**
|
17 |
+
* @var array
|
18 |
+
*/
|
19 |
+
protected $labels;
|
20 |
+
|
21 |
+
/**
|
22 |
+
* @return array
|
23 |
+
* @throws \InvalidArgumentException
|
24 |
+
*/
|
25 |
+
public function build() :array {
|
26 |
+
$req = $this->getChartRequest();
|
27 |
+
$this->preProcessRequest();
|
28 |
+
|
29 |
+
$allSeries = [];
|
30 |
+
if ( $req->combine_events ) {
|
31 |
+
$allSeries[] = $this->buildDataForEvents( $req->events );
|
32 |
+
}
|
33 |
+
else {
|
34 |
+
foreach ( $req->events as $event ) {
|
35 |
+
$allSeries[] = $this->buildDataForEvents( [ $event ] );
|
36 |
+
}
|
37 |
+
}
|
38 |
+
|
39 |
+
return [
|
40 |
+
'title' => $this->buildTitle(),
|
41 |
+
'legend' => $this->buildLegend(),
|
42 |
+
'data' => [
|
43 |
+
'labels' => $this->labels,
|
44 |
+
'series' => $allSeries,
|
45 |
+
],
|
46 |
+
];
|
47 |
+
}
|
48 |
+
|
49 |
+
protected function buildLegend() :array {
|
50 |
+
$req = $this->getChartRequest();
|
51 |
+
$legend = [];
|
52 |
+
if ( !$req->combine_events ) {
|
53 |
+
/** @var Strings $strings */
|
54 |
+
$strings = $this->getCon()->getModule_Events()->getStrings();
|
55 |
+
foreach ( $req->events as $event ) {
|
56 |
+
$legend[] = $strings->getEventName( $event );
|
57 |
+
}
|
58 |
+
}
|
59 |
+
return $legend;
|
60 |
+
}
|
61 |
+
|
62 |
+
protected function buildTitle() :string {
|
63 |
+
$req = $this->getChartRequest();
|
64 |
+
switch ( $req->interval ) {
|
65 |
+
case 'hourly':
|
66 |
+
$counter = 'hours';
|
67 |
+
break;
|
68 |
+
case 'weekly':
|
69 |
+
$counter = 'weeks';
|
70 |
+
break;
|
71 |
+
case 'monthly':
|
72 |
+
$counter = 'months';
|
73 |
+
break;
|
74 |
+
case 'yearly':
|
75 |
+
$counter = 'years';
|
76 |
+
break;
|
77 |
+
default:
|
78 |
+
case 'daily':
|
79 |
+
$counter = 'days';
|
80 |
+
break;
|
81 |
+
}
|
82 |
+
return sprintf( 'Chart showing events from the past %s %s', $req->ticks, $counter );
|
83 |
+
}
|
84 |
+
|
85 |
+
protected function buildDataForEvents( array $events ) :array {
|
86 |
+
$req = $this->getChartRequest();
|
87 |
+
$dbhEvents = $this->getCon()->getModule_Events()->getDbHandler_Events();
|
88 |
+
|
89 |
+
$tick = 0;
|
90 |
+
$carbon = Services::Request()->carbon();
|
91 |
+
|
92 |
+
$labels = [];
|
93 |
+
$dataSeries = [];
|
94 |
+
do {
|
95 |
+
|
96 |
+
/** @var Events\Select $eventSelect */
|
97 |
+
$eventSelect = $dbhEvents->getQuerySelector();
|
98 |
+
switch ( $req->interval ) {
|
99 |
+
case 'hourly':
|
100 |
+
$eventSelect->filterByBoundary_Hour( $carbon->timestamp );
|
101 |
+
$labels[] = $carbon->format( 'H' );
|
102 |
+
$carbon->subHour();
|
103 |
+
break;
|
104 |
+
case 'daily':
|
105 |
+
$eventSelect->filterByBoundary_Day( $carbon->timestamp );
|
106 |
+
$labels[] = $carbon->format( 'Y-m-d' );
|
107 |
+
$carbon->subDay();
|
108 |
+
break;
|
109 |
+
case 'weekly':
|
110 |
+
$eventSelect->filterByBoundary_Week( $carbon->timestamp );
|
111 |
+
$labels[] = ( clone $carbon )->startOfWeek()->format( 'Y-m-d' );
|
112 |
+
$carbon->subWeek();
|
113 |
+
break;
|
114 |
+
case 'monthly':
|
115 |
+
$eventSelect->filterByBoundary_Month( $carbon->timestamp );
|
116 |
+
$labels[] = $carbon->format( 'Y-m' );
|
117 |
+
$carbon->subMonth();
|
118 |
+
break;
|
119 |
+
case 'yearly':
|
120 |
+
$eventSelect->filterByBoundary_Year( $carbon->timestamp );
|
121 |
+
$labels[] = $carbon->format( 'Y' );
|
122 |
+
$carbon->subYear();
|
123 |
+
break;
|
124 |
+
}
|
125 |
+
|
126 |
+
$dataSeries[] = $eventSelect->sumEvents( $events );
|
127 |
+
|
128 |
+
$tick++;
|
129 |
+
} while ( $tick < $req->ticks );
|
130 |
+
|
131 |
+
if ( empty( $this->labels ) ) {
|
132 |
+
$this->labels = $labels;
|
133 |
+
}
|
134 |
+
|
135 |
+
return $dataSeries;
|
136 |
+
}
|
137 |
+
|
138 |
+
/**
|
139 |
+
* @throws \InvalidArgumentException
|
140 |
+
*/
|
141 |
+
protected function preProcessRequest() {
|
142 |
+
$req = $this->getChartRequest();
|
143 |
+
|
144 |
+
if ( empty( $req->events ) ) {
|
145 |
+
throw new \InvalidArgumentException( 'No events selected - please select at least 1 event.' );
|
146 |
+
}
|
147 |
+
|
148 |
+
if ( empty( $req->ticks ) ) {
|
149 |
+
switch ( $req->interval ) {
|
150 |
+
case 'daily':
|
151 |
+
$req->ticks = 7;
|
152 |
+
break;
|
153 |
+
case 'weekly':
|
154 |
+
$req->ticks = 8;
|
155 |
+
break;
|
156 |
+
default:
|
157 |
+
$req->ticks = 12;
|
158 |
+
break;
|
159 |
+
}
|
160 |
+
}
|
161 |
+
}
|
162 |
+
}
|
src/lib/src/Modules/Reporting/Charts/ChartRequestConsumer.php
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Reporting\Charts;
|
4 |
+
|
5 |
+
trait ChartRequestConsumer {
|
6 |
+
|
7 |
+
/**
|
8 |
+
* @var ChartRequestVO
|
9 |
+
*/
|
10 |
+
protected $chartReq;
|
11 |
+
|
12 |
+
/**
|
13 |
+
* @return ChartRequestVO
|
14 |
+
*/
|
15 |
+
public function getChartRequest() {
|
16 |
+
return $this->chartReq;
|
17 |
+
}
|
18 |
+
|
19 |
+
/**
|
20 |
+
* @param ChartRequestVO $req
|
21 |
+
* @return $this
|
22 |
+
*/
|
23 |
+
public function setChartRequest( $req ) {
|
24 |
+
$this->chartReq = $req;
|
25 |
+
return $this;
|
26 |
+
}
|
27 |
+
}
|
src/lib/src/Modules/Reporting/Charts/ChartRequestVO.php
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Reporting\Charts;
|
4 |
+
|
5 |
+
use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Class ChartRequestVO
|
9 |
+
* @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Reporting\Charts
|
10 |
+
* @property string $interval
|
11 |
+
* @property string $ticks
|
12 |
+
* @property string[] $events
|
13 |
+
* @property bool $combine_events
|
14 |
+
* @property array $chart_params
|
15 |
+
*/
|
16 |
+
class ChartRequestVO extends DynPropertiesClass {
|
17 |
+
|
18 |
+
/**
|
19 |
+
* @param string $key
|
20 |
+
* @return mixed
|
21 |
+
*/
|
22 |
+
public function __get( string $key ) {
|
23 |
+
$value = parent::__get( $key );
|
24 |
+
switch ( $key ) {
|
25 |
+
case 'interval':
|
26 |
+
if ( empty( $value ) ) {
|
27 |
+
$value = 'weekly';
|
28 |
+
}
|
29 |
+
break;
|
30 |
+
default:
|
31 |
+
break;
|
32 |
+
}
|
33 |
+
return $value;
|
34 |
+
}
|
35 |
+
}
|
src/lib/src/Modules/Reporting/Charts/CustomChartData.php
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Reporting\Charts;
|
4 |
+
|
5 |
+
class CustomChartData extends BaseBuildChartData {
|
6 |
+
|
7 |
+
/**
|
8 |
+
* @inheritDoc
|
9 |
+
*/
|
10 |
+
protected function preProcessRequest() {
|
11 |
+
parent::preProcessRequest();
|
12 |
+
|
13 |
+
/** @var CustomChartRequestVO $req */
|
14 |
+
$req = $this->getChartRequest();
|
15 |
+
|
16 |
+
if ( $req->render_location === static::LOCATION_SUMMARYCARD ) {
|
17 |
+
$req->interval = 'daily';
|
18 |
+
}
|
19 |
+
|
20 |
+
$theEvent = current( $req->events );
|
21 |
+
$possibleEvents = array_keys( $this->getCon()->loadEventsService()->getEvents() );
|
22 |
+
switch ( $theEvent ) {
|
23 |
+
case 'comment_block':
|
24 |
+
$req->events = array_filter(
|
25 |
+
$possibleEvents,
|
26 |
+
function ( $event ) {
|
27 |
+
return strpos( $event, 'spam_block_' ) === 0;
|
28 |
+
}
|
29 |
+
);
|
30 |
+
break;
|
31 |
+
case 'bot_blocks':
|
32 |
+
$req->events = array_filter(
|
33 |
+
$possibleEvents,
|
34 |
+
function ( $event ) {
|
35 |
+
return strpos( $event, 'bottrack_' ) === 0;
|
36 |
+
}
|
37 |
+
);
|
38 |
+
break;
|
39 |
+
default:
|
40 |
+
break;
|
41 |
+
}
|
42 |
+
}
|
43 |
+
}
|
src/lib/src/Modules/Reporting/Charts/CustomChartRequestVO.php
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Reporting\Charts;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Class CustomChartRequestVO
|
7 |
+
* @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Reporting\Charts
|
8 |
+
* @property string $render_location
|
9 |
+
*/
|
10 |
+
class CustomChartRequestVO extends ChartRequestVO {
|
11 |
+
|
12 |
+
}
|
src/lib/src/Modules/Reporting/Lib/ReportingController.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Reporting\Lib;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Logic\
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Crons\PluginCronsConsumer;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Databases\Reports as DBReports;
|
8 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules;
|
@@ -12,13 +12,10 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
12 |
class ReportingController {
|
13 |
|
14 |
use Modules\ModConsumer;
|
15 |
-
use
|
16 |
use PluginCronsConsumer;
|
17 |
|
18 |
-
|
19 |
-
* @return bool
|
20 |
-
*/
|
21 |
-
protected function canRun() {
|
22 |
/** @var Modules\Reporting\Options $opts */
|
23 |
$opts = $this->getOptions();
|
24 |
return $opts->getFrequencyInfo() !== 'disabled' || $opts->getFrequencyAlert() !== 'disabled';
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Reporting\Lib;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Logic\ExecOnce;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Crons\PluginCronsConsumer;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Databases\Reports as DBReports;
|
8 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules;
|
12 |
class ReportingController {
|
13 |
|
14 |
use Modules\ModConsumer;
|
15 |
+
use ExecOnce;
|
16 |
use PluginCronsConsumer;
|
17 |
|
18 |
+
protected function canRun() :bool {
|
|
|
|
|
|
|
19 |
/** @var Modules\Reporting\Options $opts */
|
20 |
$opts = $this->getOptions();
|
21 |
return $opts->getFrequencyInfo() !== 'disabled' || $opts->getFrequencyAlert() !== 'disabled';
|
src/lib/src/Modules/Reporting/Lib/Reports/ReportVO.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Reporting\Lib\Reports;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Data\Adapter\
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Databases\Reports\EntryVO;
|
7 |
|
8 |
/**
|
@@ -18,5 +18,5 @@ use FernleafSystems\Wordpress\Plugin\Shield\Databases\Reports\EntryVO;
|
|
18 |
*/
|
19 |
class ReportVO {
|
20 |
|
21 |
-
use
|
22 |
}
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Reporting\Lib\Reports;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Data\Adapter\DynProperties;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Databases\Reports\EntryVO;
|
7 |
|
8 |
/**
|
18 |
*/
|
19 |
class ReportVO {
|
20 |
|
21 |
+
use DynProperties;
|
22 |
}
|
src/lib/src/Modules/Reporting/UI.php
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Reporting;
|
4 |
|
@@ -8,89 +8,138 @@ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Events;
|
|
8 |
|
9 |
class UI extends BaseShield\UI {
|
10 |
|
11 |
-
public function
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
$con = $this->getCon();
|
13 |
-
/** @var Databases\Events\Select $
|
14 |
-
$
|
15 |
-
|
16 |
-
|
17 |
|
18 |
/** @var Databases\IPs\Select $oSelectIp */
|
19 |
$oSelectIp = $con->getModule_IPs()
|
20 |
->getDbHandler_IPs()
|
21 |
->getQuerySelector();
|
22 |
|
23 |
-
$
|
24 |
'login' => [
|
25 |
'id' => 'login_block',
|
26 |
'title' => __( 'Login Blocks', 'wp-simple-firewall' ),
|
27 |
'val' => sprintf( '%s: %s', __( 'Lifetime Total' ),
|
28 |
-
$
|
29 |
'tooltip_p' => __( 'Total login attempts blocked.', 'wp-simple-firewall' ),
|
30 |
],
|
31 |
// 'firewall' => [
|
32 |
// 'id' => 'firewall_block',
|
33 |
// 'title' => __( 'Firewall Blocks', 'wp-simple-firewall' ),
|
34 |
-
// 'val' => $
|
35 |
// 'tooltip' => __( 'Total requests blocked by firewall rules.', 'wp-simple-firewall' )
|
36 |
// ],
|
37 |
'bot_blocks' => [
|
38 |
'id' => 'bot_blocks',
|
39 |
'title' => __( 'Bot Detection', 'wp-simple-firewall' ),
|
40 |
'val' => sprintf( '%s: %s', __( 'Lifetime Total' ),
|
41 |
-
$
|
42 |
'tooltip_p' => __( 'Total requests identified as bots.', 'wp-simple-firewall' ),
|
43 |
],
|
44 |
'comments' => [
|
45 |
'id' => 'comment_block',
|
46 |
'title' => __( 'Comment Blocks', 'wp-simple-firewall' ),
|
47 |
'val' => sprintf( '%s: %s', __( 'Lifetime Total' ),
|
48 |
-
$
|
49 |
'spam_block_bot',
|
50 |
'spam_block_human',
|
51 |
'spam_block_recaptcha'
|
52 |
-
] ) ),
|
53 |
'tooltip_p' => __( 'Total SPAM comments blocked.', 'wp-simple-firewall' ),
|
54 |
],
|
55 |
'transgressions' => [
|
56 |
'id' => 'ip_offense',
|
57 |
'title' => __( 'Offenses', 'wp-simple-firewall' ),
|
58 |
'val' => sprintf( '%s: %s', __( 'Lifetime Total' ),
|
59 |
-
$
|
60 |
'tooltip_p' => __( 'Total offenses against the site.', 'wp-simple-firewall' ),
|
61 |
],
|
62 |
'conn_kills' => [
|
63 |
'id' => 'conn_kill',
|
64 |
'title' => __( 'Connection Killed', 'wp-simple-firewall' ),
|
65 |
'val' => sprintf( '%s: %s', __( 'Lifetime Total' ),
|
66 |
-
$
|
67 |
'tooltip_p' => __( 'Total connections blocked/killed after too many offenses.', 'wp-simple-firewall' ),
|
68 |
],
|
69 |
'ip_blocked' => [
|
70 |
'id' => 'ip_blocked',
|
71 |
'title' => __( 'IP Blocked', 'wp-simple-firewall' ),
|
72 |
'val' => sprintf( '%s: %s', __( 'Now' ),
|
73 |
-
$oSelectIp->filterByBlacklist()->count()
|
74 |
),
|
75 |
'tooltip_p' => __( 'IP address exceeds offense limit and is blocked.', 'wp-simple-firewall' ),
|
76 |
],
|
77 |
];
|
78 |
|
79 |
-
foreach ( $
|
80 |
-
$
|
81 |
-
$
|
82 |
-
$
|
83 |
}
|
84 |
|
|
|
|
|
85 |
return $this->getMod()
|
86 |
->renderTemplate(
|
87 |
-
'/wpadmin_pages/insights/reports/
|
88 |
[
|
89 |
-
'ajax'
|
90 |
-
'
|
91 |
],
|
92 |
-
'vars'
|
93 |
-
'stats' => $
|
94 |
],
|
95 |
],
|
96 |
true
|
@@ -98,33 +147,13 @@ class UI extends BaseShield\UI {
|
|
98 |
}
|
99 |
|
100 |
public function buildInsightsVars() :array {
|
101 |
-
$oEvtsMod = $this->getCon()->getModule_Events();
|
102 |
-
/** @var Events\Strings $oStrs */
|
103 |
-
$oStrs = $oEvtsMod->getStrings();
|
104 |
-
$aEvtNames = $oStrs->getEventNames();
|
105 |
-
|
106 |
return [
|
107 |
-
'ajax' => [
|
108 |
-
'render_chart' => $oEvtsMod->getAjaxActionData( 'render_chart', true ),
|
109 |
-
],
|
110 |
'content' => [
|
111 |
-
'summary_stats' => $this->
|
|
|
112 |
],
|
113 |
'flags' => [],
|
114 |
-
'strings' => [
|
115 |
-
],
|
116 |
-
'vars' => [
|
117 |
-
'events_options' => array_intersect_key(
|
118 |
-
$aEvtNames,
|
119 |
-
array_flip(
|
120 |
-
[
|
121 |
-
'ip_offense',
|
122 |
-
'conn_kill',
|
123 |
-
'firewall_block',
|
124 |
-
]
|
125 |
-
)
|
126 |
-
)
|
127 |
-
],
|
128 |
];
|
129 |
}
|
130 |
}
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Reporting;
|
4 |
|
8 |
|
9 |
class UI extends BaseShield\UI {
|
10 |
|
11 |
+
public function renderSectionCustomChart() :string {
|
12 |
+
/** @var ModCon $mod */
|
13 |
+
$mod = $this->getMod();
|
14 |
+
return $this->getMod()
|
15 |
+
->renderTemplate(
|
16 |
+
'/wpadmin_pages/insights/reports/charts_custom.twig',
|
17 |
+
[
|
18 |
+
'ajax' => [
|
19 |
+
'render_custom_chart' => $mod->getAjaxActionData( 'render_custom_chart', true ),
|
20 |
+
],
|
21 |
+
'strings' => [
|
22 |
+
'select_events' => __( 'Events', 'wp-simple-firewall' ),
|
23 |
+
'select_interval' => __( 'Interval', 'wp-simple-firewall' ),
|
24 |
+
'build_chart' => __( 'Build Chart', 'wp-simple-firewall' ),
|
25 |
+
],
|
26 |
+
'vars' => [
|
27 |
+
'events' => $this->buildPossibleEvents(),
|
28 |
+
'interval' => [
|
29 |
+
'hourly' => __( 'Hourly', 'wp-simple-firewall' ),
|
30 |
+
'daily' => __( 'Daily', 'wp-simple-firewall' ),
|
31 |
+
'weekly' => __( 'Weekly', 'wp-simple-firewall' ),
|
32 |
+
'monthly' => __( 'Monthly', 'wp-simple-firewall' ),
|
33 |
+
'yearly' => __( 'Yearly', 'wp-simple-firewall' ),
|
34 |
+
],
|
35 |
+
],
|
36 |
+
],
|
37 |
+
true
|
38 |
+
);
|
39 |
+
}
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Finds all available events logged in the DB and intersects this with all available Event names
|
43 |
+
* i.e. so you can only build charts of events with actual records
|
44 |
+
* @return array
|
45 |
+
*/
|
46 |
+
private function buildPossibleEvents() :array {
|
47 |
+
$eventsMod = $this->getCon()->getModule_Events();
|
48 |
+
/** @var Events\Strings $strings */
|
49 |
+
$strings = $eventsMod->getStrings();
|
50 |
+
return array_intersect_key(
|
51 |
+
$strings->getEventNames(),
|
52 |
+
array_flip( $eventsMod->getDbHandler_Events()
|
53 |
+
->getQuerySelector()
|
54 |
+
->getDistinctForColumn( 'event' ) )
|
55 |
+
);
|
56 |
+
}
|
57 |
+
|
58 |
+
private function renderSectionSummaryStats() :string {
|
59 |
$con = $this->getCon();
|
60 |
+
/** @var Databases\Events\Select $eventSelector */
|
61 |
+
$eventSelector = $con->getModule_Events()
|
62 |
+
->getDbHandler_Events()
|
63 |
+
->getQuerySelector();
|
64 |
|
65 |
/** @var Databases\IPs\Select $oSelectIp */
|
66 |
$oSelectIp = $con->getModule_IPs()
|
67 |
->getDbHandler_IPs()
|
68 |
->getQuerySelector();
|
69 |
|
70 |
+
$statsData = [
|
71 |
'login' => [
|
72 |
'id' => 'login_block',
|
73 |
'title' => __( 'Login Blocks', 'wp-simple-firewall' ),
|
74 |
'val' => sprintf( '%s: %s', __( 'Lifetime Total' ),
|
75 |
+
number_format( $eventSelector->clearWheres()->sumEvent( 'login_block' ) ) ),
|
76 |
'tooltip_p' => __( 'Total login attempts blocked.', 'wp-simple-firewall' ),
|
77 |
],
|
78 |
// 'firewall' => [
|
79 |
// 'id' => 'firewall_block',
|
80 |
// 'title' => __( 'Firewall Blocks', 'wp-simple-firewall' ),
|
81 |
+
// 'val' => $eventSelector->clearWheres()->sumEvent( 'firewall_block' ),
|
82 |
// 'tooltip' => __( 'Total requests blocked by firewall rules.', 'wp-simple-firewall' )
|
83 |
// ],
|
84 |
'bot_blocks' => [
|
85 |
'id' => 'bot_blocks',
|
86 |
'title' => __( 'Bot Detection', 'wp-simple-firewall' ),
|
87 |
'val' => sprintf( '%s: %s', __( 'Lifetime Total' ),
|
88 |
+
number_format( $eventSelector->clearWheres()->sumEventsLike( 'bottrack_' ) ) ),
|
89 |
'tooltip_p' => __( 'Total requests identified as bots.', 'wp-simple-firewall' ),
|
90 |
],
|
91 |
'comments' => [
|
92 |
'id' => 'comment_block',
|
93 |
'title' => __( 'Comment Blocks', 'wp-simple-firewall' ),
|
94 |
'val' => sprintf( '%s: %s', __( 'Lifetime Total' ),
|
95 |
+
number_format( $eventSelector->clearWheres()->sumEvents( [
|
96 |
'spam_block_bot',
|
97 |
'spam_block_human',
|
98 |
'spam_block_recaptcha'
|
99 |
+
] ) ) ),
|
100 |
'tooltip_p' => __( 'Total SPAM comments blocked.', 'wp-simple-firewall' ),
|
101 |
],
|
102 |
'transgressions' => [
|
103 |
'id' => 'ip_offense',
|
104 |
'title' => __( 'Offenses', 'wp-simple-firewall' ),
|
105 |
'val' => sprintf( '%s: %s', __( 'Lifetime Total' ),
|
106 |
+
number_format( $eventSelector->clearWheres()->sumEvent( 'ip_offense' ) ) ),
|
107 |
'tooltip_p' => __( 'Total offenses against the site.', 'wp-simple-firewall' ),
|
108 |
],
|
109 |
'conn_kills' => [
|
110 |
'id' => 'conn_kill',
|
111 |
'title' => __( 'Connection Killed', 'wp-simple-firewall' ),
|
112 |
'val' => sprintf( '%s: %s', __( 'Lifetime Total' ),
|
113 |
+
number_format( $eventSelector->clearWheres()->sumEvent( 'conn_kill' ) ) ),
|
114 |
'tooltip_p' => __( 'Total connections blocked/killed after too many offenses.', 'wp-simple-firewall' ),
|
115 |
],
|
116 |
'ip_blocked' => [
|
117 |
'id' => 'ip_blocked',
|
118 |
'title' => __( 'IP Blocked', 'wp-simple-firewall' ),
|
119 |
'val' => sprintf( '%s: %s', __( 'Now' ),
|
120 |
+
number_format( $oSelectIp->filterByBlacklist()->count() )
|
121 |
),
|
122 |
'tooltip_p' => __( 'IP address exceeds offense limit and is blocked.', 'wp-simple-firewall' ),
|
123 |
],
|
124 |
];
|
125 |
|
126 |
+
foreach ( $statsData as $key => $statData ) {
|
127 |
+
$subtitle = sprintf( __( 'previous %s %s', 'wp-simple-firewall' ), 7, __( 'days', 'wp-simple-firewall' ) );
|
128 |
+
$statsData[ $key ][ 'title_sub' ] = $subtitle;
|
129 |
+
$statsData[ $key ][ 'tooltip_chart' ] = sprintf( '%s: %s.', __( 'Stats', 'wp-simple-firewall' ), $subtitle );
|
130 |
}
|
131 |
|
132 |
+
/** @var ModCon $mod */
|
133 |
+
$mod = $this->getMod();
|
134 |
return $this->getMod()
|
135 |
->renderTemplate(
|
136 |
+
'/wpadmin_pages/insights/reports/charts_summary.twig',
|
137 |
[
|
138 |
+
'ajax' => [
|
139 |
+
'render_summary_chart' => $mod->getAjaxActionData( 'render_summary_chart', true ),
|
140 |
],
|
141 |
+
'vars' => [
|
142 |
+
'stats' => $statsData,
|
143 |
],
|
144 |
],
|
145 |
true
|
147 |
}
|
148 |
|
149 |
public function buildInsightsVars() :array {
|
|
|
|
|
|
|
|
|
|
|
150 |
return [
|
|
|
|
|
|
|
151 |
'content' => [
|
152 |
+
'summary_stats' => $this->renderSectionSummaryStats(),
|
153 |
+
'custom_chart' => $this->renderSectionCustomChart(),
|
154 |
],
|
155 |
'flags' => [],
|
156 |
+
'strings' => [],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
157 |
];
|
158 |
}
|
159 |
}
|
src/lib/src/Modules/SecurityAdmin/AjaxHandler.php
CHANGED
@@ -34,10 +34,7 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
|
|
34 |
return $aResponse;
|
35 |
}
|
36 |
|
37 |
-
|
38 |
-
* @return array
|
39 |
-
*/
|
40 |
-
private function ajaxExec_SecAdminCheck() {
|
41 |
/** @var ModCon $mod */
|
42 |
$mod = $this->getMod();
|
43 |
return [
|
@@ -49,71 +46,61 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
|
|
49 |
private function ajaxExec_SecAdminLogin() :array {
|
50 |
/** @var ModCon $mod */
|
51 |
$mod = $this->getMod();
|
52 |
-
$
|
53 |
-
$
|
54 |
|
55 |
if ( $mod->testSecAccessKeyRequest() ) {
|
56 |
|
57 |
if ( $mod->setSecurityAdminStatusOnOff( true ) ) {
|
58 |
-
$
|
59 |
-
$
|
60 |
-
|
61 |
}
|
62 |
else {
|
63 |
-
$
|
64 |
}
|
65 |
}
|
66 |
else {
|
67 |
-
$
|
68 |
->setMod( $this->getCon()->getModule_IPs() )
|
69 |
->setIP( Services::IP()->getRequestIp() )
|
70 |
->run();
|
71 |
-
$
|
72 |
-
if ( $
|
73 |
-
$
|
74 |
}
|
75 |
else {
|
76 |
-
$
|
77 |
}
|
78 |
-
$
|
79 |
}
|
80 |
|
81 |
return [
|
82 |
-
'success' => $
|
83 |
'page_reload' => true,
|
84 |
-
'message' => $
|
85 |
-
'html' => $
|
86 |
];
|
87 |
}
|
88 |
|
89 |
-
|
90 |
-
* @return array
|
91 |
-
*/
|
92 |
-
private function ajaxExec_SecAdminLoginBox() {
|
93 |
return [
|
94 |
-
'success' =>
|
95 |
'html' => $this->renderAdminAccessAjaxLoginForm()
|
96 |
];
|
97 |
}
|
98 |
|
99 |
-
|
100 |
-
* @return array
|
101 |
-
*/
|
102 |
-
private function ajaxExec_SendEmailRemove() {
|
103 |
( new Shield\Modules\SecurityAdmin\Lib\Actions\RemoveSecAdmin() )
|
104 |
->setMod( $this->getMod() )
|
105 |
->sendConfirmationEmail();
|
106 |
return [
|
107 |
-
'success' =>
|
108 |
'message' => __( 'Email sent. Please ensure the confirmation link opens in THIS browser window.' ),
|
109 |
];
|
110 |
}
|
111 |
|
112 |
-
|
113 |
-
* @param string $sMessage
|
114 |
-
* @return string
|
115 |
-
*/
|
116 |
-
private function renderAdminAccessAjaxLoginForm( $sMessage = '' ) {
|
117 |
/** @var ModCon $mod */
|
118 |
$mod = $this->getMod();
|
119 |
return $mod->renderTemplate( 'snippets/admin_access_login', [
|
@@ -121,7 +108,7 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
|
|
121 |
'sec_admin_login' => json_encode( $mod->getSecAdminLoginAjaxData() )
|
122 |
],
|
123 |
'strings' => [
|
124 |
-
'access_message' => empty( $
|
125 |
]
|
126 |
] );
|
127 |
}
|
34 |
return $aResponse;
|
35 |
}
|
36 |
|
37 |
+
private function ajaxExec_SecAdminCheck() :array {
|
|
|
|
|
|
|
38 |
/** @var ModCon $mod */
|
39 |
$mod = $this->getMod();
|
40 |
return [
|
46 |
private function ajaxExec_SecAdminLogin() :array {
|
47 |
/** @var ModCon $mod */
|
48 |
$mod = $this->getMod();
|
49 |
+
$success = false;
|
50 |
+
$html = '';
|
51 |
|
52 |
if ( $mod->testSecAccessKeyRequest() ) {
|
53 |
|
54 |
if ( $mod->setSecurityAdminStatusOnOff( true ) ) {
|
55 |
+
$success = true;
|
56 |
+
$msg = __( 'Security Admin PIN Accepted.', 'wp-simple-firewall' )
|
57 |
+
.' '.__( 'Please wait', 'wp-simple-firewall' ).' ...';
|
58 |
}
|
59 |
else {
|
60 |
+
$msg = __( 'Failed to process key - you may need to re-login to WordPress.', 'wp-simple-firewall' );
|
61 |
}
|
62 |
}
|
63 |
else {
|
64 |
+
$remaining = ( new Shield\Modules\IPs\Components\QueryRemainingOffenses() )
|
65 |
->setMod( $this->getCon()->getModule_IPs() )
|
66 |
->setIP( Services::IP()->getRequestIp() )
|
67 |
->run();
|
68 |
+
$msg = __( 'Security Admin PIN incorrect.', 'wp-simple-firewall' ).' ';
|
69 |
+
if ( $remaining > 0 ) {
|
70 |
+
$msg .= sprintf( __( 'Attempts remaining: %s.', 'wp-simple-firewall' ), $remaining );
|
71 |
}
|
72 |
else {
|
73 |
+
$msg .= __( "No attempts remaining.", 'wp-simple-firewall' );
|
74 |
}
|
75 |
+
$html = $this->renderAdminAccessAjaxLoginForm( $msg );
|
76 |
}
|
77 |
|
78 |
return [
|
79 |
+
'success' => $success,
|
80 |
'page_reload' => true,
|
81 |
+
'message' => $msg,
|
82 |
+
'html' => $html,
|
83 |
];
|
84 |
}
|
85 |
|
86 |
+
private function ajaxExec_SecAdminLoginBox() :array {
|
|
|
|
|
|
|
87 |
return [
|
88 |
+
'success' => true,
|
89 |
'html' => $this->renderAdminAccessAjaxLoginForm()
|
90 |
];
|
91 |
}
|
92 |
|
93 |
+
private function ajaxExec_SendEmailRemove() :array {
|
|
|
|
|
|
|
94 |
( new Shield\Modules\SecurityAdmin\Lib\Actions\RemoveSecAdmin() )
|
95 |
->setMod( $this->getMod() )
|
96 |
->sendConfirmationEmail();
|
97 |
return [
|
98 |
+
'success' => true,
|
99 |
'message' => __( 'Email sent. Please ensure the confirmation link opens in THIS browser window.' ),
|
100 |
];
|
101 |
}
|
102 |
|
103 |
+
private function renderAdminAccessAjaxLoginForm( string $msg = '' ) :string {
|
|
|
|
|
|
|
|
|
104 |
/** @var ModCon $mod */
|
105 |
$mod = $this->getMod();
|
106 |
return $mod->renderTemplate( 'snippets/admin_access_login', [
|
108 |
'sec_admin_login' => json_encode( $mod->getSecAdminLoginAjaxData() )
|
109 |
],
|
110 |
'strings' => [
|
111 |
+
'access_message' => empty( $msg ) ? __( 'Enter your Security Admin PIN', 'wp-simple-firewall' ) : $msg
|
112 |
]
|
113 |
] );
|
114 |
}
|
src/lib/src/Modules/SecurityAdmin/Lib/WhiteLabel/ApplyLabels.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin\Lib\WhiteLabel;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Logic\
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\SecurityAdmin;
|
8 |
use FernleafSystems\Wordpress\Services\Services;
|
@@ -10,9 +10,9 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
10 |
class ApplyLabels {
|
11 |
|
12 |
use ModConsumer;
|
13 |
-
use
|
14 |
|
15 |
-
protected function canRun() {
|
16 |
/** @var SecurityAdmin\Options $opts */
|
17 |
$opts = $this->getOptions();
|
18 |
return $opts->isEnabledWhitelabel();
|
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;
|
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();
|
src/lib/src/Modules/SecurityAdmin/ModCon.php
CHANGED
@@ -32,6 +32,10 @@ class ModCon extends BaseShield\ModCon {
|
|
32 |
return $this->whitelabelCon;
|
33 |
}
|
34 |
|
|
|
|
|
|
|
|
|
35 |
/**
|
36 |
* @return bool
|
37 |
* @throws \Exception
|
@@ -70,6 +74,13 @@ class ModCon extends BaseShield\ModCon {
|
|
70 |
}
|
71 |
|
72 |
$opts->setOpt( 'sec_admin_users', $this->verifySecAdminUsers( $opts->getSecurityAdminUsers() ) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
73 |
}
|
74 |
|
75 |
/**
|
@@ -145,6 +156,7 @@ class ModCon extends BaseShield\ModCon {
|
|
145 |
->remove();
|
146 |
break;
|
147 |
default:
|
|
|
148 |
break;
|
149 |
}
|
150 |
}
|
@@ -252,16 +264,19 @@ class ModCon extends BaseShield\ModCon {
|
|
252 |
$sLogoUrl = $opts->getOpt( $key );
|
253 |
}
|
254 |
if ( !empty( $sLogoUrl ) && !Services::Data()->isValidWebUrl( $sLogoUrl ) && strpos( $sLogoUrl, '/' ) !== 0 ) {
|
255 |
-
$sLogoUrl = $this->getCon()->
|
256 |
if ( empty( $sLogoUrl ) ) {
|
257 |
$opts->resetOptToDefault( $key );
|
258 |
-
$sLogoUrl = $this->getCon()->
|
259 |
}
|
260 |
}
|
261 |
|
262 |
return $sLogoUrl;
|
263 |
}
|
264 |
|
|
|
|
|
|
|
265 |
public function isWlEnabled() :bool {
|
266 |
/** @var Options $opts */
|
267 |
$opts = $this->getOptions();
|
@@ -269,7 +284,7 @@ class ModCon extends BaseShield\ModCon {
|
|
269 |
}
|
270 |
|
271 |
public function isWlHideUpdates() :bool {
|
272 |
-
return $this->
|
273 |
}
|
274 |
|
275 |
/**
|
@@ -334,11 +349,6 @@ class ModCon extends BaseShield\ModCon {
|
|
334 |
/** @var Options $opts */
|
335 |
$opts = $this->getOptions();
|
336 |
|
337 |
-
if ( hash_equals( $opts->getSecurityPIN(), self::HASH_DELETE ) ) {
|
338 |
-
$opts->clearSecurityAdminKey();
|
339 |
-
$this->setSecurityAdminStatusOnOff( false );
|
340 |
-
}
|
341 |
-
|
342 |
// Restricting Activate Plugins also means restricting the rest.
|
343 |
$aPluginsRestrictions = $opts->getAdminAccessArea_Plugins();
|
344 |
if ( in_array( 'activate_plugins', $aPluginsRestrictions ) ) {
|
32 |
return $this->whitelabelCon;
|
33 |
}
|
34 |
|
35 |
+
public function getSecAdminLoginAjaxData() :array {
|
36 |
+
return $this->getAjaxActionData( 'sec_admin_login' );
|
37 |
+
}
|
38 |
+
|
39 |
/**
|
40 |
* @return bool
|
41 |
* @throws \Exception
|
74 |
}
|
75 |
|
76 |
$opts->setOpt( 'sec_admin_users', $this->verifySecAdminUsers( $opts->getSecurityAdminUsers() ) );
|
77 |
+
|
78 |
+
if ( hash_equals( $opts->getSecurityPIN(), self::HASH_DELETE ) ) {
|
79 |
+
$opts->clearSecurityAdminKey();
|
80 |
+
$this->setSecurityAdminStatusOnOff( false );
|
81 |
+
// If you delete the PIN, you also delete the sec admins. Prevents a lock out bug.
|
82 |
+
$opts->setOpt( 'sec_admin_users', [] );
|
83 |
+
}
|
84 |
}
|
85 |
|
86 |
/**
|
156 |
->remove();
|
157 |
break;
|
158 |
default:
|
159 |
+
parent::handleModAction( $action );
|
160 |
break;
|
161 |
}
|
162 |
}
|
264 |
$sLogoUrl = $opts->getOpt( $key );
|
265 |
}
|
266 |
if ( !empty( $sLogoUrl ) && !Services::Data()->isValidWebUrl( $sLogoUrl ) && strpos( $sLogoUrl, '/' ) !== 0 ) {
|
267 |
+
$sLogoUrl = $this->getCon()->urls->forImage( $sLogoUrl );
|
268 |
if ( empty( $sLogoUrl ) ) {
|
269 |
$opts->resetOptToDefault( $key );
|
270 |
+
$sLogoUrl = $this->getCon()->urls->forImage( $opts->getOpt( $key ) );
|
271 |
}
|
272 |
}
|
273 |
|
274 |
return $sLogoUrl;
|
275 |
}
|
276 |
|
277 |
+
/**
|
278 |
+
* @deprecated 11.0
|
279 |
+
*/
|
280 |
public function isWlEnabled() :bool {
|
281 |
/** @var Options $opts */
|
282 |
$opts = $this->getOptions();
|
284 |
}
|
285 |
|
286 |
public function isWlHideUpdates() :bool {
|
287 |
+
return $this->isEnabledWhitelabel() && $this->getOptions()->isOpt( 'wl_hide_updates', 'Y' );
|
288 |
}
|
289 |
|
290 |
/**
|
349 |
/** @var Options $opts */
|
350 |
$opts = $this->getOptions();
|
351 |
|
|
|
|
|
|
|
|
|
|
|
352 |
// Restricting Activate Plugins also means restricting the rest.
|
353 |
$aPluginsRestrictions = $opts->getAdminAccessArea_Plugins();
|
354 |
if ( in_array( 'activate_plugins', $aPluginsRestrictions ) ) {
|
src/lib/src/Modules/SecurityAdmin/Strings.php
CHANGED
@@ -92,155 +92,163 @@ class Strings extends Base\Strings {
|
|
92 |
* @throws \Exception
|
93 |
*/
|
94 |
public function getOptionStrings( string $key ) :array {
|
95 |
-
/** @var Options $
|
96 |
-
$
|
97 |
$sPlugName = $this->getCon()->getHumanName();
|
98 |
|
99 |
switch ( $key ) {
|
100 |
|
101 |
case 'enable_admin_access_restriction' :
|
102 |
-
$
|
103 |
-
$
|
104 |
-
$
|
105 |
break;
|
106 |
|
107 |
case 'admin_access_key' :
|
108 |
-
$
|
109 |
-
$
|
110 |
-
$
|
111 |
sprintf( '%s: %s', __( 'Careful', 'wp-simple-firewall' ), __( 'If you forget this, you could potentially lock yourself out from using this plugin.', 'wp-simple-firewall' ) ),
|
112 |
-
'<strong>'.( $
|
113 |
-
$oOpts->hasSecurityPIN() ? sprintf( __( 'To delete the current security PIN, type exactly "%s" and save.', 'wp-simple-firewall' ), '<strong>DELETE</strong>' ) : ''
|
114 |
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
115 |
break;
|
116 |
|
117 |
case 'sec_admin_users' :
|
118 |
-
$
|
119 |
-
$
|
120 |
-
$
|
121 |
-
|
122 |
-
|
|
|
|
|
123 |
break;
|
124 |
|
125 |
case 'admin_access_timeout' :
|
126 |
-
$
|
127 |
-
$
|
128 |
-
$
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
break;
|
136 |
|
137 |
case 'allow_email_override' :
|
138 |
-
$
|
139 |
-
$
|
140 |
-
$
|
141 |
-
|
142 |
break;
|
143 |
|
144 |
case 'admin_access_restrict_posts' :
|
145 |
-
$
|
146 |
-
$
|
147 |
-
$
|
148 |
-
|
149 |
break;
|
150 |
|
151 |
case 'admin_access_restrict_plugins' :
|
152 |
-
$
|
153 |
-
$
|
154 |
-
$
|
155 |
-
|
156 |
break;
|
157 |
|
158 |
case 'admin_access_restrict_options' :
|
159 |
-
$
|
160 |
-
$
|
161 |
-
$
|
162 |
break;
|
163 |
|
164 |
case 'admin_access_restrict_admin_users' :
|
165 |
-
$
|
166 |
-
$
|
167 |
-
$
|
168 |
break;
|
169 |
|
170 |
case 'admin_access_restrict_themes' :
|
171 |
-
$
|
172 |
-
$
|
173 |
-
$
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
break;
|
187 |
|
188 |
case 'whitelabel_enable' :
|
189 |
-
$
|
190 |
-
$
|
191 |
-
$
|
192 |
break;
|
193 |
case 'wl_hide_updates' :
|
194 |
-
$
|
195 |
-
$
|
196 |
-
$
|
197 |
break;
|
198 |
case 'wl_pluginnamemain' :
|
199 |
-
$
|
200 |
-
$
|
201 |
-
$
|
202 |
break;
|
203 |
case 'wl_replace_badge_url' :
|
204 |
-
$
|
205 |
-
$
|
206 |
-
$
|
207 |
break;
|
208 |
case 'wl_namemenu' :
|
209 |
-
$
|
210 |
-
$
|
211 |
-
$
|
212 |
break;
|
213 |
case 'wl_companyname' :
|
214 |
-
$
|
215 |
-
$
|
216 |
-
$
|
217 |
break;
|
218 |
case 'wl_description' :
|
219 |
-
$
|
220 |
-
$
|
221 |
-
$
|
222 |
break;
|
223 |
case 'wl_homeurl' :
|
224 |
-
$
|
225 |
-
$
|
226 |
-
$
|
227 |
break;
|
228 |
case 'wl_menuiconurl' :
|
229 |
-
$
|
230 |
-
$
|
231 |
-
$
|
232 |
-
|
233 |
break;
|
234 |
case 'wl_dashboardlogourl' :
|
235 |
-
$
|
236 |
-
$
|
237 |
-
$
|
238 |
-
|
239 |
break;
|
240 |
case 'wl_login2fa_logourl' :
|
241 |
-
$
|
242 |
-
$
|
243 |
-
$
|
244 |
break;
|
245 |
|
246 |
default:
|
@@ -248,9 +256,9 @@ class Strings extends Base\Strings {
|
|
248 |
}
|
249 |
|
250 |
return [
|
251 |
-
'name' => $
|
252 |
-
'summary' => $
|
253 |
-
'description' => $
|
254 |
];
|
255 |
}
|
256 |
}
|
92 |
* @throws \Exception
|
93 |
*/
|
94 |
public function getOptionStrings( string $key ) :array {
|
95 |
+
/** @var Options $opts */
|
96 |
+
$opts = $this->getOptions();
|
97 |
$sPlugName = $this->getCon()->getHumanName();
|
98 |
|
99 |
switch ( $key ) {
|
100 |
|
101 |
case 'enable_admin_access_restriction' :
|
102 |
+
$name = sprintf( __( 'Enable %s Module', 'wp-simple-firewall' ), __( 'Security Admin', 'wp-simple-firewall' ) );
|
103 |
+
$summary = __( 'Enforce Security Admin Access Restriction', 'wp-simple-firewall' );
|
104 |
+
$description = __( "Enable this with great care and consideration. Ensure that you set an Security PIN that you'll remember.", 'wp-simple-firewall' );
|
105 |
break;
|
106 |
|
107 |
case 'admin_access_key' :
|
108 |
+
$name = __( 'Security Admin PIN', 'wp-simple-firewall' );
|
109 |
+
$summary = __( 'Provide/Update Security Admin PIN', 'wp-simple-firewall' );
|
110 |
+
$description = [
|
111 |
sprintf( '%s: %s', __( 'Careful', 'wp-simple-firewall' ), __( 'If you forget this, you could potentially lock yourself out from using this plugin.', 'wp-simple-firewall' ) ),
|
112 |
+
'<strong>'.( $opts->hasSecurityPIN() ? __( 'Security PIN Currently Set', 'wp-simple-firewall' ) : __( 'Security PIN NOT Currently Set', 'wp-simple-firewall' ) ).'</strong>',
|
|
|
113 |
];
|
114 |
+
if ( $opts->hasSecurityPIN() ) {
|
115 |
+
$description[] = sprintf( __( 'To delete the current security PIN, type exactly "%s" and save.', 'wp-simple-firewall' ), '<strong>DELETE</strong>' );
|
116 |
+
if ( !empty( $opts->getSecurityAdminUsers() ) ) {
|
117 |
+
$description[] = sprintf( '%s: %s', __( 'Important', 'wp-simple-firewall' ), __( 'Deleting the PIN will also remove security admin users.', 'wp-simple-firewall' ) );
|
118 |
+
}
|
119 |
+
}
|
120 |
+
|
121 |
break;
|
122 |
|
123 |
case 'sec_admin_users' :
|
124 |
+
$name = __( 'Security Admins', 'wp-simple-firewall' );
|
125 |
+
$summary = __( 'Persistent Security Admins', 'wp-simple-firewall' );
|
126 |
+
$description = [
|
127 |
+
__( "Users provided will be security admins automatically, without needing the security PIN.", 'wp-simple-firewall' ),
|
128 |
+
__( 'Enter admin username, email or ID.', 'wp-simple-firewall' ).' '.__( '1 entry per-line.', 'wp-simple-firewall' ),
|
129 |
+
sprintf( '%s: %s', __( 'Note', 'wp-simple-firewall' ), __( 'Verified users will be converted to usernames.', 'wp-simple-firewall' ) )
|
130 |
+
];
|
131 |
break;
|
132 |
|
133 |
case 'admin_access_timeout' :
|
134 |
+
$name = __( 'Security Admin Timeout', 'wp-simple-firewall' );
|
135 |
+
$summary = __( 'Specify An Automatic Timeout Interval For Security Admin Access', 'wp-simple-firewall' );
|
136 |
+
$description = __( 'This will automatically expire your Security Admin Session.', 'wp-simple-firewall' )
|
137 |
+
.'<br />'
|
138 |
+
.sprintf(
|
139 |
+
'%s: %s',
|
140 |
+
__( 'Default', 'wp-simple-firewall' ),
|
141 |
+
sprintf( '%s minutes', $opts->getOptDefault( 'admin_access_timeout' ) )
|
142 |
+
);
|
143 |
break;
|
144 |
|
145 |
case 'allow_email_override' :
|
146 |
+
$name = __( 'Allow Email Override', 'wp-simple-firewall' );
|
147 |
+
$summary = __( 'Allow Email Override Of Admin Access Restrictions', 'wp-simple-firewall' );
|
148 |
+
$description = __( 'Allow the use of verification emails to override and switch off the Security Admin restrictions.', 'wp-simple-firewall' )
|
149 |
+
.'<br/>'.sprintf( __( "The email address specified in %s's General settings will be used.", 'wp-simple-firewall' ), $sPlugName );
|
150 |
break;
|
151 |
|
152 |
case 'admin_access_restrict_posts' :
|
153 |
+
$name = __( 'Pages', 'wp-simple-firewall' );
|
154 |
+
$summary = __( 'Restrict Access To Key WordPress Posts And Pages Actions', 'wp-simple-firewall' );
|
155 |
+
$description = sprintf( '%s: %s', __( 'Careful', 'wp-simple-firewall' ), __( 'This will restrict access to page/post creation, editing and deletion.', 'wp-simple-firewall' ) )
|
156 |
+
.'<br />'.sprintf( '%s: %s', __( 'Note', 'wp-simple-firewall' ), sprintf( __( 'Selecting "%s" will also restrict all other options.', 'wp-simple-firewall' ), __( 'Edit', 'wp-simple-firewall' ) ) );
|
157 |
break;
|
158 |
|
159 |
case 'admin_access_restrict_plugins' :
|
160 |
+
$name = __( 'Plugins', 'wp-simple-firewall' );
|
161 |
+
$summary = __( 'Restrict Access To Key WordPress Plugin Actions', 'wp-simple-firewall' );
|
162 |
+
$description = sprintf( '%s: %s', __( 'Careful', 'wp-simple-firewall' ), __( 'This will restrict access to plugin installation, update, activation and deletion.', 'wp-simple-firewall' ) )
|
163 |
+
.'<br />'.sprintf( '%s: %s', __( 'Note', 'wp-simple-firewall' ), sprintf( __( 'Selecting "%s" will also restrict all other options.', 'wp-simple-firewall' ), __( 'Activate', 'wp-simple-firewall' ) ) );
|
164 |
break;
|
165 |
|
166 |
case 'admin_access_restrict_options' :
|
167 |
+
$name = __( 'WordPress Options', 'wp-simple-firewall' );
|
168 |
+
$summary = __( 'Restrict Access To Certain WordPress Admin Options', 'wp-simple-firewall' );
|
169 |
+
$description = sprintf( '%s: %s', __( 'Careful', 'wp-simple-firewall' ), __( 'This will restrict the ability of WordPress administrators from changing key WordPress settings.', 'wp-simple-firewall' ) );
|
170 |
break;
|
171 |
|
172 |
case 'admin_access_restrict_admin_users' :
|
173 |
+
$name = __( 'Admin Users', 'wp-simple-firewall' );
|
174 |
+
$summary = __( 'Restrict Access To Create/Delete/Modify Other Admin Users', 'wp-simple-firewall' );
|
175 |
+
$description = sprintf( '%s: %s', __( 'Careful', 'wp-simple-firewall' ), __( 'This will restrict the ability of WordPress administrators from creating, modifying or promoting other administrators.', 'wp-simple-firewall' ) );
|
176 |
break;
|
177 |
|
178 |
case 'admin_access_restrict_themes' :
|
179 |
+
$name = __( 'Themes', 'wp-simple-firewall' );
|
180 |
+
$summary = __( 'Restrict Access To WordPress Theme Actions', 'wp-simple-firewall' );
|
181 |
+
$description = sprintf( '%s: %s', __( 'Careful', 'wp-simple-firewall' ), __( 'This will restrict access to theme installation, update, activation and deletion.', 'wp-simple-firewall' ) )
|
182 |
+
.'<br />'.
|
183 |
+
sprintf( '%s: %s',
|
184 |
+
__( 'Note', 'wp-simple-firewall' ),
|
185 |
+
sprintf(
|
186 |
+
__( 'Selecting "%s" will also restrict all other options.', 'wp-simple-firewall' ),
|
187 |
+
sprintf(
|
188 |
+
__( '%s and %s', 'wp-simple-firewall' ),
|
189 |
+
__( 'Activate', 'wp-simple-firewall' ),
|
190 |
+
__( 'Edit Theme Options', 'wp-simple-firewall' )
|
191 |
+
)
|
192 |
+
)
|
193 |
+
);
|
194 |
break;
|
195 |
|
196 |
case 'whitelabel_enable' :
|
197 |
+
$name = sprintf( '%s: %s', __( 'Enable', 'wp-simple-firewall' ), __( 'White Label', 'wp-simple-firewall' ) );
|
198 |
+
$summary = __( 'Activate Your White Label Settings', 'wp-simple-firewall' );
|
199 |
+
$description = __( 'Turn on/off the application of your White Label settings.', 'wp-simple-firewall' );
|
200 |
break;
|
201 |
case 'wl_hide_updates' :
|
202 |
+
$name = __( 'Hide Updates', 'wp-simple-firewall' );
|
203 |
+
$summary = __( 'Hide Plugin Updates From Non-Security Admins', 'wp-simple-firewall' );
|
204 |
+
$description = sprintf( __( 'Hide available %s updates from non-security administrators.', 'wp-simple-firewall' ), $sPlugName );
|
205 |
break;
|
206 |
case 'wl_pluginnamemain' :
|
207 |
+
$name = __( 'Plugin Name', 'wp-simple-firewall' );
|
208 |
+
$summary = __( 'The Name Of The Plugin', 'wp-simple-firewall' );
|
209 |
+
$description = __( 'The name of the plugin that will be displayed to your site users.', 'wp-simple-firewall' );
|
210 |
break;
|
211 |
case 'wl_replace_badge_url' :
|
212 |
+
$name = __( 'Replace Plugin Badge', 'wp-simple-firewall' );
|
213 |
+
$summary = __( 'Replace Plugin Badge URL and Images', 'wp-simple-firewall' );
|
214 |
+
$description = __( 'When using the plugin badge, replace the URL and link with your Whitelabel settings.', 'wp-simple-firewall' );
|
215 |
break;
|
216 |
case 'wl_namemenu' :
|
217 |
+
$name = __( 'Menu Title', 'wp-simple-firewall' );
|
218 |
+
$summary = __( 'The Main Menu Title Of The Plugin', 'wp-simple-firewall' );
|
219 |
+
$description = sprintf( __( 'The Main Menu Title Of The Plugin. If left empty, the "%s" will be used.', 'wp-simple-firewall' ), __( 'Plugin Name', 'wp-simple-firewall' ) );
|
220 |
break;
|
221 |
case 'wl_companyname' :
|
222 |
+
$name = __( 'Company Name', 'wp-simple-firewall' );
|
223 |
+
$summary = __( 'The Name Of Your Company', 'wp-simple-firewall' );
|
224 |
+
$description = __( 'Provide the name of your company.', 'wp-simple-firewall' );
|
225 |
break;
|
226 |
case 'wl_description' :
|
227 |
+
$name = __( 'Description', 'wp-simple-firewall' );
|
228 |
+
$summary = __( 'The Description Of The Plugin', 'wp-simple-firewall' );
|
229 |
+
$description = __( 'The description of the plugin displayed on the plugins page.', 'wp-simple-firewall' );
|
230 |
break;
|
231 |
case 'wl_homeurl' :
|
232 |
+
$name = __( 'Home URL', 'wp-simple-firewall' );
|
233 |
+
$summary = __( 'Plugin Home Page URL', 'wp-simple-firewall' );
|
234 |
+
$description = __( "When a user clicks the home link for this plugin, this is where they'll be directed.", 'wp-simple-firewall' );
|
235 |
break;
|
236 |
case 'wl_menuiconurl' :
|
237 |
+
$name = __( 'Menu Icon', 'wp-simple-firewall' );
|
238 |
+
$summary = __( 'Menu Icon URL', 'wp-simple-firewall' );
|
239 |
+
$description = __( 'The URL of the icon to display in the menu.', 'wp-simple-firewall' )
|
240 |
+
.' '.sprintf( __( 'The %s should measure %s.', 'wp-simple-firewall' ), __( 'icon', 'wp-simple-firewall' ), '16px x 16px' );
|
241 |
break;
|
242 |
case 'wl_dashboardlogourl' :
|
243 |
+
$name = __( 'Dashboard Logo', 'wp-simple-firewall' );
|
244 |
+
$summary = __( 'Dashboard Logo URL', 'wp-simple-firewall' );
|
245 |
+
$description = __( 'The URL of the logo to display in the admin pages.', 'wp-simple-firewall' )
|
246 |
+
.' '.sprintf( __( 'The %s should measure %s.', 'wp-simple-firewall' ), __( 'logo', 'wp-simple-firewall' ), '128px x 128px' );
|
247 |
break;
|
248 |
case 'wl_login2fa_logourl' :
|
249 |
+
$name = __( '2FA Login Logo URL', 'wp-simple-firewall' );
|
250 |
+
$summary = __( '2FA Login Logo URL', 'wp-simple-firewall' );
|
251 |
+
$description = __( 'The URL of the logo to display on the Two-Factor Authentication login page.', 'wp-simple-firewall' );
|
252 |
break;
|
253 |
|
254 |
default:
|
256 |
}
|
257 |
|
258 |
return [
|
259 |
+
'name' => $name,
|
260 |
+
'summary' => $summary,
|
261 |
+
'description' => $description,
|
262 |
];
|
263 |
}
|
264 |
}
|
src/lib/src/Modules/Sessions/ModCon.php
CHANGED
@@ -22,7 +22,8 @@ class ModCon extends BaseShield\ModCon {
|
|
22 |
}
|
23 |
|
24 |
public function getDbHandler_Sessions() :Databases\Session\Handler {
|
25 |
-
|
|
|
26 |
}
|
27 |
|
28 |
public function isAutoAddSessions() :bool {
|
22 |
}
|
23 |
|
24 |
public function getDbHandler_Sessions() :Databases\Session\Handler {
|
25 |
+
$new = $this->getDbH( 'sessions' );
|
26 |
+
return empty( $new ) ? $this->getDbH( 'session' ) : $new;
|
27 |
}
|
28 |
|
29 |
public function isAutoAddSessions() :bool {
|
src/lib/src/Modules/Sessions/Processor.php
CHANGED
@@ -33,6 +33,7 @@ class Processor extends BaseShield\Processor {
|
|
33 |
|
34 |
protected function captureLogin( \WP_User $user ) {
|
35 |
$this->activateUserSession( $user );
|
|
|
36 |
}
|
37 |
|
38 |
public function onWpLoaded() {
|
33 |
|
34 |
protected function captureLogin( \WP_User $user ) {
|
35 |
$this->activateUserSession( $user );
|
36 |
+
$this->getCon()->fireEvent( 'login_success' );
|
37 |
}
|
38 |
|
39 |
public function onWpLoaded() {
|
src/lib/src/Modules/Traffic/AjaxHandler.php
CHANGED
@@ -10,14 +10,14 @@ class AjaxHandler extends Shield\Modules\BaseShield\AjaxHandler {
|
|
10 |
|
11 |
switch ( $action ) {
|
12 |
case 'render_table_traffic':
|
13 |
-
$
|
14 |
break;
|
15 |
|
16 |
default:
|
17 |
-
$
|
18 |
}
|
19 |
|
20 |
-
return $
|
21 |
}
|
22 |
|
23 |
private function ajaxExec_BuildTableTraffic() :array {
|
10 |
|
11 |
switch ( $action ) {
|
12 |
case 'render_table_traffic':
|
13 |
+
$response = $this->ajaxExec_BuildTableTraffic();
|
14 |
break;
|
15 |
|
16 |
default:
|
17 |
+
$response = parent::processAjaxAction( $action );
|
18 |
}
|
19 |
|
20 |
+
return $response;
|
21 |
}
|
22 |
|
23 |
private function ajaxExec_BuildTableTraffic() :array {
|
src/lib/src/Modules/Traffic/Lib/Logger.php
CHANGED
@@ -6,7 +6,6 @@ use FernleafSystems\Wordpress\Plugin\Shield\Databases\Traffic\EntryVO;
|
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Traffic;
|
8 |
use FernleafSystems\Wordpress\Services\Services;
|
9 |
-
use FernleafSystems\Wordpress\Services\Utilities\Net\IpIdentify;
|
10 |
|
11 |
class Logger {
|
12 |
|
@@ -26,7 +25,7 @@ class Logger {
|
|
26 |
|
27 |
private function isRequestToBeLogged() :bool {
|
28 |
return !$this->getCon()->plugin_deleting
|
29 |
-
&& apply_filters(
|
30 |
&& ( !$this->isCustomExcluded() )
|
31 |
&& ( !$this->isRequestTypeExcluded() );
|
32 |
}
|
@@ -68,25 +67,13 @@ class Logger {
|
|
68 |
}
|
69 |
|
70 |
private function isServiceIp_Search() :bool {
|
71 |
-
return in_array( Services::IP()->getIpDetector()->getIPIdentity(),
|
72 |
-
|
73 |
-
IpIdentify::BAIDU,
|
74 |
-
IpIdentify::BING,
|
75 |
-
IpIdentify::DUCKDUCKGO,
|
76 |
-
IpIdentify::GOOGLE,
|
77 |
-
IpIdentify::HUAWEI,
|
78 |
-
IpIdentify::YAHOO,
|
79 |
-
IpIdentify::YANDEX,
|
80 |
-
] );
|
81 |
}
|
82 |
|
83 |
private function isServiceIp_Uptime() :bool {
|
84 |
-
return in_array( Services::IP()->getIpDetector()->getIPIdentity(),
|
85 |
-
|
86 |
-
IpIdentify::STATUSCAKE,
|
87 |
-
IpIdentify::UPTIMEROBOT,
|
88 |
-
IpIdentify::NODEPING
|
89 |
-
] );
|
90 |
}
|
91 |
|
92 |
private function logTraffic() {
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Traffic;
|
8 |
use FernleafSystems\Wordpress\Services\Services;
|
|
|
9 |
|
10 |
class Logger {
|
11 |
|
25 |
|
26 |
private function isRequestToBeLogged() :bool {
|
27 |
return !$this->getCon()->plugin_deleting
|
28 |
+
&& apply_filters( 'shield/is_log_traffic', true )
|
29 |
&& ( !$this->isCustomExcluded() )
|
30 |
&& ( !$this->isRequestTypeExcluded() );
|
31 |
}
|
67 |
}
|
68 |
|
69 |
private function isServiceIp_Search() :bool {
|
70 |
+
return in_array( Services::IP()->getIpDetector()->getIPIdentity(),
|
71 |
+
Services::ServiceProviders()->getSearchProviders() );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
72 |
}
|
73 |
|
74 |
private function isServiceIp_Uptime() :bool {
|
75 |
+
return in_array( Services::IP()->getIpDetector()->getIPIdentity(),
|
76 |
+
Services::ServiceProviders()->getUptimeProviders() );
|
|
|
|
|
|
|
|
|
77 |
}
|
78 |
|
79 |
private function logTraffic() {
|
src/lib/src/Modules/Traffic/ModCon.php
CHANGED
@@ -4,6 +4,7 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Traffic;
|
|
4 |
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Databases;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
|
|
|
7 |
use FernleafSystems\Wordpress\Services\Services;
|
8 |
|
9 |
class ModCon extends BaseShield\ModCon {
|
@@ -12,6 +13,16 @@ class ModCon extends BaseShield\ModCon {
|
|
12 |
return $this->getDbH( 'traffic' );
|
13 |
}
|
14 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
protected function preProcessOptions() {
|
16 |
/** @var Options $opts */
|
17 |
$opts = $this->getOptions();
|
4 |
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Databases;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\BaseShield;
|
7 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Utilities\Tool\DbTableExport;
|
8 |
use FernleafSystems\Wordpress\Services\Services;
|
9 |
|
10 |
class ModCon extends BaseShield\ModCon {
|
13 |
return $this->getDbH( 'traffic' );
|
14 |
}
|
15 |
|
16 |
+
protected function handleFileDownload( string $downloadID ) {
|
17 |
+
switch ( $downloadID ) {
|
18 |
+
case 'db_traffic':
|
19 |
+
( new DbTableExport() )
|
20 |
+
->setDbHandler( $this->getDbHandler_Traffic() )
|
21 |
+
->toCSV();
|
22 |
+
break;
|
23 |
+
}
|
24 |
+
}
|
25 |
+
|
26 |
protected function preProcessOptions() {
|
27 |
/** @var Options $opts */
|
28 |
$opts = $this->getOptions();
|
src/lib/src/Modules/Traffic/Processor.php
CHANGED
@@ -3,12 +3,7 @@
|
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Traffic;
|
4 |
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules;
|
6 |
-
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Traffic\Lib;
|
7 |
|
8 |
-
/**
|
9 |
-
* Class Processor
|
10 |
-
* @package FernleafSystems\Wordpress\Plugin\Shield\Modules\Traffic
|
11 |
-
*/
|
12 |
class Processor extends Modules\BaseShield\Processor {
|
13 |
|
14 |
protected function run() {
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\Traffic;
|
4 |
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules;
|
|
|
6 |
|
|
|
|
|
|
|
|
|
7 |
class Processor extends Modules\BaseShield\Processor {
|
8 |
|
9 |
protected function run() {
|
src/lib/src/Modules/Traffic/Strings.php
CHANGED
@@ -28,27 +28,27 @@ class Strings extends Base\Strings {
|
|
28 |
switch ( $section ) {
|
29 |
|
30 |
case 'section_enable_plugin_feature_traffic' :
|
31 |
-
$
|
32 |
-
$
|
33 |
-
$
|
34 |
sprintf( '%s - %s', __( 'Purpose', 'wp-simple-firewall' ), __( 'Monitor and review all requests to your site.', 'wp-simple-firewall' ) ),
|
35 |
sprintf( '%s - %s', __( 'Recommendation', 'wp-simple-firewall' ), sprintf( __( 'Required only if you need to review and investigate and monitor requests to your site', 'wp-simple-firewall' ) ) )
|
36 |
];
|
37 |
break;
|
38 |
|
39 |
case 'section_traffic_options' :
|
40 |
-
$
|
41 |
-
$
|
|
|
42 |
sprintf( '%s - %s', __( 'Purpose', 'wp-simple-firewall' ), __( 'Provides finer control over the Traffic Watch system.', 'wp-simple-firewall' ) ),
|
43 |
sprintf( '%s - %s', __( 'Recommendation', 'wp-simple-firewall' ), sprintf( __( 'These settings are dependent on your requirements.', 'wp-simple-firewall' ), __( 'User Management', 'wp-simple-firewall' ) ) )
|
44 |
];
|
45 |
-
$sTitleShort = __( 'Traffic Logging Options', 'wp-simple-firewall' );
|
46 |
break;
|
47 |
|
48 |
case 'section_traffic_limiter' :
|
49 |
-
$
|
50 |
-
$
|
51 |
-
$
|
52 |
sprintf( '%s - %s', __( 'Purpose', 'wp-simple-firewall' ), __( 'Prevents excessive requests from a single visitor.', 'wp-simple-firewall' ) ),
|
53 |
sprintf( '%s - %s', __( 'Important', 'wp-simple-firewall' ), sprintf( __( 'This feature is only available while the Traffic Logger is active.', 'wp-simple-firewall' ), __( 'User Management', 'wp-simple-firewall' ) ) ),
|
54 |
sprintf( '%s - %s', __( 'Warning', 'wp-simple-firewall' ), __( 'Use this feature with care.', 'wp-simple-firewall' ) )
|
@@ -61,9 +61,9 @@ class Strings extends Base\Strings {
|
|
61 |
}
|
62 |
|
63 |
return [
|
64 |
-
'title' => $
|
65 |
-
'title_short' => $
|
66 |
-
'summary' => ( isset( $
|
67 |
];
|
68 |
}
|
69 |
|
@@ -80,69 +80,75 @@ class Strings extends Base\Strings {
|
|
80 |
switch ( $key ) {
|
81 |
|
82 |
case 'enable_traffic' :
|
83 |
-
$
|
84 |
-
$
|
85 |
-
$
|
86 |
break;
|
87 |
|
88 |
case 'enable_logger' :
|
89 |
-
$
|
90 |
-
$
|
91 |
-
$
|
92 |
break;
|
93 |
|
94 |
case 'type_exclusions' :
|
95 |
-
$
|
96 |
-
$
|
97 |
-
$
|
98 |
-
|
99 |
break;
|
100 |
|
101 |
case 'custom_exclusions' :
|
102 |
-
$
|
103 |
-
$
|
104 |
-
$
|
105 |
-
|
106 |
-
|
|
|
|
|
107 |
break;
|
108 |
|
109 |
case 'auto_clean' :
|
110 |
-
$
|
111 |
-
$
|
112 |
-
$
|
113 |
break;
|
114 |
|
115 |
case 'max_entries' :
|
116 |
-
$
|
117 |
-
$
|
118 |
-
$
|
119 |
break;
|
120 |
|
121 |
case 'enable_limiter' :
|
122 |
-
$
|
123 |
-
$
|
124 |
-
$
|
125 |
break;
|
126 |
|
127 |
case 'limit_requests' :
|
128 |
-
$
|
129 |
-
$
|
130 |
-
$
|
131 |
-
|
132 |
-
|
133 |
-
|
|
|
|
|
134 |
break;
|
135 |
|
136 |
case 'limit_time_span' :
|
137 |
-
$
|
138 |
-
$
|
139 |
-
$
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
|
|
|
|
146 |
break;
|
147 |
|
148 |
default:
|
@@ -150,9 +156,9 @@ class Strings extends Base\Strings {
|
|
150 |
}
|
151 |
|
152 |
return [
|
153 |
-
'name' => $
|
154 |
-
'summary' => $
|
155 |
-
'description' => $
|
156 |
];
|
157 |
}
|
158 |
}
|
28 |
switch ( $section ) {
|
29 |
|
30 |
case 'section_enable_plugin_feature_traffic' :
|
31 |
+
$short = sprintf( '%s/%s', __( 'On', 'wp-simple-firewall' ), __( 'Off', 'wp-simple-firewall' ) );
|
32 |
+
$title = sprintf( __( 'Enable Module: %s', 'wp-simple-firewall' ), $sModName );
|
33 |
+
$summary = [
|
34 |
sprintf( '%s - %s', __( 'Purpose', 'wp-simple-firewall' ), __( 'Monitor and review all requests to your site.', 'wp-simple-firewall' ) ),
|
35 |
sprintf( '%s - %s', __( 'Recommendation', 'wp-simple-firewall' ), sprintf( __( 'Required only if you need to review and investigate and monitor requests to your site', 'wp-simple-firewall' ) ) )
|
36 |
];
|
37 |
break;
|
38 |
|
39 |
case 'section_traffic_options' :
|
40 |
+
$short = __( 'Traffic Logging Options', 'wp-simple-firewall' );
|
41 |
+
$title = __( 'Traffic Watch Options', 'wp-simple-firewall' );
|
42 |
+
$summary = [
|
43 |
sprintf( '%s - %s', __( 'Purpose', 'wp-simple-firewall' ), __( 'Provides finer control over the Traffic Watch system.', 'wp-simple-firewall' ) ),
|
44 |
sprintf( '%s - %s', __( 'Recommendation', 'wp-simple-firewall' ), sprintf( __( 'These settings are dependent on your requirements.', 'wp-simple-firewall' ), __( 'User Management', 'wp-simple-firewall' ) ) )
|
45 |
];
|
|
|
46 |
break;
|
47 |
|
48 |
case 'section_traffic_limiter' :
|
49 |
+
$title = __( 'Brute Force Traffic Rate Limiting', 'wp-simple-firewall' );
|
50 |
+
$short = __( 'Traffic Rate Limiting', 'wp-simple-firewall' );
|
51 |
+
$summary = [
|
52 |
sprintf( '%s - %s', __( 'Purpose', 'wp-simple-firewall' ), __( 'Prevents excessive requests from a single visitor.', 'wp-simple-firewall' ) ),
|
53 |
sprintf( '%s - %s', __( 'Important', 'wp-simple-firewall' ), sprintf( __( 'This feature is only available while the Traffic Logger is active.', 'wp-simple-firewall' ), __( 'User Management', 'wp-simple-firewall' ) ) ),
|
54 |
sprintf( '%s - %s', __( 'Warning', 'wp-simple-firewall' ), __( 'Use this feature with care.', 'wp-simple-firewall' ) )
|
61 |
}
|
62 |
|
63 |
return [
|
64 |
+
'title' => $title,
|
65 |
+
'title_short' => $short,
|
66 |
+
'summary' => ( isset( $summary ) && is_array( $summary ) ) ? $summary : [],
|
67 |
];
|
68 |
}
|
69 |
|
80 |
switch ( $key ) {
|
81 |
|
82 |
case 'enable_traffic' :
|
83 |
+
$name = sprintf( __( 'Enable %s Module', 'wp-simple-firewall' ), $sModName );
|
84 |
+
$summary = sprintf( __( 'Enable (or Disable) The %s Module', 'wp-simple-firewall' ), $sModName );
|
85 |
+
$desc = sprintf( __( 'Un-Checking this option will completely disable the %s module.', 'wp-simple-firewall' ), $sModName );
|
86 |
break;
|
87 |
|
88 |
case 'enable_logger' :
|
89 |
+
$name = __( 'Enable Traffic Logger', 'wp-simple-firewall' );
|
90 |
+
$summary = __( 'Turn On The Traffic Logging Feature', 'wp-simple-firewall' );
|
91 |
+
$desc = __( 'Enable or disable the ability to log and monitor requests to your site', 'wp-simple-firewall' );
|
92 |
break;
|
93 |
|
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' :
|
102 |
+
$name = __( 'Custom Exclusions', 'wp-simple-firewall' );
|
103 |
+
$summary = __( 'Provide Custom Traffic Exclusions', 'wp-simple-firewall' );
|
104 |
+
$desc = [
|
105 |
+
__( "For each entry, if the text is present in either the User Agent or request Path, it will be excluded.", 'wp-simple-firewall' ),
|
106 |
+
__( 'Take a new line for each entry.', 'wp-simple-firewall' ),
|
107 |
+
__( 'Comparisons are case-insensitive.', 'wp-simple-firewall' )
|
108 |
+
];
|
109 |
break;
|
110 |
|
111 |
case 'auto_clean' :
|
112 |
+
$name = __( 'Auto Expiry Cleaning', 'wp-simple-firewall' );
|
113 |
+
$summary = __( 'Enable Traffic Log Auto Expiry', 'wp-simple-firewall' );
|
114 |
+
$desc = __( 'DB cleanup will delete logs older than this maximum value (in days).', 'wp-simple-firewall' );
|
115 |
break;
|
116 |
|
117 |
case 'max_entries' :
|
118 |
+
$name = __( 'Max Log Length', 'wp-simple-firewall' );
|
119 |
+
$summary = __( 'Maximum Traffic Log Length To Keep', 'wp-simple-firewall' );
|
120 |
+
$desc = __( 'DB cleanup will delete logs to maintain this maximum number of records.', 'wp-simple-firewall' );
|
121 |
break;
|
122 |
|
123 |
case 'enable_limiter' :
|
124 |
+
$name = __( 'Enable Rate Limiting', 'wp-simple-firewall' );
|
125 |
+
$summary = __( 'Turn On The Rate Limiting Feature', 'wp-simple-firewall' );
|
126 |
+
$desc = __( 'Enable or disable the rate limiting feature according to your rate limiting parameters.', 'wp-simple-firewall' );
|
127 |
break;
|
128 |
|
129 |
case 'limit_requests' :
|
130 |
+
$name = __( 'Max Request Limit', 'wp-simple-firewall' );
|
131 |
+
$summary = __( 'Maximum Number Of Requests Allowed In Time Limit', 'wp-simple-firewall' );
|
132 |
+
$desc = [
|
133 |
+
__( 'The maximum number of requests that are allowed within the given request time limit.', 'wp-simple-firewall' ),
|
134 |
+
__( 'Any visitor that exceeds this number of requests in the given time period will register an offense against their IP address.', 'wp-simple-firewall' ),
|
135 |
+
__( 'Enough offenses will result in a ban of the IP address.', 'wp-simple-firewall' ),
|
136 |
+
__( 'Use a larger maximum request limit to reduce the risk of blocking legitimate visitors.', 'wp-simple-firewall' )
|
137 |
+
];
|
138 |
break;
|
139 |
|
140 |
case 'limit_time_span' :
|
141 |
+
$name = __( 'Request Limit Time Interval', 'wp-simple-firewall' );
|
142 |
+
$summary = __( 'The Time Interval To Test For Excessive Requests', 'wp-simple-firewall' );
|
143 |
+
$desc = [
|
144 |
+
__( 'The time period within which to monitor for multiple requests that exceed the max request limit.', 'wp-simple-firewall' ),
|
145 |
+
sprintf( '%s: %s', __( 'Note', 'wp-simple-firewall' ), __( 'Interval is measured in seconds.', 'wp-simple-firewall' ) ),
|
146 |
+
sprintf( '%s: %s', __( 'Example', 'wp-simple-firewall' ),
|
147 |
+
sprintf( __( 'Use %s to test for excessive requests within a %s minutes interval.', 'wp-simple-firewall' ), '<code>300</code>', 5 ) ),
|
148 |
+
sprintf( '%s: %s', __( 'Example', 'wp-simple-firewall' ),
|
149 |
+
sprintf( __( 'Use %s to test for excessive requests within a %s minutes interval.', 'wp-simple-firewall' ), '<code>3600</code>', 60 ) ),
|
150 |
+
__( 'Use a smaller interval to reduce the risk of blocking legitimate visitors.', 'wp-simple-firewall' )
|
151 |
+
];
|
152 |
break;
|
153 |
|
154 |
default:
|
156 |
}
|
157 |
|
158 |
return [
|
159 |
+
'name' => $name,
|
160 |
+
'summary' => $summary,
|
161 |
+
'description' => $desc,
|
162 |
];
|
163 |
}
|
164 |
}
|
src/lib/src/Modules/Traffic/UI.php
CHANGED
@@ -48,35 +48,31 @@ class UI extends BaseShield\UI {
|
|
48 |
);
|
49 |
}
|
50 |
|
51 |
-
/**
|
52 |
-
* @param string $section
|
53 |
-
* @return array
|
54 |
-
*/
|
55 |
protected function getSectionWarnings( string $section ) :array {
|
56 |
-
/** @var Options $
|
57 |
-
$
|
58 |
|
59 |
-
$
|
60 |
|
61 |
-
$
|
62 |
-
if ( !$
|
63 |
-
$
|
64 |
}
|
65 |
|
66 |
switch ( $section ) {
|
67 |
case 'section_traffic_limiter':
|
68 |
if ( $this->getCon()->isPremiumActive() ) {
|
69 |
-
if ( !$
|
70 |
-
$
|
71 |
}
|
72 |
}
|
73 |
else {
|
74 |
-
$
|
75 |
}
|
76 |
break;
|
77 |
}
|
78 |
|
79 |
-
return $
|
80 |
}
|
81 |
|
82 |
protected function getSettingsRelatedLinks() :array {
|
48 |
);
|
49 |
}
|
50 |
|
|
|
|
|
|
|
|
|
51 |
protected function getSectionWarnings( string $section ) :array {
|
52 |
+
/** @var Options $opts */
|
53 |
+
$opts = $this->getOptions();
|
54 |
|
55 |
+
$warning = [];
|
56 |
|
57 |
+
$srvIP = Services::IP();
|
58 |
+
if ( !$srvIP->isValidIp_PublicRange( $srvIP->getRequestIp() ) ) {
|
59 |
+
$warning[] = __( 'Traffic Watcher will not run because visitor IP address detection is not correctly configured.', 'wp-simple-firewall' );
|
60 |
}
|
61 |
|
62 |
switch ( $section ) {
|
63 |
case 'section_traffic_limiter':
|
64 |
if ( $this->getCon()->isPremiumActive() ) {
|
65 |
+
if ( !$opts->isTrafficLoggerEnabled() ) {
|
66 |
+
$warning[] = sprintf( __( '%s may only be enabled if the Traffic Logger feature is also turned on.', 'wp-simple-firewall' ), __( 'Traffic Rate Limiter', 'wp-simple-firewall' ) );
|
67 |
}
|
68 |
}
|
69 |
else {
|
70 |
+
$warning[] = sprintf( __( '%s is a Pro-only feature.', 'wp-simple-firewall' ), __( 'Traffic Rate Limiter', 'wp-simple-firewall' ) );
|
71 |
}
|
72 |
break;
|
73 |
}
|
74 |
|
75 |
+
return $warning;
|
76 |
}
|
77 |
|
78 |
protected function getSettingsRelatedLinks() :array {
|
src/lib/src/Modules/UserManagement/Lib/Password/UserPasswordHandler.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\UserManagement\Lib\Password;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Logic\
|
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;
|
@@ -16,10 +16,10 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
16 |
class UserPasswordHandler {
|
17 |
|
18 |
use ModConsumer;
|
19 |
-
use
|
20 |
use WpLoginCapture;
|
21 |
|
22 |
-
protected function canRun() {
|
23 |
/** @var UserManagement\Options $opts */
|
24 |
$opts = $this->getOptions();
|
25 |
return $opts->isPasswordPoliciesEnabled();
|
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;
|
16 |
class UserPasswordHandler {
|
17 |
|
18 |
use ModConsumer;
|
19 |
+
use ExecOnce;
|
20 |
use WpLoginCapture;
|
21 |
|
22 |
+
protected function canRun() :bool {
|
23 |
/** @var UserManagement\Options $opts */
|
24 |
$opts = $this->getOptions();
|
25 |
return $opts->isPasswordPoliciesEnabled();
|
src/lib/src/Modules/UserManagement/Lib/Registration/EmailValidate.php
CHANGED
@@ -10,7 +10,7 @@ class EmailValidate {
|
|
10 |
|
11 |
use ModConsumer;
|
12 |
|
13 |
-
private $
|
14 |
|
15 |
public function run() {
|
16 |
/** @var UserManagement\Options $oOpts */
|
@@ -25,30 +25,30 @@ class EmailValidate {
|
|
25 |
* @return array
|
26 |
*/
|
27 |
public function validateNewUserEmail( $aUserData ) {
|
28 |
-
$
|
29 |
-
/** @var UserManagement\Options $
|
30 |
|
31 |
-
if ( !is_array( $this->
|
32 |
-
$this->
|
33 |
}
|
34 |
|
35 |
// This hook seems to be called twice on any given registration.
|
36 |
-
if ( !in_array( $
|
37 |
-
$this->
|
38 |
|
39 |
-
$
|
40 |
$sInvalidBecause = null;
|
41 |
-
if ( !is_email( $
|
42 |
$sInvalidBecause = 'syntax';
|
43 |
}
|
44 |
else {
|
45 |
-
$
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
if ( !empty( $
|
50 |
-
$aChecks = $
|
51 |
-
$aVerifys = ( new Email( $
|
52 |
if ( is_array( $aVerifys ) ) {
|
53 |
foreach ( $aVerifys as $sVerifyKey => $bIsValid ) {
|
54 |
if ( !$bIsValid && in_array( $sVerifyKey, $aChecks ) ) {
|
@@ -61,12 +61,12 @@ class EmailValidate {
|
|
61 |
}
|
62 |
|
63 |
if ( !empty( $sInvalidBecause ) ) {
|
64 |
-
$sOpt = $
|
65 |
$this->getCon()->fireEvent(
|
66 |
'reg_email_invalid',
|
67 |
[
|
68 |
'audit' => [
|
69 |
-
'email' => sanitize_email( $
|
70 |
'reason' => sanitize_key( $sInvalidBecause ),
|
71 |
],
|
72 |
'offense_count' => $sOpt == 'log' ? 0 : 1,
|
10 |
|
11 |
use ModConsumer;
|
12 |
|
13 |
+
private $track;
|
14 |
|
15 |
public function run() {
|
16 |
/** @var UserManagement\Options $oOpts */
|
25 |
* @return array
|
26 |
*/
|
27 |
public function validateNewUserEmail( $aUserData ) {
|
28 |
+
$email = $aUserData[ 'user_email' ];
|
29 |
+
/** @var UserManagement\Options $opts */
|
30 |
|
31 |
+
if ( !is_array( $this->track ) ) {
|
32 |
+
$this->track = [];
|
33 |
}
|
34 |
|
35 |
// This hook seems to be called twice on any given registration.
|
36 |
+
if ( !empty( $email ) && !in_array( $email, $this->track ) ) {
|
37 |
+
$this->track[] = $email;
|
38 |
|
39 |
+
$opts = $this->getOptions();
|
40 |
$sInvalidBecause = null;
|
41 |
+
if ( !is_email( $email ) ) {
|
42 |
$sInvalidBecause = 'syntax';
|
43 |
}
|
44 |
else {
|
45 |
+
$apiToken = $this->getCon()
|
46 |
+
->getModule_License()
|
47 |
+
->getWpHashesTokenManager()
|
48 |
+
->getToken();
|
49 |
+
if ( !empty( $apiToken ) ) {
|
50 |
+
$aChecks = $opts->getEmailValidationChecks();
|
51 |
+
$aVerifys = ( new Email( $apiToken ) )->getEmailVerification( $email );
|
52 |
if ( is_array( $aVerifys ) ) {
|
53 |
foreach ( $aVerifys as $sVerifyKey => $bIsValid ) {
|
54 |
if ( !$bIsValid && in_array( $sVerifyKey, $aChecks ) ) {
|
61 |
}
|
62 |
|
63 |
if ( !empty( $sInvalidBecause ) ) {
|
64 |
+
$sOpt = $opts->getValidateEmailOnRegistration();
|
65 |
$this->getCon()->fireEvent(
|
66 |
'reg_email_invalid',
|
67 |
[
|
68 |
'audit' => [
|
69 |
+
'email' => sanitize_email( $email ),
|
70 |
'reason' => sanitize_key( $sInvalidBecause ),
|
71 |
],
|
72 |
'offense_count' => $sOpt == 'log' ? 0 : 1,
|
src/lib/src/Modules/UserManagement/Lib/Session/UserSessionHandler.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\UserManagement\Lib\Session;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Logic\
|
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;
|
@@ -12,10 +12,10 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
12 |
class UserSessionHandler {
|
13 |
|
14 |
use ModConsumer;
|
15 |
-
use
|
16 |
use WpLoginCapture;
|
17 |
|
18 |
-
protected function canRun() {
|
19 |
return $this->getCon()
|
20 |
->getModule_Sessions()
|
21 |
->getDbHandler_Sessions()
|
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;
|
12 |
class UserSessionHandler {
|
13 |
|
14 |
use ModConsumer;
|
15 |
+
use ExecOnce;
|
16 |
use WpLoginCapture;
|
17 |
|
18 |
+
protected function canRun() :bool {
|
19 |
return $this->getCon()
|
20 |
->getModule_Sessions()
|
21 |
->getDbHandler_Sessions()
|
src/lib/src/Modules/UserManagement/Lib/Suspend/UserSuspendController.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\UserManagement\Lib\Suspend;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Logic\
|
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;
|
@@ -11,9 +11,9 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
11 |
class UserSuspendController {
|
12 |
|
13 |
use ModConsumer;
|
14 |
-
use
|
15 |
|
16 |
-
protected function canRun() {
|
17 |
/** @var UserManagement\Options $opts */
|
18 |
$opts = $this->getOptions();
|
19 |
return $opts->isSuspendEnabled() && $this->getCon()->isPremiumActive();
|
2 |
|
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;
|
11 |
class UserSuspendController {
|
12 |
|
13 |
use ModConsumer;
|
14 |
+
use ExecOnce;
|
15 |
|
16 |
+
protected function canRun() :bool {
|
17 |
/** @var UserManagement\Options $opts */
|
18 |
$opts = $this->getOptions();
|
19 |
return $opts->isSuspendEnabled() && $this->getCon()->isPremiumActive();
|
src/lib/src/Scans/Apc/ResultItem.php
CHANGED
@@ -1,16 +1,14 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Apc;
|
4 |
|
5 |
-
use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base;
|
6 |
-
|
7 |
/**
|
8 |
* Class ResultItem
|
9 |
-
* @property string slug
|
10 |
-
* @property string context
|
11 |
-
* @property int last_updated_at
|
12 |
* @package FernleafSystems\Wordpress\Plugin\Shield\Scans\Apc
|
|
|
|
|
|
|
13 |
*/
|
14 |
-
class ResultItem extends Base\BaseResultItem {
|
15 |
|
16 |
}
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Apc;
|
4 |
|
|
|
|
|
5 |
/**
|
6 |
* Class ResultItem
|
|
|
|
|
|
|
7 |
* @package FernleafSystems\Wordpress\Plugin\Shield\Scans\Apc
|
8 |
+
* @property string $slug
|
9 |
+
* @property string $context
|
10 |
+
* @property int $last_updated_at
|
11 |
*/
|
12 |
+
class ResultItem extends \FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\BaseResultItem {
|
13 |
|
14 |
}
|
src/lib/src/Scans/Apc/Scan.php
CHANGED
@@ -22,7 +22,7 @@ class Scan extends Shield\Scans\Base\BaseScan {
|
|
22 |
$aNewItems = [];
|
23 |
if ( $oTempRs->hasItems() ) {
|
24 |
foreach ( $oTempRs->getAllItems() as $oItem ) {
|
25 |
-
$aNewItems[] = $oItem->
|
26 |
}
|
27 |
}
|
28 |
$oAction->results = $aNewItems;
|
22 |
$aNewItems = [];
|
23 |
if ( $oTempRs->hasItems() ) {
|
24 |
foreach ( $oTempRs->getAllItems() as $oItem ) {
|
25 |
+
$aNewItems[] = $oItem->getRawData();
|
26 |
}
|
27 |
}
|
28 |
$oAction->results = $aNewItems;
|
src/lib/src/Scans/Apc/ScanActionVO.php
CHANGED
@@ -1,15 +1,13 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Apc;
|
4 |
|
5 |
-
use FernleafSystems\Wordpress\Plugin\Shield;
|
6 |
-
|
7 |
/**
|
8 |
* Class ScanActionVO
|
9 |
* @package FernleafSystems\Wordpress\Plugin\Shield\Scans\Apc
|
10 |
* @property int $abandoned_limit
|
11 |
*/
|
12 |
-
class ScanActionVO extends Shield\Scans\Base\BaseScanActionVO {
|
13 |
|
14 |
const QUEUE_GROUP_SIZE_LIMIT = 3;
|
15 |
}
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Apc;
|
4 |
|
|
|
|
|
5 |
/**
|
6 |
* Class ScanActionVO
|
7 |
* @package FernleafSystems\Wordpress\Plugin\Shield\Scans\Apc
|
8 |
* @property int $abandoned_limit
|
9 |
*/
|
10 |
+
class ScanActionVO extends \FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\BaseScanActionVO {
|
11 |
|
12 |
const QUEUE_GROUP_SIZE_LIMIT = 3;
|
13 |
}
|
src/lib/src/Scans/Base/BaseMergeItems.php
CHANGED
@@ -15,7 +15,7 @@ class BaseMergeItems {
|
|
15 |
* @return BaseResultItem
|
16 |
*/
|
17 |
public function mergeItemTo( $oBaseItem, $oMergeItem ) {
|
18 |
-
foreach ( $oMergeItem->
|
19 |
$oBaseItem->{$sKey} = $mVal;
|
20 |
}
|
21 |
return $oBaseItem;
|
15 |
* @return BaseResultItem
|
16 |
*/
|
17 |
public function mergeItemTo( $oBaseItem, $oMergeItem ) {
|
18 |
+
foreach ( $oMergeItem->getRawData() as $sKey => $mVal ) {
|
19 |
$oBaseItem->{$sKey} = $mVal;
|
20 |
}
|
21 |
return $oBaseItem;
|
src/lib/src/Scans/Base/BaseResultItem.php
CHANGED
@@ -1,8 +1,8 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Base;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Data\Adapter\
|
6 |
|
7 |
/**
|
8 |
* Class BaseResultItem
|
@@ -14,26 +14,20 @@ use FernleafSystems\Utilities\Data\Adapter\StdClassAdapter;
|
|
14 |
*/
|
15 |
class BaseResultItem {
|
16 |
|
17 |
-
use
|
18 |
|
19 |
-
|
20 |
-
* @return bool
|
21 |
-
*/
|
22 |
-
public function isReady() {
|
23 |
return false;
|
24 |
}
|
25 |
|
26 |
-
|
27 |
-
|
28 |
-
*/
|
29 |
-
public function generateHash() {
|
30 |
-
return md5( json_encode( $this->getRawDataAsArray() ) );
|
31 |
}
|
32 |
|
33 |
/**
|
34 |
* @return mixed
|
35 |
*/
|
36 |
public function getData() {
|
37 |
-
return
|
38 |
}
|
39 |
}
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Base;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Data\Adapter\DynProperties;
|
6 |
|
7 |
/**
|
8 |
* Class BaseResultItem
|
14 |
*/
|
15 |
class BaseResultItem {
|
16 |
|
17 |
+
use DynProperties;
|
18 |
|
19 |
+
public function isReady() :bool {
|
|
|
|
|
|
|
20 |
return false;
|
21 |
}
|
22 |
|
23 |
+
public function generateHash() :string {
|
24 |
+
return md5( json_encode( $this->getRawData() ) );
|
|
|
|
|
|
|
25 |
}
|
26 |
|
27 |
/**
|
28 |
* @return mixed
|
29 |
*/
|
30 |
public function getData() {
|
31 |
+
return $this->data ?? $this->getRawData();
|
32 |
}
|
33 |
}
|
src/lib/src/Scans/Base/BaseScanActionVO.php
CHANGED
@@ -1,8 +1,8 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Base;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Data\Adapter\
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\Table\BaseEntryFormatter;
|
7 |
|
8 |
/**
|
@@ -20,7 +20,7 @@ use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\Table\BaseEntryFormatter;
|
|
20 |
*/
|
21 |
abstract class BaseScanActionVO {
|
22 |
|
23 |
-
use
|
24 |
|
25 |
const QUEUE_GROUP_SIZE_LIMIT = 1;
|
26 |
const DEFAULT_SLEEP_SECONDS = 0;
|
@@ -29,32 +29,29 @@ abstract class BaseScanActionVO {
|
|
29 |
* @return BaseResultItem|mixed
|
30 |
*/
|
31 |
public function getNewResultItem() {
|
32 |
-
$
|
33 |
-
return new $
|
34 |
}
|
35 |
|
36 |
/**
|
37 |
* @return BaseResultsSet|mixed
|
38 |
*/
|
39 |
public function getNewResultsSet() {
|
40 |
-
$
|
41 |
-
return new $
|
42 |
}
|
43 |
|
44 |
/**
|
45 |
* @return BaseEntryFormatter|mixed
|
46 |
*/
|
47 |
public function getTableEntryFormatter() {
|
48 |
-
$
|
49 |
-
/** @var BaseEntryFormatter $
|
50 |
-
$
|
51 |
-
return $
|
52 |
}
|
53 |
|
54 |
-
|
55 |
-
* @return string
|
56 |
-
*/
|
57 |
-
public function getScanNamespace() {
|
58 |
try {
|
59 |
$namespace = ( new \ReflectionClass( $this ) )->getNamespaceName();
|
60 |
}
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Base;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Data\Adapter\DynProperties;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\Table\BaseEntryFormatter;
|
7 |
|
8 |
/**
|
20 |
*/
|
21 |
abstract class BaseScanActionVO {
|
22 |
|
23 |
+
use DynProperties;
|
24 |
|
25 |
const QUEUE_GROUP_SIZE_LIMIT = 1;
|
26 |
const DEFAULT_SLEEP_SECONDS = 0;
|
29 |
* @return BaseResultItem|mixed
|
30 |
*/
|
31 |
public function getNewResultItem() {
|
32 |
+
$class = $this->getScanNamespace().'ResultItem';
|
33 |
+
return new $class();
|
34 |
}
|
35 |
|
36 |
/**
|
37 |
* @return BaseResultsSet|mixed
|
38 |
*/
|
39 |
public function getNewResultsSet() {
|
40 |
+
$class = $this->getScanNamespace().'ResultsSet';
|
41 |
+
return new $class();
|
42 |
}
|
43 |
|
44 |
/**
|
45 |
* @return BaseEntryFormatter|mixed
|
46 |
*/
|
47 |
public function getTableEntryFormatter() {
|
48 |
+
$class = $this->getScanNamespace().'Table\\EntryFormatter';
|
49 |
+
/** @var BaseEntryFormatter $formatter */
|
50 |
+
$formatter = new $class();
|
51 |
+
return $formatter->setScanActionVO( $this );
|
52 |
}
|
53 |
|
54 |
+
public function getScanNamespace() :string {
|
|
|
|
|
|
|
55 |
try {
|
56 |
$namespace = ( new \ReflectionClass( $this ) )->getNamespaceName();
|
57 |
}
|
src/lib/src/Scans/Base/Files/BaseFileMapScan.php
CHANGED
@@ -24,7 +24,7 @@ abstract class BaseFileMapScan extends Base\BaseScan {
|
|
24 |
$newItems = [];
|
25 |
if ( $oTempRs->hasItems() ) {
|
26 |
foreach ( $oTempRs->getAllItems() as $oItem ) {
|
27 |
-
$newItems[] = $oItem->
|
28 |
}
|
29 |
}
|
30 |
$action->results = $newItems;
|
24 |
$newItems = [];
|
25 |
if ( $oTempRs->hasItems() ) {
|
26 |
foreach ( $oTempRs->getAllItems() as $oItem ) {
|
27 |
+
$newItems[] = $oItem->getRawData();
|
28 |
}
|
29 |
}
|
30 |
$action->results = $newItems;
|
src/lib/src/Scans/Base/Table/BaseEntryFormatter.php
CHANGED
@@ -61,7 +61,7 @@ abstract class BaseEntryFormatter {
|
|
61 |
* @return array
|
62 |
*/
|
63 |
protected function getBaseData() {
|
64 |
-
return $this->getEntryVO()->
|
65 |
}
|
66 |
|
67 |
/**
|
61 |
* @return array
|
62 |
*/
|
63 |
protected function getBaseData() {
|
64 |
+
return $this->getEntryVO()->getRawData();
|
65 |
}
|
66 |
|
67 |
/**
|
src/lib/src/Scans/Base/Utilities/ItemActionHandler.php
CHANGED
@@ -63,9 +63,9 @@ abstract class ItemActionHandler {
|
|
63 |
|
64 |
/** @var HackGuard\ModCon $mod */
|
65 |
$mod = $this->getMod();
|
66 |
-
/** @var Scanner\Update $
|
67 |
-
$
|
68 |
-
if ( !$
|
69 |
throw new \Exception( 'Item could not be ignored at this time.' );
|
70 |
}
|
71 |
|
63 |
|
64 |
/** @var HackGuard\ModCon $mod */
|
65 |
$mod = $this->getMod();
|
66 |
+
/** @var Scanner\Update $updater */
|
67 |
+
$updater = $mod->getDbHandler_ScanResults()->getQueryUpdater();
|
68 |
+
if ( !$updater->setIgnored( $oEntry ) ) {
|
69 |
throw new \Exception( 'Item could not be ignored at this time.' );
|
70 |
}
|
71 |
|
src/lib/src/Scans/Mal/ResultItem.php
CHANGED
@@ -1,32 +1,24 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Mal;
|
4 |
|
5 |
-
use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base;
|
6 |
-
|
7 |
/**
|
8 |
* Class ResultItem
|
|
|
9 |
* @property string $path_full
|
10 |
* @property string $path_fragment - relative to ABSPATH
|
11 |
* @property bool $is_mal
|
12 |
* @property string $mal_sig
|
13 |
* @property int[] $file_lines
|
14 |
* @property int $fp_confidence - false positive confidence level
|
15 |
-
* @package FernleafSystems\Wordpress\Plugin\Shield\Scans\Mal
|
16 |
*/
|
17 |
-
class ResultItem extends Base\BaseResultItem {
|
18 |
|
19 |
-
|
20 |
-
* @return string
|
21 |
-
*/
|
22 |
-
public function generateHash() {
|
23 |
return md5( $this->path_full );
|
24 |
}
|
25 |
|
26 |
-
|
27 |
-
* @return bool
|
28 |
-
*/
|
29 |
-
public function isReady() {
|
30 |
return !empty( $this->path_full ) && !empty( $this->md5_file_wp ) && !empty( $this->path_fragment );
|
31 |
}
|
32 |
}
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Mal;
|
4 |
|
|
|
|
|
5 |
/**
|
6 |
* Class ResultItem
|
7 |
+
* @package FernleafSystems\Wordpress\Plugin\Shield\Scans\Mal
|
8 |
* @property string $path_full
|
9 |
* @property string $path_fragment - relative to ABSPATH
|
10 |
* @property bool $is_mal
|
11 |
* @property string $mal_sig
|
12 |
* @property int[] $file_lines
|
13 |
* @property int $fp_confidence - false positive confidence level
|
|
|
14 |
*/
|
15 |
+
class ResultItem extends \FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\BaseResultItem {
|
16 |
|
17 |
+
public function generateHash() :string {
|
|
|
|
|
|
|
18 |
return md5( $this->path_full );
|
19 |
}
|
20 |
|
21 |
+
public function isReady() :bool {
|
|
|
|
|
|
|
22 |
return !empty( $this->path_full ) && !empty( $this->md5_file_wp ) && !empty( $this->path_fragment );
|
23 |
}
|
24 |
}
|
src/lib/src/Scans/Mal/ScanActionVO.php
CHANGED
@@ -2,8 +2,6 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Mal;
|
4 |
|
5 |
-
use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\BaseScanActionVO;
|
6 |
-
|
7 |
/**
|
8 |
* Class ScanActionVO
|
9 |
* @package FernleafSystems\Wordpress\Plugin\Shield\Scans\Mal
|
@@ -15,7 +13,7 @@ use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\BaseScanActionVO;
|
|
15 |
* @property string[] $patterns_simple
|
16 |
* @property int $confidence_threshold
|
17 |
*/
|
18 |
-
class ScanActionVO extends BaseScanActionVO {
|
19 |
|
20 |
const QUEUE_GROUP_SIZE_LIMIT = 50;
|
21 |
const DEFAULT_SLEEP_SECONDS = 1;
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Mal;
|
4 |
|
|
|
|
|
5 |
/**
|
6 |
* Class ScanActionVO
|
7 |
* @package FernleafSystems\Wordpress\Plugin\Shield\Scans\Mal
|
13 |
* @property string[] $patterns_simple
|
14 |
* @property int $confidence_threshold
|
15 |
*/
|
16 |
+
class ScanActionVO extends \FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\BaseScanActionVO {
|
17 |
|
18 |
const QUEUE_GROUP_SIZE_LIMIT = 50;
|
19 |
const DEFAULT_SLEEP_SECONDS = 1;
|
src/lib/src/Scans/Ptg/ResultItem.php
CHANGED
@@ -1,9 +1,7 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Ptg;
|
4 |
|
5 |
-
use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base;
|
6 |
-
|
7 |
/**
|
8 |
* Class ResultItem
|
9 |
* @package FernleafSystems\Wordpress\Plugin\Shield\Scans\Ptg
|
@@ -15,12 +13,9 @@ use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base;
|
|
15 |
* @property string $is_different
|
16 |
* @property string $is_missing
|
17 |
*/
|
18 |
-
class ResultItem extends Base\BaseResultItem {
|
19 |
|
20 |
-
|
21 |
-
* @return string
|
22 |
-
*/
|
23 |
-
public function generateHash() {
|
24 |
return md5( $this->path_full );
|
25 |
}
|
26 |
}
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Ptg;
|
4 |
|
|
|
|
|
5 |
/**
|
6 |
* Class ResultItem
|
7 |
* @package FernleafSystems\Wordpress\Plugin\Shield\Scans\Ptg
|
13 |
* @property string $is_different
|
14 |
* @property string $is_missing
|
15 |
*/
|
16 |
+
class ResultItem extends \FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\BaseResultItem {
|
17 |
|
18 |
+
public function generateHash() :string {
|
|
|
|
|
|
|
19 |
return md5( $this->path_full );
|
20 |
}
|
21 |
}
|
src/lib/src/Scans/Ptg/ScanActionVO.php
CHANGED
@@ -1,16 +1,14 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Ptg;
|
4 |
|
5 |
-
use FernleafSystems\Wordpress\Plugin\Shield;
|
6 |
-
|
7 |
/**
|
8 |
* Class ScanActionVO
|
9 |
* @package FernleafSystems\Wordpress\Plugin\Shield\Scans\Ptg
|
10 |
* @property string[] $scan_root_dirs
|
11 |
* @property string[] $file_exts
|
12 |
*/
|
13 |
-
class ScanActionVO extends Shield\Scans\Base\BaseScanActionVO {
|
14 |
|
15 |
const CONTEXT_PLUGINS = 'plugins';
|
16 |
const CONTEXT_THEMES = 'themes';
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Ptg;
|
4 |
|
|
|
|
|
5 |
/**
|
6 |
* Class ScanActionVO
|
7 |
* @package FernleafSystems\Wordpress\Plugin\Shield\Scans\Ptg
|
8 |
* @property string[] $scan_root_dirs
|
9 |
* @property string[] $file_exts
|
10 |
*/
|
11 |
+
class ScanActionVO extends \FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\BaseScanActionVO {
|
12 |
|
13 |
const CONTEXT_PLUGINS = 'plugins';
|
14 |
const CONTEXT_THEMES = 'themes';
|
src/lib/src/Scans/Ufc/ResultItem.php
CHANGED
@@ -1,21 +1,16 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Ufc;
|
4 |
|
5 |
-
use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base;
|
6 |
-
|
7 |
/**
|
8 |
* Class ResultItem
|
9 |
-
* @property string path_full
|
10 |
-
* @property string path_fragment
|
11 |
* @package FernleafSystems\Wordpress\Plugin\Shield\Scans\Ufc
|
|
|
|
|
12 |
*/
|
13 |
-
class ResultItem extends Base\BaseResultItem {
|
14 |
|
15 |
-
|
16 |
-
* @return string
|
17 |
-
*/
|
18 |
-
public function generateHash() {
|
19 |
return md5( $this->path_full );
|
20 |
}
|
21 |
}
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Ufc;
|
4 |
|
|
|
|
|
5 |
/**
|
6 |
* Class ResultItem
|
|
|
|
|
7 |
* @package FernleafSystems\Wordpress\Plugin\Shield\Scans\Ufc
|
8 |
+
* @property string $path_full
|
9 |
+
* @property string $path_fragment
|
10 |
*/
|
11 |
+
class ResultItem extends \FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\BaseResultItem {
|
12 |
|
13 |
+
public function generateHash() :string {
|
|
|
|
|
|
|
14 |
return md5( $this->path_full );
|
15 |
}
|
16 |
}
|
src/lib/src/Scans/Ufc/ScanActionVO.php
CHANGED
@@ -1,16 +1,14 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Ufc;
|
4 |
|
5 |
-
use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\BaseScanActionVO;
|
6 |
-
|
7 |
/**
|
8 |
* Class ScanActionVO
|
9 |
* @package FernleafSystems\Wordpress\Plugin\Shield\Scans\Ufc
|
10 |
* @property string[] $scan_dirs
|
11 |
* @property string[] $exclusions
|
12 |
*/
|
13 |
-
class ScanActionVO extends BaseScanActionVO {
|
14 |
|
15 |
const QUEUE_GROUP_SIZE_LIMIT = 100;
|
16 |
}
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Ufc;
|
4 |
|
|
|
|
|
5 |
/**
|
6 |
* Class ScanActionVO
|
7 |
* @package FernleafSystems\Wordpress\Plugin\Shield\Scans\Ufc
|
8 |
* @property string[] $scan_dirs
|
9 |
* @property string[] $exclusions
|
10 |
*/
|
11 |
+
class ScanActionVO extends \FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\BaseScanActionVO {
|
12 |
|
13 |
const QUEUE_GROUP_SIZE_LIMIT = 100;
|
14 |
}
|
src/lib/src/Scans/Wcf/ResultItem.php
CHANGED
@@ -1,31 +1,23 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Wcf;
|
4 |
|
5 |
-
use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base;
|
6 |
-
|
7 |
/**
|
8 |
* Class ResultItem
|
9 |
-
* @property string path_full
|
10 |
-
* @property string path_fragment
|
11 |
-
* @property string md5_file_wp
|
12 |
-
* @property bool is_checksumfail
|
13 |
-
* @property bool is_missing
|
14 |
* @package FernleafSystems\Wordpress\Plugin\Shield\Scans\Wcf
|
|
|
|
|
|
|
|
|
|
|
15 |
*/
|
16 |
-
class ResultItem extends Base\BaseResultItem {
|
17 |
|
18 |
-
|
19 |
-
* @return string
|
20 |
-
*/
|
21 |
-
public function generateHash() {
|
22 |
return md5( $this->path_full );
|
23 |
}
|
24 |
|
25 |
-
|
26 |
-
* @return bool
|
27 |
-
*/
|
28 |
-
public function isReady() {
|
29 |
return !empty( $this->path_full ) && !empty( $this->md5_file_wp ) && !empty( $this->path_fragment );
|
30 |
}
|
31 |
}
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Wcf;
|
4 |
|
|
|
|
|
5 |
/**
|
6 |
* Class ResultItem
|
|
|
|
|
|
|
|
|
|
|
7 |
* @package FernleafSystems\Wordpress\Plugin\Shield\Scans\Wcf
|
8 |
+
* @property string $path_full
|
9 |
+
* @property string $path_fragment
|
10 |
+
* @property string $md5_file_wp
|
11 |
+
* @property bool $is_checksumfail
|
12 |
+
* @property bool $is_missing
|
13 |
*/
|
14 |
+
class ResultItem extends \FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\BaseResultItem {
|
15 |
|
16 |
+
public function generateHash() :string {
|
|
|
|
|
|
|
17 |
return md5( $this->path_full );
|
18 |
}
|
19 |
|
20 |
+
public function isReady() :bool {
|
|
|
|
|
|
|
21 |
return !empty( $this->path_full ) && !empty( $this->md5_file_wp ) && !empty( $this->path_fragment );
|
22 |
}
|
23 |
}
|
src/lib/src/Scans/Wcf/ScanActionVO.php
CHANGED
@@ -1,16 +1,14 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Wcf;
|
4 |
|
5 |
-
use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\BaseScanActionVO;
|
6 |
-
|
7 |
/**
|
8 |
* Class ScanActionVO
|
9 |
* @package FernleafSystems\Wordpress\Plugin\Shield\Scans\Wcf
|
10 |
* @property string $exclusions_missing_regex
|
11 |
* @property string $exclusions_files_regex
|
12 |
*/
|
13 |
-
class ScanActionVO extends BaseScanActionVO {
|
14 |
|
15 |
const QUEUE_GROUP_SIZE_LIMIT = 100;
|
16 |
}
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Wcf;
|
4 |
|
|
|
|
|
5 |
/**
|
6 |
* Class ScanActionVO
|
7 |
* @package FernleafSystems\Wordpress\Plugin\Shield\Scans\Wcf
|
8 |
* @property string $exclusions_missing_regex
|
9 |
* @property string $exclusions_files_regex
|
10 |
*/
|
11 |
+
class ScanActionVO extends \FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\BaseScanActionVO {
|
12 |
|
13 |
const QUEUE_GROUP_SIZE_LIMIT = 100;
|
14 |
}
|
src/lib/src/Scans/Wpv/ResultItem.php
CHANGED
@@ -1,31 +1,24 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Wpv;
|
4 |
|
5 |
-
use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Scans\Wpv\WpVulnDb\WpVulnVO;
|
7 |
|
8 |
/**
|
9 |
* Class ResultItem
|
10 |
-
* @property string slug
|
11 |
-
* @property string context
|
12 |
-
* @property int wpvuln_id
|
13 |
-
* @property array wpvuln_vo
|
14 |
* @package FernleafSystems\Wordpress\Plugin\Shield\Scans\Wpv
|
|
|
|
|
|
|
|
|
15 |
*/
|
16 |
-
class ResultItem extends Base\BaseResultItem {
|
17 |
|
18 |
-
|
19 |
-
* @return string
|
20 |
-
*/
|
21 |
-
public function generateHash() {
|
22 |
return md5( $this->slug.$this->wpvuln_id );
|
23 |
}
|
24 |
|
25 |
-
|
26 |
-
* @return WpVulnVO
|
27 |
-
*/
|
28 |
-
public function getWpVulnVo() {
|
29 |
return ( new WpVulnVO() )->applyFromArray( $this->wpvuln_vo );
|
30 |
}
|
31 |
}
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Wpv;
|
4 |
|
|
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Scans\Wpv\WpVulnDb\WpVulnVO;
|
6 |
|
7 |
/**
|
8 |
* Class ResultItem
|
|
|
|
|
|
|
|
|
9 |
* @package FernleafSystems\Wordpress\Plugin\Shield\Scans\Wpv
|
10 |
+
* @property string $slug
|
11 |
+
* @property string $context
|
12 |
+
* @property int $wpvuln_id
|
13 |
+
* @property array $wpvuln_vo
|
14 |
*/
|
15 |
+
class ResultItem extends \FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\BaseResultItem {
|
16 |
|
17 |
+
public function generateHash() :string {
|
|
|
|
|
|
|
18 |
return md5( $this->slug.$this->wpvuln_id );
|
19 |
}
|
20 |
|
21 |
+
public function getWpVulnVo() :WpVulnVO {
|
|
|
|
|
|
|
22 |
return ( new WpVulnVO() )->applyFromArray( $this->wpvuln_vo );
|
23 |
}
|
24 |
}
|
src/lib/src/Scans/Wpv/Scan.php
CHANGED
@@ -23,8 +23,8 @@ class Scan extends Shield\Scans\Base\BaseScan {
|
|
23 |
|
24 |
$aNewItems = [];
|
25 |
if ( $oTempRs->hasItems() ) {
|
26 |
-
foreach ( $oTempRs->getAllItems() as $
|
27 |
-
$aNewItems[] = $
|
28 |
}
|
29 |
}
|
30 |
$oAction->results = $aNewItems;
|
@@ -73,7 +73,7 @@ class Scan extends Shield\Scans\Base\BaseScan {
|
|
73 |
$oItem->slug = $sFile;
|
74 |
$oItem->context = $sContext;
|
75 |
$oItem->wpvuln_id = $oVo->id;
|
76 |
-
$oItem->wpvuln_vo = $oVo->
|
77 |
$oResultsSet->addItem( $oItem );
|
78 |
}
|
79 |
|
23 |
|
24 |
$aNewItems = [];
|
25 |
if ( $oTempRs->hasItems() ) {
|
26 |
+
foreach ( $oTempRs->getAllItems() as $item ) {
|
27 |
+
$aNewItems[] = $item->getRawData();
|
28 |
}
|
29 |
}
|
30 |
$oAction->results = $aNewItems;
|
73 |
$oItem->slug = $sFile;
|
74 |
$oItem->context = $sContext;
|
75 |
$oItem->wpvuln_id = $oVo->id;
|
76 |
+
$oItem->wpvuln_vo = $oVo->getRawData();
|
77 |
$oResultsSet->addItem( $oItem );
|
78 |
}
|
79 |
|
src/lib/src/Scans/Wpv/ScanActionVO.php
CHANGED
@@ -1,13 +1,11 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Wpv;
|
4 |
|
5 |
-
use FernleafSystems\Wordpress\Plugin\Shield;
|
6 |
-
|
7 |
/**
|
8 |
* Class ScanActionVO
|
9 |
* @package FernleafSystems\Wordpress\Plugin\Shield\Scans\Wpv
|
10 |
*/
|
11 |
-
class ScanActionVO extends Shield\Scans\Base\BaseScanActionVO {
|
12 |
|
13 |
}
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Wpv;
|
4 |
|
|
|
|
|
5 |
/**
|
6 |
* Class ScanActionVO
|
7 |
* @package FernleafSystems\Wordpress\Plugin\Shield\Scans\Wpv
|
8 |
*/
|
9 |
+
class ScanActionVO extends \FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\BaseScanActionVO {
|
10 |
|
11 |
}
|
src/lib/src/Scans/Wpv/WpVulnDb/WpVulnVO.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Wpv\WpVulnDb;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Data\Adapter\
|
6 |
|
7 |
/**
|
8 |
* Class WpVulnVO
|
@@ -17,7 +17,7 @@ use FernleafSystems\Utilities\Data\Adapter\DynamicPropertiesClass;
|
|
17 |
* @property int $created_at
|
18 |
* @property int $published_date
|
19 |
*/
|
20 |
-
class WpVulnVO extends
|
21 |
|
22 |
const URL_BASE = 'https://wpscan.com/vulnerability/%s';
|
23 |
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Scans\Wpv\WpVulnDb;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
|
6 |
|
7 |
/**
|
8 |
* Class WpVulnVO
|
17 |
* @property int $created_at
|
18 |
* @property int $published_date
|
19 |
*/
|
20 |
+
class WpVulnVO extends DynPropertiesClass {
|
21 |
|
22 |
const URL_BASE = 'https://wpscan.com/vulnerability/%s';
|
23 |
|
src/lib/src/ShieldNetApi/Common/BaseApi.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\ShieldNetApi\Common;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Data\Adapter\
|
6 |
use FernleafSystems\Wordpress\Services\Services;
|
7 |
use FernleafSystems\Wordpress\Services\Utilities\HttpRequest;
|
8 |
|
@@ -16,11 +16,8 @@ use FernleafSystems\Wordpress\Services\Utilities\HttpRequest;
|
|
16 |
* @property array $params_body
|
17 |
* @property array $params_query
|
18 |
*/
|
19 |
-
abstract class BaseApi {
|
20 |
|
21 |
-
use StdClassAdapter {
|
22 |
-
__get as __adapterGet;
|
23 |
-
}
|
24 |
const DEFAULT_URL_STUB = '';
|
25 |
const API_ACTION = '';
|
26 |
|
@@ -75,36 +72,36 @@ abstract class BaseApi {
|
|
75 |
}
|
76 |
|
77 |
/**
|
78 |
-
* @param string $
|
79 |
* @return mixed
|
80 |
*/
|
81 |
-
public function __get( $
|
82 |
|
83 |
-
$
|
84 |
|
85 |
-
switch ( $
|
86 |
|
87 |
case 'params_query':
|
88 |
case 'params_body':
|
89 |
-
if ( !is_array( $
|
90 |
-
$
|
91 |
}
|
92 |
break;
|
93 |
|
94 |
case 'request_method':
|
95 |
-
$
|
96 |
break;
|
97 |
|
98 |
case 'lookup_url_stub':
|
99 |
-
if ( empty( $
|
100 |
-
$
|
101 |
}
|
102 |
-
$
|
103 |
break;
|
104 |
|
105 |
case 'timeout':
|
106 |
-
if ( empty( $
|
107 |
-
$
|
108 |
}
|
109 |
break;
|
110 |
|
@@ -112,6 +109,6 @@ abstract class BaseApi {
|
|
112 |
break;
|
113 |
}
|
114 |
|
115 |
-
return $
|
116 |
}
|
117 |
}
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\ShieldNetApi\Common;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
|
6 |
use FernleafSystems\Wordpress\Services\Services;
|
7 |
use FernleafSystems\Wordpress\Services\Utilities\HttpRequest;
|
8 |
|
16 |
* @property array $params_body
|
17 |
* @property array $params_query
|
18 |
*/
|
19 |
+
abstract class BaseApi extends DynPropertiesClass {
|
20 |
|
|
|
|
|
|
|
21 |
const DEFAULT_URL_STUB = '';
|
22 |
const API_ACTION = '';
|
23 |
|
72 |
}
|
73 |
|
74 |
/**
|
75 |
+
* @param string $key
|
76 |
* @return mixed
|
77 |
*/
|
78 |
+
public function __get( string $key ) {
|
79 |
|
80 |
+
$value = parent::__get( $key );
|
81 |
|
82 |
+
switch ( $key ) {
|
83 |
|
84 |
case 'params_query':
|
85 |
case 'params_body':
|
86 |
+
if ( !is_array( $value ) ) {
|
87 |
+
$value = [];
|
88 |
}
|
89 |
break;
|
90 |
|
91 |
case 'request_method':
|
92 |
+
$value = empty( $value ) ? 'get' : strtolower( $value );
|
93 |
break;
|
94 |
|
95 |
case 'lookup_url_stub':
|
96 |
+
if ( empty( $value ) ) {
|
97 |
+
$value = static::DEFAULT_URL_STUB;
|
98 |
}
|
99 |
+
$value = rtrim( $value, '/' );
|
100 |
break;
|
101 |
|
102 |
case 'timeout':
|
103 |
+
if ( empty( $value ) || !is_numeric( $value ) ) {
|
104 |
+
$value = 60;
|
105 |
}
|
106 |
break;
|
107 |
|
109 |
break;
|
110 |
}
|
111 |
|
112 |
+
return $value;
|
113 |
}
|
114 |
}
|
src/lib/src/ShieldNetApi/Common/BaseShieldNetApi.php
CHANGED
@@ -17,31 +17,31 @@ class BaseShieldNetApi extends BaseApi {
|
|
17 |
const DEFAULT_URL_STUB = 'https://net.getshieldsecurity.com/wp-json/apto-snapi/v1';
|
18 |
|
19 |
/**
|
20 |
-
* @param string $
|
21 |
* @return mixed
|
22 |
*/
|
23 |
-
public function __get( $
|
24 |
|
25 |
-
$
|
26 |
|
27 |
-
switch ( $
|
28 |
|
29 |
case 'params_query':
|
30 |
if ( $this->request_method == 'get' ) {
|
31 |
-
$
|
32 |
}
|
33 |
break;
|
34 |
|
35 |
case 'params_body':
|
36 |
if ( $this->request_method == 'post' ) {
|
37 |
-
$
|
38 |
}
|
39 |
break;
|
40 |
|
41 |
case 'shield_net_params':
|
42 |
-
if ( !is_array( $
|
43 |
-
$
|
44 |
-
$this->shield_net_params = $
|
45 |
}
|
46 |
break;
|
47 |
|
@@ -49,7 +49,7 @@ class BaseShieldNetApi extends BaseApi {
|
|
49 |
break;
|
50 |
}
|
51 |
|
52 |
-
return $
|
53 |
}
|
54 |
|
55 |
/**
|
17 |
const DEFAULT_URL_STUB = 'https://net.getshieldsecurity.com/wp-json/apto-snapi/v1';
|
18 |
|
19 |
/**
|
20 |
+
* @param string $key
|
21 |
* @return mixed
|
22 |
*/
|
23 |
+
public function __get( string $key ) {
|
24 |
|
25 |
+
$value = parent::__get( $key );
|
26 |
|
27 |
+
switch ( $key ) {
|
28 |
|
29 |
case 'params_query':
|
30 |
if ( $this->request_method == 'get' ) {
|
31 |
+
$value = array_merge( $this->shield_net_params, $value );
|
32 |
}
|
33 |
break;
|
34 |
|
35 |
case 'params_body':
|
36 |
if ( $this->request_method == 'post' ) {
|
37 |
+
$value = array_merge( $this->shield_net_params, $value );
|
38 |
}
|
39 |
break;
|
40 |
|
41 |
case 'shield_net_params':
|
42 |
+
if ( !is_array( $value ) ) {
|
43 |
+
$value = $this->getShieldNetApiParams();
|
44 |
+
$this->shield_net_params = $value;
|
45 |
}
|
46 |
break;
|
47 |
|
49 |
break;
|
50 |
}
|
51 |
|
52 |
+
return $value;
|
53 |
}
|
54 |
|
55 |
/**
|
src/lib/src/ShieldNetApi/FileLocker/DecryptFile.php
CHANGED
@@ -8,7 +8,6 @@ use FernleafSystems\Wordpress\Services\Utilities\Encrypt\OpenSslEncryptVo;
|
|
8 |
|
9 |
class DecryptFile extends BaseShieldNetApi {
|
10 |
|
11 |
-
use ModConsumer;
|
12 |
const API_ACTION = 'filelocker/decrypt';
|
13 |
|
14 |
/**
|
@@ -17,7 +16,7 @@ class DecryptFile extends BaseShieldNetApi {
|
|
17 |
* @return string|null
|
18 |
*/
|
19 |
public function retrieve( OpenSslEncryptVo $oOpenSslVO, $nPublicKeyId ) {
|
20 |
-
$
|
21 |
|
22 |
$this->request_method = 'post';
|
23 |
$this->params_body = [
|
@@ -26,10 +25,10 @@ class DecryptFile extends BaseShieldNetApi {
|
|
26 |
'sealed_pass' => $oOpenSslVO->sealed_password,
|
27 |
];
|
28 |
|
29 |
-
$
|
30 |
-
if ( is_array( $
|
31 |
-
$
|
32 |
}
|
33 |
-
return $
|
34 |
}
|
35 |
}
|
8 |
|
9 |
class DecryptFile extends BaseShieldNetApi {
|
10 |
|
|
|
11 |
const API_ACTION = 'filelocker/decrypt';
|
12 |
|
13 |
/**
|
16 |
* @return string|null
|
17 |
*/
|
18 |
public function retrieve( OpenSslEncryptVo $oOpenSslVO, $nPublicKeyId ) {
|
19 |
+
$content = null;
|
20 |
|
21 |
$this->request_method = 'post';
|
22 |
$this->params_body = [
|
25 |
'sealed_pass' => $oOpenSslVO->sealed_password,
|
26 |
];
|
27 |
|
28 |
+
$raw = $this->sendReq();
|
29 |
+
if ( is_array( $raw ) && !empty( $raw[ 'data' ] ) ) {
|
30 |
+
$content = base64_decode( $raw[ 'data' ][ 'opened_data' ] );
|
31 |
}
|
32 |
+
return $content;
|
33 |
}
|
34 |
}
|
src/lib/src/ShieldNetApi/FileLocker/GetPublicKey.php
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\ShieldNetApi\FileLocker;
|
4 |
|
@@ -12,11 +12,11 @@ class GetPublicKey extends BaseShieldNetApi {
|
|
12 |
* @return array|null
|
13 |
*/
|
14 |
public function retrieve() {
|
15 |
-
$
|
16 |
-
$
|
17 |
-
if ( is_array( $
|
18 |
-
$
|
19 |
}
|
20 |
-
return $
|
21 |
}
|
22 |
}
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\ShieldNetApi\FileLocker;
|
4 |
|
12 |
* @return array|null
|
13 |
*/
|
14 |
public function retrieve() {
|
15 |
+
$key = null;
|
16 |
+
$raw = $this->sendReq();
|
17 |
+
if ( is_array( $raw ) && !empty( $raw[ 'data' ][ 'key_id' ] ) ) {
|
18 |
+
$key[ $raw[ 'data' ][ 'key_id' ] ] = $raw[ 'data' ][ 'pub_key' ];
|
19 |
}
|
20 |
+
return $key;
|
21 |
}
|
22 |
}
|
src/lib/src/ShieldNetApi/Handshake/Verify.php
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\ShieldNetApi\Handshake;
|
4 |
|
@@ -8,11 +8,8 @@ class Verify extends Common\BaseShieldNetApi {
|
|
8 |
|
9 |
const API_ACTION = 'handshake/verify';
|
10 |
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
public function run() {
|
15 |
-
$aRaw = $this->sendReq();
|
16 |
-
return is_array( $aRaw ) && !empty( $aRaw[ 'data' ][ 'success' ] );
|
17 |
}
|
18 |
}
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\ShieldNetApi\Handshake;
|
4 |
|
8 |
|
9 |
const API_ACTION = 'handshake/verify';
|
10 |
|
11 |
+
public function run() :bool {
|
12 |
+
$raw = $this->sendReq();
|
13 |
+
return is_array( $raw ) && !empty( $raw[ 'data' ][ 'success' ] );
|
|
|
|
|
|
|
14 |
}
|
15 |
}
|
src/lib/src/ShieldNetApi/HandshakingNonce.php
CHANGED
@@ -9,32 +9,25 @@ class HandshakingNonce {
|
|
9 |
|
10 |
use ModConsumer;
|
11 |
|
12 |
-
|
13 |
-
|
14 |
-
*/
|
15 |
-
public function create() {
|
16 |
-
$aNonces = $this->getNonces();
|
17 |
|
18 |
-
$
|
19 |
-
$
|
20 |
-
$this->storeNonces( $
|
21 |
|
22 |
-
return $
|
23 |
}
|
24 |
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
if ( isset( $aNs[ $sNonce ] ) ) {
|
33 |
-
$bValid = Services::Request()->ts() <= $aNs[ $sNonce ];
|
34 |
-
unset( $aNs[ $sNonce ] );
|
35 |
-
$this->storeNonces( $aNs );
|
36 |
}
|
37 |
-
return $
|
38 |
}
|
39 |
|
40 |
/**
|
@@ -48,20 +41,20 @@ class HandshakingNonce {
|
|
48 |
|
49 |
/**
|
50 |
* Also filters out expired nonces on-save
|
51 |
-
* @param int[] $
|
52 |
* @return $this
|
53 |
*/
|
54 |
-
private function storeNonces( array $
|
55 |
-
$
|
56 |
-
|
57 |
-
|
58 |
-
$
|
59 |
-
$
|
60 |
-
function ( $
|
61 |
-
return $
|
62 |
}
|
63 |
);
|
64 |
-
$
|
65 |
return $this;
|
66 |
}
|
67 |
}
|
9 |
|
10 |
use ModConsumer;
|
11 |
|
12 |
+
public function create() :string {
|
13 |
+
$nonces = $this->getNonces();
|
|
|
|
|
|
|
14 |
|
15 |
+
$pass = wp_generate_password( 12, false );
|
16 |
+
$nonces[ $pass ] = Services::Request()->ts() + 90;
|
17 |
+
$this->storeNonces( $nonces );
|
18 |
|
19 |
+
return $pass;
|
20 |
}
|
21 |
|
22 |
+
public function verify( string $nonce ) :bool {
|
23 |
+
$nonces = $this->getNonces();
|
24 |
+
$valid = false;
|
25 |
+
if ( isset( $nonces[ $nonce ] ) ) {
|
26 |
+
$valid = Services::Request()->ts() <= $nonces[ $nonce ];
|
27 |
+
unset( $nonces[ $nonce ] );
|
28 |
+
$this->storeNonces( $nonces );
|
|
|
|
|
|
|
|
|
29 |
}
|
30 |
+
return $valid;
|
31 |
}
|
32 |
|
33 |
/**
|
41 |
|
42 |
/**
|
43 |
* Also filters out expired nonces on-save
|
44 |
+
* @param int[] $nonces
|
45 |
* @return $this
|
46 |
*/
|
47 |
+
private function storeNonces( array $nonces ) {
|
48 |
+
$snapiCon = $this->getCon()
|
49 |
+
->getModule_Plugin()
|
50 |
+
->getShieldNetApiController();
|
51 |
+
$snapiCon->vo->nonces = array_filter(
|
52 |
+
$nonces,
|
53 |
+
function ( $ts ) {
|
54 |
+
return $ts > Services::Request()->ts();
|
55 |
}
|
56 |
);
|
57 |
+
$snapiCon->storeVoData();
|
58 |
return $this;
|
59 |
}
|
60 |
}
|
src/lib/src/ShieldNetApi/ShieldNetApiController.php
CHANGED
@@ -1,8 +1,8 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\ShieldNetApi;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Data\Adapter\
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin;
|
8 |
use FernleafSystems\Wordpress\Plugin\Shield\ShieldNetApi;
|
@@ -13,12 +13,9 @@ use FernleafSystems\Wordpress\Services\Services;
|
|
13 |
* @package FernleafSystems\Wordpress\Plugin\Shield\ShieldNetApi
|
14 |
* @property ShieldNetApiDataVO $vo
|
15 |
*/
|
16 |
-
class ShieldNetApiController {
|
17 |
|
18 |
use ModConsumer;
|
19 |
-
use StdClassAdapter {
|
20 |
-
__get as __adapterGet;
|
21 |
-
}
|
22 |
|
23 |
/**
|
24 |
* Automatically throttles request because otherwise PRO-nulled versions of Shield will cause
|
@@ -27,28 +24,28 @@ class ShieldNetApiController {
|
|
27 |
* Note To Plugin 'Null'ers:
|
28 |
* PRO features that require handshaking wont work even if you null the plugin because our
|
29 |
* API will always reject those requests. Don't fiddle with this function, please. You may get
|
30 |
-
* away with nulling the plugin for
|
31 |
* @return bool
|
32 |
*/
|
33 |
-
public function canHandshake() {
|
34 |
-
$
|
35 |
if ( $this->vo->last_handshake_at === 0 ) {
|
36 |
|
37 |
-
$
|
38 |
-
|
39 |
-
if ( $
|
40 |
-
$
|
41 |
->setMod( $this->getMod() )
|
42 |
->run();
|
43 |
|
44 |
-
if ( $
|
45 |
-
$this->vo->last_handshake_at = $
|
46 |
$this->vo->handshake_fail_count = 0;
|
47 |
}
|
48 |
else {
|
49 |
$this->vo->handshake_fail_count++;
|
50 |
}
|
51 |
-
$this->vo->last_handshake_attempt_at = $
|
52 |
$this->storeVoData();
|
53 |
}
|
54 |
}
|
@@ -57,29 +54,29 @@ class ShieldNetApiController {
|
|
57 |
}
|
58 |
|
59 |
public function storeVoData() {
|
60 |
-
$this->getOptions()->setOpt( 'snapi_data', $this->vo->
|
61 |
$this->getMod()->saveModOptions();
|
62 |
}
|
63 |
|
64 |
/**
|
65 |
-
* @param string $
|
66 |
* @return mixed
|
67 |
*/
|
68 |
-
public function __get( $
|
69 |
-
/** @var Plugin\Options $
|
70 |
-
$
|
71 |
|
72 |
-
$
|
73 |
|
74 |
-
switch ( $
|
75 |
|
76 |
case 'vo':
|
77 |
-
if ( empty( $
|
78 |
-
$
|
79 |
-
$
|
80 |
-
is_array( $
|
81 |
);
|
82 |
-
$this->vo = $
|
83 |
}
|
84 |
break;
|
85 |
|
@@ -87,6 +84,6 @@ class ShieldNetApiController {
|
|
87 |
break;
|
88 |
}
|
89 |
|
90 |
-
return $
|
91 |
}
|
92 |
}
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\ShieldNetApi;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Plugin;
|
8 |
use FernleafSystems\Wordpress\Plugin\Shield\ShieldNetApi;
|
13 |
* @package FernleafSystems\Wordpress\Plugin\Shield\ShieldNetApi
|
14 |
* @property ShieldNetApiDataVO $vo
|
15 |
*/
|
16 |
+
class ShieldNetApiController extends DynPropertiesClass {
|
17 |
|
18 |
use ModConsumer;
|
|
|
|
|
|
|
19 |
|
20 |
/**
|
21 |
* Automatically throttles request because otherwise PRO-nulled versions of Shield will cause
|
24 |
* Note To Plugin 'Null'ers:
|
25 |
* PRO features that require handshaking wont work even if you null the plugin because our
|
26 |
* API will always reject those requests. Don't fiddle with this function, please. You may get
|
27 |
+
* away with nulling the plugin for some PRO features, but you can't null our API, sorry.
|
28 |
* @return bool
|
29 |
*/
|
30 |
+
public function canHandshake() :bool {
|
31 |
+
$now = Services::Request()->ts();
|
32 |
if ( $this->vo->last_handshake_at === 0 ) {
|
33 |
|
34 |
+
$canAttempt = $now - MINUTE_IN_SECONDS*5*$this->vo->handshake_fail_count
|
35 |
+
> $this->vo->last_handshake_attempt_at;
|
36 |
+
if ( $canAttempt ) {
|
37 |
+
$handshakeSuccess = ( new ShieldNetApi\Handshake\Verify() )
|
38 |
->setMod( $this->getMod() )
|
39 |
->run();
|
40 |
|
41 |
+
if ( $handshakeSuccess ) {
|
42 |
+
$this->vo->last_handshake_at = $now;
|
43 |
$this->vo->handshake_fail_count = 0;
|
44 |
}
|
45 |
else {
|
46 |
$this->vo->handshake_fail_count++;
|
47 |
}
|
48 |
+
$this->vo->last_handshake_attempt_at = $now;
|
49 |
$this->storeVoData();
|
50 |
}
|
51 |
}
|
54 |
}
|
55 |
|
56 |
public function storeVoData() {
|
57 |
+
$this->getOptions()->setOpt( 'snapi_data', $this->vo->getRawData() );
|
58 |
$this->getMod()->saveModOptions();
|
59 |
}
|
60 |
|
61 |
/**
|
62 |
+
* @param string $key
|
63 |
* @return mixed
|
64 |
*/
|
65 |
+
public function __get( string $key ) {
|
66 |
+
/** @var Plugin\Options $opts */
|
67 |
+
$opts = $this->getOptions();
|
68 |
|
69 |
+
$value = parent::__get( $key );
|
70 |
|
71 |
+
switch ( $key ) {
|
72 |
|
73 |
case 'vo':
|
74 |
+
if ( empty( $value ) ) {
|
75 |
+
$data = $opts->getOpt( 'snapi_data', [] );
|
76 |
+
$value = ( new ShieldNetApiDataVO() )->applyFromArray(
|
77 |
+
is_array( $data ) ? $data : []
|
78 |
);
|
79 |
+
$this->vo = $value;
|
80 |
}
|
81 |
break;
|
82 |
|
84 |
break;
|
85 |
}
|
86 |
|
87 |
+
return $value;
|
88 |
}
|
89 |
}
|
src/lib/src/ShieldNetApi/ShieldNetApiDataVO.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\ShieldNetApi;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Data\Adapter\
|
6 |
|
7 |
/**
|
8 |
* Class ShieldNetApiDataVO
|
@@ -12,38 +12,34 @@ use FernleafSystems\Utilities\Data\Adapter\StdClassAdapter;
|
|
12 |
* @property int $handshake_fail_count
|
13 |
* @property int[] $nonces
|
14 |
*/
|
15 |
-
class ShieldNetApiDataVO {
|
16 |
-
|
17 |
-
use StdClassAdapter {
|
18 |
-
__get as __adapterGet;
|
19 |
-
}
|
20 |
|
21 |
/**
|
22 |
-
* @param string $
|
23 |
* @return mixed
|
24 |
*/
|
25 |
-
public function __get( $
|
26 |
|
27 |
-
$
|
28 |
|
29 |
-
switch ( $
|
30 |
|
31 |
case 'nonces':
|
32 |
-
if ( !is_array( $
|
33 |
-
$
|
34 |
}
|
35 |
break;
|
36 |
|
37 |
case 'last_handshake_at':
|
38 |
case 'last_handshake_attempt_at':
|
39 |
case 'handshake_fail_count':
|
40 |
-
$
|
41 |
break;
|
42 |
|
43 |
default:
|
44 |
break;
|
45 |
}
|
46 |
|
47 |
-
return $
|
48 |
}
|
49 |
}
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\ShieldNetApi;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
|
6 |
|
7 |
/**
|
8 |
* Class ShieldNetApiDataVO
|
12 |
* @property int $handshake_fail_count
|
13 |
* @property int[] $nonces
|
14 |
*/
|
15 |
+
class ShieldNetApiDataVO extends DynPropertiesClass {
|
|
|
|
|
|
|
|
|
16 |
|
17 |
/**
|
18 |
+
* @param string $key
|
19 |
* @return mixed
|
20 |
*/
|
21 |
+
public function __get( string $key ) {
|
22 |
|
23 |
+
$value = parent::__get( $key );
|
24 |
|
25 |
+
switch ( $key ) {
|
26 |
|
27 |
case 'nonces':
|
28 |
+
if ( !is_array( $value ) ) {
|
29 |
+
$value = [];
|
30 |
}
|
31 |
break;
|
32 |
|
33 |
case 'last_handshake_at':
|
34 |
case 'last_handshake_attempt_at':
|
35 |
case 'handshake_fail_count':
|
36 |
+
$value = (int)$value;
|
37 |
break;
|
38 |
|
39 |
default:
|
40 |
break;
|
41 |
}
|
42 |
|
43 |
+
return $value;
|
44 |
}
|
45 |
}
|
src/lib/src/Tables/Build/AdminNotes.php
CHANGED
@@ -15,16 +15,16 @@ class AdminNotes extends BaseBuild {
|
|
15 |
* @return array[]
|
16 |
*/
|
17 |
public function getEntriesFormatted() :array {
|
18 |
-
$
|
19 |
|
20 |
-
foreach ( $this->getEntriesRaw() as $
|
21 |
-
/** @var EntryVO $
|
22 |
-
$
|
23 |
-
$
|
24 |
-
$
|
25 |
}
|
26 |
|
27 |
-
return $
|
28 |
}
|
29 |
|
30 |
/**
|
15 |
* @return array[]
|
16 |
*/
|
17 |
public function getEntriesFormatted() :array {
|
18 |
+
$entries = [];
|
19 |
|
20 |
+
foreach ( $this->getEntriesRaw() as $key => $entry ) {
|
21 |
+
/** @var EntryVO $entry */
|
22 |
+
$e = $entry->getRawData();
|
23 |
+
$e[ 'created_at' ] = $this->formatTimestampField( $entry->created_at );
|
24 |
+
$entries[ $key ] = $e;
|
25 |
}
|
26 |
|
27 |
+
return $entries;
|
28 |
}
|
29 |
|
30 |
/**
|
src/lib/src/Tables/Build/AuditTrail.php
CHANGED
@@ -16,53 +16,50 @@ class AuditTrail extends BaseBuild {
|
|
16 |
* @return $this
|
17 |
*/
|
18 |
protected function applyCustomQueryFilters() {
|
19 |
-
$
|
20 |
-
/** @var Shield\Databases\AuditTrail\Select $
|
21 |
-
$
|
22 |
|
23 |
-
$
|
24 |
|
25 |
-
$oIp = Services::IP();
|
26 |
// If an IP is specified, it takes priority
|
27 |
-
if (
|
28 |
-
$
|
29 |
}
|
30 |
-
elseif ( $
|
31 |
-
$
|
32 |
}
|
33 |
|
34 |
/**
|
35 |
* put this date stuff in the base so we can filter anything
|
36 |
*/
|
37 |
-
if ( !empty( $
|
38 |
-
$aParts = explode( '-', $
|
39 |
-
$
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
$oSelector->filterByCreatedAt( $sTs, '>' );
|
44 |
}
|
45 |
|
46 |
-
if ( !empty( $
|
47 |
-
$aParts = explode( '-', $
|
48 |
-
$
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
$oSelector->filterByCreatedAt( $sTs, '<' );
|
54 |
}
|
55 |
|
56 |
// if username is provided, this takes priority over "logged-in" (even if it's invalid)
|
57 |
-
if ( !empty( $
|
58 |
-
$
|
59 |
}
|
60 |
-
elseif ( $
|
61 |
-
$
|
62 |
}
|
63 |
|
64 |
-
$
|
65 |
-
|
66 |
|
67 |
return $this;
|
68 |
}
|
@@ -83,80 +80,75 @@ class AuditTrail extends BaseBuild {
|
|
83 |
* @return array[]
|
84 |
*/
|
85 |
public function getEntriesFormatted() :array {
|
86 |
-
$
|
87 |
|
88 |
$srvIP = Services::IP();
|
89 |
$you = $srvIP->getRequestIp();
|
90 |
-
$
|
91 |
-
foreach ( $this->getEntriesRaw() as $
|
92 |
-
/** @var Shield\Databases\AuditTrail\EntryVO $
|
93 |
|
94 |
-
$
|
95 |
-
if ( empty( $
|
96 |
/**
|
97 |
* To cater for the contexts that don't refer to a module, but rather a context
|
98 |
* with the Audit Trail module
|
99 |
*/
|
100 |
-
$mod = $
|
101 |
if ( empty( $mod ) ) {
|
102 |
-
$mod = $
|
103 |
-
}
|
104 |
-
$oStrings = $mod->getStrings();
|
105 |
-
|
106 |
-
if ( $oStrings instanceof Shield\Modules\Base\Strings ) {
|
107 |
-
$sMsg = stripslashes( sanitize_textarea_field(
|
108 |
-
vsprintf(
|
109 |
-
implode( "\n", $oStrings->getAuditMessage( $oEntry->event ) ),
|
110 |
-
$oEntry->meta
|
111 |
-
)
|
112 |
-
) );
|
113 |
}
|
|
|
|
|
|
|
|
|
114 |
}
|
115 |
else {
|
116 |
-
$
|
117 |
}
|
118 |
|
119 |
-
if ( !isset( $
|
120 |
-
$
|
121 |
-
$
|
122 |
-
$
|
123 |
-
$
|
124 |
-
$
|
125 |
-
if ( $
|
126 |
-
$
|
127 |
}
|
128 |
|
129 |
try {
|
130 |
-
$
|
131 |
}
|
132 |
catch ( \Exception $e ) {
|
133 |
-
$
|
134 |
}
|
135 |
|
136 |
-
if ( empty( $
|
137 |
-
$
|
138 |
}
|
139 |
else {
|
140 |
-
$
|
141 |
-
$this->getIpAnalysisLink( $
|
142 |
-
$
|
143 |
);
|
144 |
}
|
145 |
}
|
146 |
else {
|
147 |
-
$
|
148 |
-
$
|
149 |
-
$
|
|
|
150 |
}
|
151 |
|
152 |
-
if ( $
|
153 |
-
$
|
154 |
-
|
155 |
}
|
156 |
|
157 |
-
$
|
158 |
}
|
159 |
-
return $
|
160 |
}
|
161 |
|
162 |
/**
|
16 |
* @return $this
|
17 |
*/
|
18 |
protected function applyCustomQueryFilters() {
|
19 |
+
$params = $this->getParams();
|
20 |
+
/** @var Shield\Databases\AuditTrail\Select $selector */
|
21 |
+
$selector = $this->getWorkingSelector();
|
22 |
|
23 |
+
$selector->filterByEvent( $params[ 'fEvent' ] );
|
24 |
|
|
|
25 |
// If an IP is specified, it takes priority
|
26 |
+
if ( Services::IP()->isValidIp( $params[ 'fIp' ] ) ) {
|
27 |
+
$selector->filterByIp( $params[ 'fIp' ] );
|
28 |
}
|
29 |
+
elseif ( $params[ 'fExcludeYou' ] == 'Y' ) {
|
30 |
+
$selector->filterByNotIp( Services::IP()->getRequestIp() );
|
31 |
}
|
32 |
|
33 |
/**
|
34 |
* put this date stuff in the base so we can filter anything
|
35 |
*/
|
36 |
+
if ( !empty( $params[ 'fDateFrom' ] ) && preg_match( '#^\d{4}-\d{2}-\d{2}$#', $params[ 'fDateFrom' ] ) ) {
|
37 |
+
$aParts = explode( '-', $params[ 'fDateFrom' ] );
|
38 |
+
$ts = Services::Request()->carbon()
|
39 |
+
->setDate( $aParts[ 0 ], $aParts[ 1 ], $aParts[ 2 ] )
|
40 |
+
->setTime( 0, 0 )->timestamp;
|
41 |
+
$selector->filterByCreatedAt( $ts, '>' );
|
|
|
42 |
}
|
43 |
|
44 |
+
if ( !empty( $params[ 'fDateTo' ] ) && preg_match( '#^\d{4}-\d{2}-\d{2}$#', $params[ 'fDateTo' ] ) ) {
|
45 |
+
$aParts = explode( '-', $params[ 'fDateTo' ] );
|
46 |
+
$ts = Services::Request()->carbon()
|
47 |
+
->setDate( $aParts[ 0 ], $aParts[ 1 ], $aParts[ 2 ] )
|
48 |
+
->setTime( 0, 0 )
|
49 |
+
->addDay()->timestamp;
|
50 |
+
$selector->filterByCreatedAt( $ts, '<' );
|
|
|
51 |
}
|
52 |
|
53 |
// if username is provided, this takes priority over "logged-in" (even if it's invalid)
|
54 |
+
if ( !empty( $params[ 'fUsername' ] ) ) {
|
55 |
+
$selector->filterByUsername( $params[ 'fUsername' ] );
|
56 |
}
|
57 |
+
elseif ( $params[ 'fLoggedIn' ] >= 0 ) {
|
58 |
+
$selector->filterByIsLoggedIn( $params[ 'fLoggedIn' ] );
|
59 |
}
|
60 |
|
61 |
+
$selector->setOrderBy( 'updated_at', 'DESC', true )
|
62 |
+
->setOrderBy( 'created_at' );
|
63 |
|
64 |
return $this;
|
65 |
}
|
80 |
* @return array[]
|
81 |
*/
|
82 |
public function getEntriesFormatted() :array {
|
83 |
+
$entries = [];
|
84 |
|
85 |
$srvIP = Services::IP();
|
86 |
$you = $srvIP->getRequestIp();
|
87 |
+
$con = $this->getCon();
|
88 |
+
foreach ( $this->getEntriesRaw() as $key => $entry ) {
|
89 |
+
/** @var Shield\Databases\AuditTrail\EntryVO $entry */
|
90 |
|
91 |
+
$msg = 'Audit message could not be retrieved';
|
92 |
+
if ( empty( $entry->message ) ) {
|
93 |
/**
|
94 |
* To cater for the contexts that don't refer to a module, but rather a context
|
95 |
* with the Audit Trail module
|
96 |
*/
|
97 |
+
$mod = $con->getModule( $entry->context );
|
98 |
if ( empty( $mod ) ) {
|
99 |
+
$mod = $con->getModule_AuditTrail();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
100 |
}
|
101 |
+
|
102 |
+
$msg = Shield\Modules\AuditTrail\Lib\AuditMessageBuilder::Build(
|
103 |
+
$entry, $mod->getStrings()->getAuditMessage( $entry->event )
|
104 |
+
);
|
105 |
}
|
106 |
else {
|
107 |
+
$msg = $entry->message;
|
108 |
}
|
109 |
|
110 |
+
if ( !isset( $entries[ $entry->rid ] ) ) {
|
111 |
+
$ent = $entry->getRawData();
|
112 |
+
$ent[ 'meta' ] = $entry->meta;
|
113 |
+
$ent[ 'event' ] = str_replace( '_', ' ', sanitize_text_field( $entry->event ) );
|
114 |
+
$ent[ 'message' ] = $msg;
|
115 |
+
$ent[ 'created_at' ] = $this->formatTimestampField( $entry->created_at );
|
116 |
+
if ( $entry->wp_username == '-' ) {
|
117 |
+
$ent[ 'wp_username' ] = __( 'Not logged-in', 'wp-simple-firewall' );
|
118 |
}
|
119 |
|
120 |
try {
|
121 |
+
$ent[ 'is_you' ] = $srvIP->checkIp( $you, $entry->ip );
|
122 |
}
|
123 |
catch ( \Exception $e ) {
|
124 |
+
$ent[ 'is_you' ] = false;
|
125 |
}
|
126 |
|
127 |
+
if ( empty( $entry->ip ) ) {
|
128 |
+
$ent[ 'ip' ] = '';
|
129 |
}
|
130 |
else {
|
131 |
+
$ent[ 'ip' ] = sprintf( '%s%s',
|
132 |
+
$this->getIpAnalysisLink( $entry->ip ),
|
133 |
+
$ent[ 'is_you' ] ? ' <small>('.__( 'You', 'wp-simple-firewall' ).')</small>' : ''
|
134 |
);
|
135 |
}
|
136 |
}
|
137 |
else {
|
138 |
+
$ent = $entries[ $entry->rid ];
|
139 |
+
$ent[ 'meta' ] = Services::DataManipulation()->mergeArraysRecursive( $ent[ 'meta' ], $entry->meta );
|
140 |
+
$ent[ 'message' ] .= "\n".$msg;
|
141 |
+
$ent[ 'category' ] = max( $ent[ 'category' ], $entry->category );
|
142 |
}
|
143 |
|
144 |
+
if ( $entry->count > 1 ) {
|
145 |
+
$ent[ 'message' ] = $msg."\n"
|
146 |
+
.sprintf( __( 'This event repeated %s times in the last 24hrs.', 'wp-simple-firewall' ), $entry->count );
|
147 |
}
|
148 |
|
149 |
+
$entries[ $entry->rid ] = $ent;
|
150 |
}
|
151 |
+
return $entries;
|
152 |
}
|
153 |
|
154 |
/**
|
src/lib/src/Tables/Build/Ip.php
CHANGED
@@ -18,17 +18,17 @@ class Ip extends BaseBuild {
|
|
18 |
* @return $this
|
19 |
*/
|
20 |
protected function applyCustomQueryFilters() {
|
21 |
-
$
|
22 |
|
23 |
-
/** @var IPs\Select $
|
24 |
-
$
|
25 |
-
$
|
26 |
-
if ( Services::IP()->isValidIp( $
|
27 |
-
$
|
28 |
}
|
29 |
|
30 |
-
$
|
31 |
-
$
|
32 |
|
33 |
return $this;
|
34 |
}
|
@@ -50,29 +50,29 @@ class Ip extends BaseBuild {
|
|
50 |
|
51 |
$nTransLimit = $opts->getOffenseLimit();
|
52 |
$you = $srvIP->getRequestIp();
|
53 |
-
$
|
54 |
|
55 |
-
foreach ( $this->getEntriesRaw() as $
|
56 |
-
/** @var IPs\EntryVO $
|
57 |
-
$aE = $
|
58 |
-
$bBlocked = $
|
59 |
$aE[ 'last_trans_at' ] = Services::Request()
|
60 |
->carbon( true )
|
61 |
-
->setTimestamp( $
|
62 |
->diffForHumans();
|
63 |
-
$aE[ 'last_access_at' ] = $this->formatTimestampField( $
|
64 |
-
$aE[ 'created_at' ] = $this->formatTimestampField( $
|
65 |
$aE[ 'blocked' ] = $bBlocked ? __( 'Yes' ) : __( 'No' );
|
66 |
-
$aE[ 'expires_at' ] = $this->formatTimestampField( $
|
67 |
-
$aE[ 'is_you' ] = $srvIP->checkIp( $you, $
|
68 |
$aE[ 'ip' ] = sprintf( '%s%s',
|
69 |
-
$this->getIpAnalysisLink( $
|
70 |
$aE[ 'is_you' ] ? ' <span class="small">('.__( 'You', 'wp-simple-firewall' ).')</span>' : ''
|
71 |
);
|
72 |
|
73 |
-
$
|
74 |
}
|
75 |
-
return $
|
76 |
}
|
77 |
|
78 |
/**
|
18 |
* @return $this
|
19 |
*/
|
20 |
protected function applyCustomQueryFilters() {
|
21 |
+
$params = $this->getParams();
|
22 |
|
23 |
+
/** @var IPs\Select $selector */
|
24 |
+
$selector = $this->getWorkingSelector();
|
25 |
+
$selector->filterByLists( $params[ 'fLists' ] );
|
26 |
+
if ( Services::IP()->isValidIp( $params[ 'fIp' ] ) ) {
|
27 |
+
$selector->filterByIp( $params[ 'fIp' ] );
|
28 |
}
|
29 |
|
30 |
+
$selector->setOrderBy( 'last_access_at', 'DESC', true );
|
31 |
+
$selector->setOrderBy( 'created_at', 'DESC', false );
|
32 |
|
33 |
return $this;
|
34 |
}
|
50 |
|
51 |
$nTransLimit = $opts->getOffenseLimit();
|
52 |
$you = $srvIP->getRequestIp();
|
53 |
+
$entries = [];
|
54 |
|
55 |
+
foreach ( $this->getEntriesRaw() as $key => $entry ) {
|
56 |
+
/** @var IPs\EntryVO $entry */
|
57 |
+
$aE = $entry->getRawData();
|
58 |
+
$bBlocked = $entry->blocked_at > 0 || $entry->transgressions >= $nTransLimit;
|
59 |
$aE[ 'last_trans_at' ] = Services::Request()
|
60 |
->carbon( true )
|
61 |
+
->setTimestamp( $entry->last_access_at )
|
62 |
->diffForHumans();
|
63 |
+
$aE[ 'last_access_at' ] = $this->formatTimestampField( $entry->last_access_at );
|
64 |
+
$aE[ 'created_at' ] = $this->formatTimestampField( $entry->created_at );
|
65 |
$aE[ 'blocked' ] = $bBlocked ? __( 'Yes' ) : __( 'No' );
|
66 |
+
$aE[ 'expires_at' ] = $this->formatTimestampField( $entry->last_access_at + $opts->getAutoExpireTime() );
|
67 |
+
$aE[ 'is_you' ] = $srvIP->checkIp( $you, $entry->ip );
|
68 |
$aE[ 'ip' ] = sprintf( '%s%s',
|
69 |
+
$this->getIpAnalysisLink( $entry->ip ),
|
70 |
$aE[ 'is_you' ] ? ' <span class="small">('.__( 'You', 'wp-simple-firewall' ).')</span>' : ''
|
71 |
);
|
72 |
|
73 |
+
$entries[ $key ] = $aE;
|
74 |
}
|
75 |
+
return $entries;
|
76 |
}
|
77 |
|
78 |
/**
|
src/lib/src/Tables/Build/ScanApc.php
CHANGED
@@ -26,20 +26,20 @@ class ScanApc extends ScanBase {
|
|
26 |
$oConverter = new Scan\Results\ConvertBetweenTypes();
|
27 |
|
28 |
$oWpPlugins = Services::WpPlugins();
|
29 |
-
foreach ( $this->getEntriesRaw() as $nKey => $
|
30 |
-
/** @var Shield\Databases\Scanner\EntryVO $
|
31 |
/** @var Shield\Scans\Apc\ResultItem $oIt */
|
32 |
$oIt = $oConverter
|
33 |
-
->setScanController( $mod->getScanCon( $
|
34 |
-
->convertVoToResultItem( $
|
35 |
$oPlugin = $oWpPlugins->getPluginAsVo( $oIt->slug );
|
36 |
-
$aE = $
|
37 |
$aE[ 'plugin' ] = sprintf( '%s (%s)', $oPlugin->Name, $oPlugin->Version );
|
38 |
$aE[ 'status' ] = sprintf( '%s: %s',
|
39 |
__( 'Abandoned', 'wp-simple-firewall' ), $oCarbon->setTimestamp( $oIt->last_updated_at )
|
40 |
->diffForHumans() );
|
41 |
-
$aE[ 'ignored' ] = $this->formatIsIgnored( $
|
42 |
-
$aE[ 'created_at' ] = $this->formatTimestampField( $
|
43 |
$aEntries[ $nKey ] = $aE;
|
44 |
}
|
45 |
|
26 |
$oConverter = new Scan\Results\ConvertBetweenTypes();
|
27 |
|
28 |
$oWpPlugins = Services::WpPlugins();
|
29 |
+
foreach ( $this->getEntriesRaw() as $nKey => $entry ) {
|
30 |
+
/** @var Shield\Databases\Scanner\EntryVO $entry */
|
31 |
/** @var Shield\Scans\Apc\ResultItem $oIt */
|
32 |
$oIt = $oConverter
|
33 |
+
->setScanController( $mod->getScanCon( $entry->scan ) )
|
34 |
+
->convertVoToResultItem( $entry );
|
35 |
$oPlugin = $oWpPlugins->getPluginAsVo( $oIt->slug );
|
36 |
+
$aE = $entry->getRawData();
|
37 |
$aE[ 'plugin' ] = sprintf( '%s (%s)', $oPlugin->Name, $oPlugin->Version );
|
38 |
$aE[ 'status' ] = sprintf( '%s: %s',
|
39 |
__( 'Abandoned', 'wp-simple-firewall' ), $oCarbon->setTimestamp( $oIt->last_updated_at )
|
40 |
->diffForHumans() );
|
41 |
+
$aE[ 'ignored' ] = $this->formatIsIgnored( $entry );
|
42 |
+
$aE[ 'created_at' ] = $this->formatTimestampField( $entry->created_at );
|
43 |
$aEntries[ $nKey ] = $aE;
|
44 |
}
|
45 |
|
src/lib/src/Tables/Build/ScanPtg.php
CHANGED
@@ -19,19 +19,19 @@ class ScanPtg extends ScanBase {
|
|
19 |
* @return Shield\Databases\Scanner\EntryVO[]
|
20 |
*/
|
21 |
protected function postSelectEntriesFilter( $aEntries ) {
|
22 |
-
$
|
23 |
|
24 |
/** @var ModCon $mod */
|
25 |
$mod = $this->getMod();
|
26 |
|
27 |
-
if ( !empty( $
|
28 |
|
29 |
|
30 |
/** @var Shield\Scans\Ptg\ResultsSet $oSlugResults */
|
31 |
$oSlugResults = ( new Scan\Results\ConvertBetweenTypes() )
|
32 |
-
->setScanController( $mod->getScanCon( $
|
33 |
->fromVOsToResultsSet( $aEntries );
|
34 |
-
$oSlugResults = $oSlugResults->getResultsSetForSlug( $
|
35 |
|
36 |
foreach ( $aEntries as $key => $oVo ) {
|
37 |
if ( !$oSlugResults->getItemExists( $oVo->hash ) ) {
|
19 |
* @return Shield\Databases\Scanner\EntryVO[]
|
20 |
*/
|
21 |
protected function postSelectEntriesFilter( $aEntries ) {
|
22 |
+
$params = $this->getParams();
|
23 |
|
24 |
/** @var ModCon $mod */
|
25 |
$mod = $this->getMod();
|
26 |
|
27 |
+
if ( !empty( $params[ 'fSlug' ] ) ) {
|
28 |
|
29 |
|
30 |
/** @var Shield\Scans\Ptg\ResultsSet $oSlugResults */
|
31 |
$oSlugResults = ( new Scan\Results\ConvertBetweenTypes() )
|
32 |
+
->setScanController( $mod->getScanCon( $params[ 'fSlug' ] ) )
|
33 |
->fromVOsToResultsSet( $aEntries );
|
34 |
+
$oSlugResults = $oSlugResults->getResultsSetForSlug( $params[ 'fSlug' ] );
|
35 |
|
36 |
foreach ( $aEntries as $key => $oVo ) {
|
37 |
if ( !$oSlugResults->getItemExists( $oVo->hash ) ) {
|
src/lib/src/Tables/Build/ScanWpv.php
CHANGED
@@ -30,13 +30,13 @@ class ScanWpv extends ScanBase {
|
|
30 |
$oWpThemes->getUpdates( true );
|
31 |
|
32 |
$oConverter = new Scan\Results\ConvertBetweenTypes();
|
33 |
-
foreach ( $this->getEntriesRaw() as $nKey => $
|
34 |
-
/** @var Shield\Databases\Scanner\EntryVO $
|
35 |
/** @var Shield\Scans\Wpv\ResultItem $oIt */
|
36 |
$oIt = $oConverter
|
37 |
-
->setScanController( $mod->getScanCon( $
|
38 |
-
->convertVoToResultItem( $
|
39 |
-
$aE = $
|
40 |
if ( $oIt->context == 'plugins' ) {
|
41 |
$oAsset = $oWpPlugins->getPluginAsVo( $oIt->slug );
|
42 |
$aE[ 'asset' ] = $oAsset;
|
@@ -55,8 +55,8 @@ class ScanWpv extends ScanBase {
|
|
55 |
}
|
56 |
$aE[ 'slug' ] = $oIt->slug;
|
57 |
$aE[ 'wpvuln_vo' ] = $oIt->getWpVulnVo();
|
58 |
-
$aE[ 'ignored' ] = $this->formatIsIgnored( $
|
59 |
-
$aE[ 'created_at' ] = $this->formatTimestampField( $
|
60 |
$aEntries[ $nKey ] = $aE;
|
61 |
}
|
62 |
|
30 |
$oWpThemes->getUpdates( true );
|
31 |
|
32 |
$oConverter = new Scan\Results\ConvertBetweenTypes();
|
33 |
+
foreach ( $this->getEntriesRaw() as $nKey => $entry ) {
|
34 |
+
/** @var Shield\Databases\Scanner\EntryVO $entry */
|
35 |
/** @var Shield\Scans\Wpv\ResultItem $oIt */
|
36 |
$oIt = $oConverter
|
37 |
+
->setScanController( $mod->getScanCon( $entry->scan ) )
|
38 |
+
->convertVoToResultItem( $entry );
|
39 |
+
$aE = $entry->getRawData();
|
40 |
if ( $oIt->context == 'plugins' ) {
|
41 |
$oAsset = $oWpPlugins->getPluginAsVo( $oIt->slug );
|
42 |
$aE[ 'asset' ] = $oAsset;
|
55 |
}
|
56 |
$aE[ 'slug' ] = $oIt->slug;
|
57 |
$aE[ 'wpvuln_vo' ] = $oIt->getWpVulnVo();
|
58 |
+
$aE[ 'ignored' ] = $this->formatIsIgnored( $entry );
|
59 |
+
$aE[ 'created_at' ] = $this->formatTimestampField( $entry->created_at );
|
60 |
$aEntries[ $nKey ] = $aE;
|
61 |
}
|
62 |
|
src/lib/src/Tables/Build/Sessions.php
CHANGED
@@ -59,21 +59,21 @@ class Sessions extends BaseBuild {
|
|
59 |
|
60 |
$srvIP = Services::IP();
|
61 |
$you = $srvIP->getRequestIp();
|
62 |
-
foreach ( $this->getEntriesRaw() as $nKey => $
|
63 |
-
/** @var Session\EntryVO $
|
64 |
-
$aE = $
|
65 |
-
$aE[ 'is_secadmin' ] = $this->isSecAdminSession( $
|
66 |
-
$aE[ 'last_activity_at' ] = $this->formatTimestampField( $
|
67 |
-
$aE[ 'logged_in_at' ] = $this->formatTimestampField( $
|
68 |
|
69 |
try {
|
70 |
-
$aE[ 'is_you' ] = $srvIP->checkIp( $you, $
|
71 |
}
|
72 |
catch ( \Exception $e ) {
|
73 |
$aE[ 'is_you' ] = false;
|
74 |
}
|
75 |
$aE[ 'ip' ] = sprintf( '%s%s',
|
76 |
-
$this->getIpAnalysisLink( $
|
77 |
$aE[ 'is_you' ] ? ' <small>('.__( 'You', 'wp-simple-firewall' ).')</small>' : ''
|
78 |
);
|
79 |
|
59 |
|
60 |
$srvIP = Services::IP();
|
61 |
$you = $srvIP->getRequestIp();
|
62 |
+
foreach ( $this->getEntriesRaw() as $nKey => $entry ) {
|
63 |
+
/** @var Session\EntryVO $entry */
|
64 |
+
$aE = $entry->getRawData();
|
65 |
+
$aE[ 'is_secadmin' ] = $this->isSecAdminSession( $entry ) ? __( 'Yes' ) : __( 'No' );
|
66 |
+
$aE[ 'last_activity_at' ] = $this->formatTimestampField( $entry->last_activity_at );
|
67 |
+
$aE[ 'logged_in_at' ] = $this->formatTimestampField( $entry->logged_in_at );
|
68 |
|
69 |
try {
|
70 |
+
$aE[ 'is_you' ] = $srvIP->checkIp( $you, $entry->ip );
|
71 |
}
|
72 |
catch ( \Exception $e ) {
|
73 |
$aE[ 'is_you' ] = false;
|
74 |
}
|
75 |
$aE[ 'ip' ] = sprintf( '%s%s',
|
76 |
+
$this->getIpAnalysisLink( $entry->ip ),
|
77 |
$aE[ 'is_you' ] ? ' <small>('.__( 'You', 'wp-simple-firewall' ).')</small>' : ''
|
78 |
);
|
79 |
|
src/lib/src/Tables/Build/Traffic.php
CHANGED
@@ -20,13 +20,13 @@ class Traffic extends BaseBuild {
|
|
20 |
/** @var Databases\Traffic\Select $select */
|
21 |
$select = $this->getWorkingSelector();
|
22 |
|
23 |
-
$
|
24 |
// If an IP is specified, it takes priority
|
25 |
-
if ( $
|
26 |
$select->filterByIp( inet_pton( $params[ 'fIp' ] ) );
|
27 |
}
|
28 |
elseif ( $params[ 'fExcludeYou' ] == 'Y' ) {
|
29 |
-
$select->filterByNotIp( inet_pton( $
|
30 |
}
|
31 |
|
32 |
// if username is provided, this takes priority over "logged-in" (even if it's invalid)
|
@@ -99,7 +99,7 @@ class Traffic extends BaseBuild {
|
|
99 |
$sCodeType = 'warning';
|
100 |
}
|
101 |
|
102 |
-
$e = $record->
|
103 |
$e[ 'path' ] = $sPath;
|
104 |
$e[ 'code' ] = sprintf( '<span class="badge badge-%s">%s</span>', $sCodeType, $record->code );
|
105 |
$e[ 'trans' ] = sprintf(
|
@@ -177,7 +177,11 @@ class Traffic extends BaseBuild {
|
|
177 |
->lookup();
|
178 |
|
179 |
$badgeTemplate = '<span class="badge badge-%s">%s</span>';
|
180 |
-
|
|
|
|
|
|
|
|
|
181 |
$status = sprintf( $badgeTemplate, 'danger', __( 'Blocked', 'wp-simple-firewall' ) );
|
182 |
}
|
183 |
elseif ( $record->list === ModCon::LIST_AUTO_BLACK ) {
|
@@ -192,9 +196,6 @@ class Traffic extends BaseBuild {
|
|
192 |
__( 'Bypass', 'wp-simple-firewall' )
|
193 |
);
|
194 |
}
|
195 |
-
else {
|
196 |
-
$status = __( 'No Record', 'wp-simple-firewall' );
|
197 |
-
}
|
198 |
return $status;
|
199 |
}
|
200 |
|
20 |
/** @var Databases\Traffic\Select $select */
|
21 |
$select = $this->getWorkingSelector();
|
22 |
|
23 |
+
$srvIP = Services::IP();
|
24 |
// If an IP is specified, it takes priority
|
25 |
+
if ( $srvIP->isValidIp( $params[ 'fIp' ] ) ) {
|
26 |
$select->filterByIp( inet_pton( $params[ 'fIp' ] ) );
|
27 |
}
|
28 |
elseif ( $params[ 'fExcludeYou' ] == 'Y' ) {
|
29 |
+
$select->filterByNotIp( inet_pton( $srvIP->getRequestIp() ) );
|
30 |
}
|
31 |
|
32 |
// if username is provided, this takes priority over "logged-in" (even if it's invalid)
|
99 |
$sCodeType = 'warning';
|
100 |
}
|
101 |
|
102 |
+
$e = $record->getRawData();
|
103 |
$e[ 'path' ] = $sPath;
|
104 |
$e[ 'code' ] = sprintf( '<span class="badge badge-%s">%s</span>', $sCodeType, $record->code );
|
105 |
$e[ 'trans' ] = sprintf(
|
177 |
->lookup();
|
178 |
|
179 |
$badgeTemplate = '<span class="badge badge-%s">%s</span>';
|
180 |
+
$status = __( 'No Record', 'wp-simple-firewall' );
|
181 |
+
if ( !$record instanceof Databases\IPs\EntryVO ) {
|
182 |
+
$status = __( 'No Record', 'wp-simple-firewall' );
|
183 |
+
}
|
184 |
+
elseif ( $record->blocked_at > 0 || $record->list === ModCon::LIST_MANUAL_BLACK ) {
|
185 |
$status = sprintf( $badgeTemplate, 'danger', __( 'Blocked', 'wp-simple-firewall' ) );
|
186 |
}
|
187 |
elseif ( $record->list === ModCon::LIST_AUTO_BLACK ) {
|
196 |
__( 'Bypass', 'wp-simple-firewall' )
|
197 |
);
|
198 |
}
|
|
|
|
|
|
|
199 |
return $status;
|
200 |
}
|
201 |
|
src/lib/src/Tables/Render/WpListTable/AuditTrail.php
CHANGED
@@ -18,15 +18,15 @@ class AuditTrail extends Base {
|
|
18 |
}
|
19 |
|
20 |
/**
|
21 |
-
* @param int $
|
22 |
* @return string
|
23 |
*/
|
24 |
-
protected function getActionButton_AddParam( $
|
25 |
return $this->buildActionButton_Custom(
|
26 |
__( 'Whitelist Param', 'wp-simple-firewall' ),
|
27 |
[ 'custom-action' ],
|
28 |
[
|
29 |
-
'rid' => $
|
30 |
'custom-action' => 'item_addparamwhite'
|
31 |
],
|
32 |
__( 'Add Parameter To Whitelist', 'wp-simple-firewall' )
|
@@ -49,11 +49,11 @@ class AuditTrail extends Base {
|
|
49 |
* @return string
|
50 |
*/
|
51 |
public function column_user( $item ) {
|
52 |
-
$
|
53 |
if ( isset( $item[ 'meta' ][ 'param' ] ) ) {
|
54 |
-
$
|
55 |
}
|
56 |
-
return $
|
57 |
}
|
58 |
|
59 |
/**
|
18 |
}
|
19 |
|
20 |
/**
|
21 |
+
* @param int $id
|
22 |
* @return string
|
23 |
*/
|
24 |
+
protected function getActionButton_AddParam( $id ) {
|
25 |
return $this->buildActionButton_Custom(
|
26 |
__( 'Whitelist Param', 'wp-simple-firewall' ),
|
27 |
[ 'custom-action' ],
|
28 |
[
|
29 |
+
'rid' => $id,
|
30 |
'custom-action' => 'item_addparamwhite'
|
31 |
],
|
32 |
__( 'Add Parameter To Whitelist', 'wp-simple-firewall' )
|
49 |
* @return string
|
50 |
*/
|
51 |
public function column_user( $item ) {
|
52 |
+
$content = $item[ 'wp_username' ];
|
53 |
if ( isset( $item[ 'meta' ][ 'param' ] ) ) {
|
54 |
+
$content .= $this->buildActions( [ $this->getActionButton_AddParam( $item[ 'id' ] ) ] );
|
55 |
}
|
56 |
+
return $content;
|
57 |
}
|
58 |
|
59 |
/**
|
src/lib/src/Utilities/AdminNotices/Controller.php
CHANGED
@@ -18,31 +18,31 @@ class Controller {
|
|
18 |
|
19 |
/**
|
20 |
* TODO doesn't handle error message highlighting
|
21 |
-
* @param string $
|
22 |
* @return string
|
23 |
*/
|
24 |
-
public function onLoginMessage( $
|
25 |
$aM = $this->retrieveFlashMessage();
|
26 |
if ( is_array( $aM ) && isset( $aM[ 'show_login' ] ) && $aM[ 'show_login' ] ) {
|
27 |
-
$
|
28 |
$this->clearFlashMessage();
|
29 |
}
|
30 |
-
return $
|
31 |
}
|
32 |
|
33 |
/**
|
34 |
-
* @param string $
|
35 |
-
* @param bool $
|
36 |
* @param bool $bShowOnLoginPage
|
37 |
* @return $this
|
38 |
*/
|
39 |
-
public function addFlash( $
|
40 |
$oMeta = $this->getCon()->getCurrentUserMeta();
|
41 |
if ( $oMeta instanceof PluginUserMeta ) {
|
42 |
$oMeta->flash_msg = [
|
43 |
-
'message' => sanitize_text_field( $
|
44 |
'expires_at' => Services::Request()->ts() + 20,
|
45 |
-
'error' => $
|
46 |
'show_login' => $bShowOnLoginPage,
|
47 |
];
|
48 |
}
|
18 |
|
19 |
/**
|
20 |
* TODO doesn't handle error message highlighting
|
21 |
+
* @param string $msg
|
22 |
* @return string
|
23 |
*/
|
24 |
+
public function onLoginMessage( $msg ) {
|
25 |
$aM = $this->retrieveFlashMessage();
|
26 |
if ( is_array( $aM ) && isset( $aM[ 'show_login' ] ) && $aM[ 'show_login' ] ) {
|
27 |
+
$msg .= sprintf( '<p class="message">%s</p>', sanitize_text_field( $aM[ 'message' ] ) );
|
28 |
$this->clearFlashMessage();
|
29 |
}
|
30 |
+
return $msg;
|
31 |
}
|
32 |
|
33 |
/**
|
34 |
+
* @param string $msg
|
35 |
+
* @param bool $isError
|
36 |
* @param bool $bShowOnLoginPage
|
37 |
* @return $this
|
38 |
*/
|
39 |
+
public function addFlash( $msg, $isError = false, $bShowOnLoginPage = false ) {
|
40 |
$oMeta = $this->getCon()->getCurrentUserMeta();
|
41 |
if ( $oMeta instanceof PluginUserMeta ) {
|
42 |
$oMeta->flash_msg = [
|
43 |
+
'message' => sanitize_text_field( $msg ),
|
44 |
'expires_at' => Services::Request()->ts() + 20,
|
45 |
+
'error' => $isError,
|
46 |
'show_login' => $bShowOnLoginPage,
|
47 |
];
|
48 |
}
|
src/lib/src/Utilities/AdminNotices/NoticeVO.php
CHANGED
@@ -1,8 +1,8 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Utilities\AdminNotices;
|
4 |
|
5 |
-
use FernleafSystems\Utilities\Data\Adapter\
|
6 |
|
7 |
/**
|
8 |
* Class NoticeVO
|
@@ -24,5 +24,5 @@ use FernleafSystems\Utilities\Data\Adapter\StdClassAdapter;
|
|
24 |
*/
|
25 |
class NoticeVO {
|
26 |
|
27 |
-
use
|
28 |
}
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Utilities\AdminNotices;
|
4 |
|
5 |
+
use FernleafSystems\Utilities\Data\Adapter\DynProperties;
|
6 |
|
7 |
/**
|
8 |
* Class NoticeVO
|
24 |
*/
|
25 |
class NoticeVO {
|
26 |
|
27 |
+
use DynProperties;
|
28 |
}
|
src/lib/src/Utilities/HCaptcha/TestRequest.php
CHANGED
@@ -3,8 +3,8 @@
|
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Utilities\HCaptcha;
|
4 |
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\ModCon;
|
6 |
-
use FernleafSystems\Wordpress\Services\Services;
|
7 |
use FernleafSystems\Wordpress\Plugin\Shield\Utilities\ReCaptcha;
|
|
|
8 |
|
9 |
class TestRequest extends ReCaptcha\TestRequest {
|
10 |
|
@@ -24,25 +24,25 @@ class TestRequest extends ReCaptcha\TestRequest {
|
|
24 |
throw new \Exception( __( 'Whoops.', 'wp-simple-firewall' ).' '.__( 'CAPTCHA was not submitted.', 'wp-simple-firewall' ), 1 );
|
25 |
}
|
26 |
else {
|
27 |
-
$
|
28 |
-
$
|
29 |
'body' => [
|
30 |
'secret' => $mod->getCaptchaCfg()->secret,
|
31 |
'response' => $sCaptchaResponse,
|
32 |
'remoteip' => Services::IP()->getRequestIp(),
|
33 |
]
|
34 |
] )
|
35 |
-
|
36 |
-
$
|
37 |
|
38 |
-
if ( empty( $
|
39 |
-
$
|
40 |
__( 'Whoops.', 'wp-simple-firewall' ),
|
41 |
__( 'CAPTCHA verification failed.', 'wp-simple-firewall' ),
|
42 |
Services::WpGeneral()->isAjax() ?
|
43 |
__( 'Maybe refresh the page and try again.', 'wp-simple-firewall' ) : ''
|
44 |
];
|
45 |
-
throw new \Exception( implode( ' ', $
|
46 |
}
|
47 |
}
|
48 |
return true;
|
3 |
namespace FernleafSystems\Wordpress\Plugin\Shield\Utilities\HCaptcha;
|
4 |
|
5 |
use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\ModCon;
|
|
|
6 |
use FernleafSystems\Wordpress\Plugin\Shield\Utilities\ReCaptcha;
|
7 |
+
use FernleafSystems\Wordpress\Services\Services;
|
8 |
|
9 |
class TestRequest extends ReCaptcha\TestRequest {
|
10 |
|
24 |
throw new \Exception( __( 'Whoops.', 'wp-simple-firewall' ).' '.__( 'CAPTCHA was not submitted.', 'wp-simple-firewall' ), 1 );
|
25 |
}
|
26 |
else {
|
27 |
+
$HTTPReq = Services::HttpRequest();
|
28 |
+
$successRequest = $HTTPReq->post( self::URL_VERIFY, [
|
29 |
'body' => [
|
30 |
'secret' => $mod->getCaptchaCfg()->secret,
|
31 |
'response' => $sCaptchaResponse,
|
32 |
'remoteip' => Services::IP()->getRequestIp(),
|
33 |
]
|
34 |
] )
|
35 |
+
&& !empty( $HTTPReq->lastResponse->body );
|
36 |
+
$response = $successRequest ? json_decode( $HTTPReq->lastResponse->body, true ) : [];
|
37 |
|
38 |
+
if ( empty( $response[ 'success' ] ) ) {
|
39 |
+
$msg = [
|
40 |
__( 'Whoops.', 'wp-simple-firewall' ),
|
41 |
__( 'CAPTCHA verification failed.', 'wp-simple-firewall' ),
|
42 |
Services::WpGeneral()->isAjax() ?
|
43 |
__( 'Maybe refresh the page and try again.', 'wp-simple-firewall' ) : ''
|
44 |
];
|
45 |
+
throw new \Exception( implode( ' ', $msg ), 2 );
|
46 |
}
|
47 |
}
|
48 |
return true;
|
src/lib/src/Utilities/HumanSpam/TestContent.php
ADDED
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Utilities\HumanSpam;
|
4 |
+
|
5 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Modules;
|
6 |
+
use FernleafSystems\Wordpress\Services\Services;
|
7 |
+
|
8 |
+
class TestContent {
|
9 |
+
|
10 |
+
use Modules\PluginControllerConsumer;
|
11 |
+
|
12 |
+
/**
|
13 |
+
* @var string[]
|
14 |
+
*/
|
15 |
+
private $list;
|
16 |
+
|
17 |
+
/**
|
18 |
+
* @param array $itemsToTest
|
19 |
+
* @param bool $finishAfterFirst
|
20 |
+
* @return string[][]
|
21 |
+
*/
|
22 |
+
public function findSpam( array $itemsToTest, bool $finishAfterFirst = true ) :array {
|
23 |
+
$spamFound = [];
|
24 |
+
|
25 |
+
$itemsToTest = array_map( 'strval', array_filter( $itemsToTest ) );
|
26 |
+
foreach ( $this->getSpamList() as $word ) {
|
27 |
+
foreach ( $itemsToTest as $key => $item ) {
|
28 |
+
if ( stripos( $item, $word ) !== false ) {
|
29 |
+
|
30 |
+
if ( !isset( $spamFound[ $word ] ) ) {
|
31 |
+
$spamFound[ $word ] = [];
|
32 |
+
}
|
33 |
+
$spamFound[ $word ][ $key ] = $item;
|
34 |
+
|
35 |
+
if ( $finishAfterFirst ) {
|
36 |
+
break 2;
|
37 |
+
}
|
38 |
+
}
|
39 |
+
}
|
40 |
+
}
|
41 |
+
|
42 |
+
return $spamFound;
|
43 |
+
}
|
44 |
+
|
45 |
+
private function getSpamList() :array {
|
46 |
+
if ( empty( $this->list ) ) {
|
47 |
+
$FS = Services::WpFs();
|
48 |
+
$file = $this->getFile();
|
49 |
+
if ( !$FS->exists( $file ) || Services::Request()
|
50 |
+
->ts() - $FS->getModifiedTime( $file ) > WEEK_IN_SECONDS ) {
|
51 |
+
$this->importBlacklist();
|
52 |
+
}
|
53 |
+
$this->list = array_map( 'base64_decode', explode( "\n", $FS->getFileContent( $file, true ) ) );
|
54 |
+
}
|
55 |
+
return $this->list;
|
56 |
+
}
|
57 |
+
|
58 |
+
private function importBlacklist() :bool {
|
59 |
+
$success = false;
|
60 |
+
$mod = $this->getCon()->getModule_Comments();
|
61 |
+
$rawList = Services::HttpRequest()->getContent( $mod->getOptions()->getDef( 'url_spam_blacklist_terms' ) );
|
62 |
+
if ( !empty( $rawList ) ) {
|
63 |
+
$success = Services::WpFs()->putFileContent(
|
64 |
+
$this->getFile(),
|
65 |
+
implode( "\n", array_map( 'base64_encode', array_filter( array_map( 'trim', explode( "\n", $rawList ) ) ) ) ),
|
66 |
+
true
|
67 |
+
);
|
68 |
+
}
|
69 |
+
return $success;
|
70 |
+
}
|
71 |
+
|
72 |
+
private function getFile() :string {
|
73 |
+
return $this->getCon()->getModule_Comments()->getSpamBlacklistFile();
|
74 |
+
}
|
75 |
+
}
|
src/lib/src/Utilities/Options/CleanStorage.php
CHANGED
@@ -10,10 +10,10 @@ class CleanStorage {
|
|
10 |
|
11 |
public function run() {
|
12 |
foreach ( $this->getCon()->modules as $mod ) {
|
13 |
-
$
|
14 |
-
foreach ( array_keys( $
|
15 |
-
if ( !$
|
16 |
-
$
|
17 |
}
|
18 |
}
|
19 |
$mod->saveModOptions();
|
10 |
|
11 |
public function run() {
|
12 |
foreach ( $this->getCon()->modules as $mod ) {
|
13 |
+
$opts = $mod->getOptions();
|
14 |
+
foreach ( array_keys( $opts->getAllOptionsValues() ) as $optKey ) {
|
15 |
+
if ( !$opts->isValidOptionKey( $optKey ) ) {
|
16 |
+
$opts->unsetOpt( $optKey );
|
17 |
}
|
18 |
}
|
19 |
$mod->saveModOptions();
|
src/lib/src/Utilities/ReCaptcha/Enqueue.php
CHANGED
@@ -23,6 +23,9 @@ class Enqueue {
|
|
23 |
}
|
24 |
}
|
25 |
|
|
|
|
|
|
|
26 |
public function onWpEnqueueJs() {
|
27 |
/** @var ModCon $oMod */
|
28 |
$oMod = $this->getMod();
|
@@ -50,10 +53,7 @@ class Enqueue {
|
|
50 |
add_action( 'login_footer', [ $this, 'maybeDequeueRecaptcha' ], -100 );
|
51 |
}
|
52 |
|
53 |
-
|
54 |
-
* @return string
|
55 |
-
*/
|
56 |
-
public function getCaptchaHtml() {
|
57 |
return '<div class="icwpg-recaptcha"></div>';
|
58 |
}
|
59 |
|
23 |
}
|
24 |
}
|
25 |
|
26 |
+
/**
|
27 |
+
* TODO: Consider how to move this to our standardised Enqueue system.
|
28 |
+
*/
|
29 |
public function onWpEnqueueJs() {
|
30 |
/** @var ModCon $oMod */
|
31 |
$oMod = $this->getMod();
|
53 |
add_action( 'login_footer', [ $this, 'maybeDequeueRecaptcha' ], -100 );
|
54 |
}
|
55 |
|
56 |
+
public function getCaptchaHtml() :string {
|
|
|
|
|
|
|
57 |
return '<div class="icwpg-recaptcha"></div>';
|
58 |
}
|
59 |
|
src/lib/src/Utilities/ReCaptcha/TestRequest.php
CHANGED
@@ -32,18 +32,17 @@ class TestRequest {
|
|
32 |
* @throws \Exception
|
33 |
*/
|
34 |
protected function runTest() {
|
35 |
-
/** @var ModCon $mod */
|
36 |
$mod = $this->getMod();
|
37 |
|
38 |
-
$
|
39 |
|
40 |
-
if ( empty( $
|
41 |
throw new \Exception( __( 'Whoops.', 'wp-simple-firewall' ).' '.__( 'CAPTCHA was not submitted.', 'wp-simple-firewall' ), 1 );
|
42 |
}
|
43 |
else {
|
44 |
-
$
|
45 |
-
->verify( $
|
46 |
-
if ( empty( $
|
47 |
$aMsg = [
|
48 |
__( 'Whoops.', 'wp-simple-firewall' ),
|
49 |
__( 'CAPTCHA verification failed.', 'wp-simple-firewall' ),
|
32 |
* @throws \Exception
|
33 |
*/
|
34 |
protected function runTest() {
|
|
|
35 |
$mod = $this->getMod();
|
36 |
|
37 |
+
$captchaResponse = Services::Request()->post( 'g-recaptcha-response' );
|
38 |
|
39 |
+
if ( empty( $captchaResponse ) ) {
|
40 |
throw new \Exception( __( 'Whoops.', 'wp-simple-firewall' ).' '.__( 'CAPTCHA was not submitted.', 'wp-simple-firewall' ), 1 );
|
41 |
}
|
42 |
else {
|
43 |
+
$response = ( new ReCaptcha( $mod->getCaptchaCfg()->secret, new WordpressPost() ) )
|
44 |
+
->verify( $captchaResponse, Services::IP()->getRequestIp() );
|
45 |
+
if ( empty( $response ) || !$response->isSuccess() ) {
|
46 |
$aMsg = [
|
47 |
__( 'Whoops.', 'wp-simple-firewall' ),
|
48 |
__( 'CAPTCHA verification failed.', 'wp-simple-firewall' ),
|
src/lib/src/Utilities/Resources/Dynamic.php
ADDED
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Utilities\Resources;
|
4 |
+
|
5 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Modules\PluginControllerConsumer;
|
6 |
+
use FernleafSystems\Wordpress\Services\Services;
|
7 |
+
|
8 |
+
class Dynamic {
|
9 |
+
|
10 |
+
const RESOURCES_DIR = 'resources';
|
11 |
+
use PluginControllerConsumer;
|
12 |
+
|
13 |
+
public function getBaseDir() :string {
|
14 |
+
return path_join( $this->getCon()->getPluginCachePath(), self::RESOURCES_DIR );
|
15 |
+
}
|
16 |
+
|
17 |
+
public function getResourcePath( string $resource ) :string {
|
18 |
+
$path = path_join( $this->getBaseDir(), $resource );
|
19 |
+
Services::WpFs()->mkdir( dirname( $path ) );
|
20 |
+
return $path;
|
21 |
+
}
|
22 |
+
|
23 |
+
public function getResourceUrl( string $resource ) :string {
|
24 |
+
$this->getResourcePath( $resource );
|
25 |
+
$url = content_url(
|
26 |
+
sprintf( '%s/%s/%s',
|
27 |
+
$this->getCon()->cfg->paths[ 'cache' ],
|
28 |
+
self::RESOURCES_DIR,
|
29 |
+
$resource
|
30 |
+
)
|
31 |
+
);
|
32 |
+
if ( $this->resourceExists( $resource ) ) {
|
33 |
+
$url = add_query_arg(
|
34 |
+
[ 'mtime' => Services::WpFs()->getModifiedTime( $this->getResourcePath( $resource ) ) ],
|
35 |
+
$url
|
36 |
+
);
|
37 |
+
}
|
38 |
+
return $url;
|
39 |
+
}
|
40 |
+
|
41 |
+
public function getModifiedTime( string $res ) :int {
|
42 |
+
return (int)Services::WpFs()->getModifiedTime( $this->getResourcePath( $res ) );
|
43 |
+
}
|
44 |
+
|
45 |
+
public function resourceCreate( string $res, string $content ) {
|
46 |
+
Services::WpFs()->putFileContent( $this->getResourcePath( $res ), $content );
|
47 |
+
}
|
48 |
+
|
49 |
+
public function resourceDelete( string $res ) {
|
50 |
+
Services::WpFs()->deleteFile( $this->getResourcePath( $res ) );
|
51 |
+
}
|
52 |
+
|
53 |
+
public function resourceExists( string $res ) :bool {
|
54 |
+
return Services::WpFs()->exists( $this->getResourcePath( $res ) );
|
55 |
+
}
|
56 |
+
}
|
src/lib/src/Utilities/Time/WorldTimeApi.php
CHANGED
@@ -12,7 +12,7 @@ class WorldTimeApi {
|
|
12 |
*/
|
13 |
public function current() :int {
|
14 |
$raw = Services::HttpRequest()
|
15 |
-
->getContent( 'https://
|
16 |
if ( empty( $raw ) ) {
|
17 |
throw new \Exception( 'Request to World Clock Api Failed' );
|
18 |
}
|
@@ -20,7 +20,7 @@ class WorldTimeApi {
|
|
20 |
if ( empty( $dec ) ) {
|
21 |
throw new \Exception( 'Failed to decode World Clock Api response' );
|
22 |
}
|
23 |
-
return (int)$dec[ '
|
24 |
}
|
25 |
|
26 |
/**
|
12 |
*/
|
13 |
public function current() :int {
|
14 |
$raw = Services::HttpRequest()
|
15 |
+
->getContent( 'https://api.aptoweb.com/api/v1/time' );
|
16 |
if ( empty( $raw ) ) {
|
17 |
throw new \Exception( 'Request to World Clock Api Failed' );
|
18 |
}
|
20 |
if ( empty( $dec ) ) {
|
21 |
throw new \Exception( 'Failed to decode World Clock Api response' );
|
22 |
}
|
23 |
+
return (int)$dec[ 'current' ][ 'seconds' ];
|
24 |
}
|
25 |
|
26 |
/**
|
src/lib/src/Utilities/Tool/DbTableExport.php
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php declare( strict_types=1 );
|
2 |
+
|
3 |
+
namespace FernleafSystems\Wordpress\Plugin\Shield\Utilities\Tool;
|
4 |
+
|
5 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base\EntryVO;
|
6 |
+
use FernleafSystems\Wordpress\Plugin\Shield\Databases\Base\HandlerConsumer;
|
7 |
+
use FernleafSystems\Wordpress\Services\Services;
|
8 |
+
|
9 |
+
class DbTableExport {
|
10 |
+
|
11 |
+
use HandlerConsumer;
|
12 |
+
|
13 |
+
public function toCSV() {
|
14 |
+
$content = [];
|
15 |
+
/** @var EntryVO $entryVO */
|
16 |
+
foreach ( $this->getDbHandler()->getIterator() as $entryVO ) {
|
17 |
+
$content[] = $this->implodeForCSV( $this->getEntryAsRawArray( $entryVO ) );
|
18 |
+
}
|
19 |
+
array_unshift( $content, $this->implodeForCSV( $this->getActualColumns() ) );
|
20 |
+
Services::Response()->downloadStringAsFile( implode( "\n", $content ), $this->getFileName() );
|
21 |
+
}
|
22 |
+
|
23 |
+
protected function implodeForCSV( array $line ) :string {
|
24 |
+
return '"'.implode( '","', $line ).'"';
|
25 |
+
}
|
26 |
+
|
27 |
+
/**
|
28 |
+
* @param EntryVO $entryVO
|
29 |
+
* @return array
|
30 |
+
*/
|
31 |
+
protected function getEntryAsRawArray( $entryVO ) :array {
|
32 |
+
$entry = $entryVO->getRawData();
|
33 |
+
$schema = $this->getDbHandler()->getTableSchema();
|
34 |
+
if ( $schema->is_ip_binary ) {
|
35 |
+
$entry[ 'ip' ] = $entryVO->ip;
|
36 |
+
}
|
37 |
+
if ( $schema->hasColumn( 'meta' ) ) {
|
38 |
+
$entry[ 'meta' ] = serialize( $entryVO->meta );
|
39 |
+
}
|
40 |
+
return $entry;
|
41 |
+
}
|
42 |
+
|
43 |
+
protected function getActualColumns() :array {
|
44 |
+
return Services::WpDb()->getColumnsForTable( $this->getDbHandler()->getTableSchema()->table, 'strtolower' );
|
45 |
+
}
|
46 |
+
|
47 |
+
protected function getFileName() :string {
|
48 |
+
return sprintf( 'table_export-%s-%s.csv', $this->getDbHandler()->getTableSchema()->table, date( 'Ymd_His' ) );
|
49 |
+
}
|
50 |
+
}
|
src/lib/src/Utilities/Tool/IpListSort.php
CHANGED
@@ -9,21 +9,21 @@ namespace FernleafSystems\Wordpress\Plugin\Shield\Utilities\Tool;
|
|
9 |
class IpListSort {
|
10 |
|
11 |
/**
|
12 |
-
* @param string[] $
|
13 |
* @return array
|
14 |
*/
|
15 |
-
public static function Sort( $
|
16 |
-
if ( is_array( $
|
17 |
-
$
|
18 |
return strpos( $sIP, '.' ) > 0;
|
19 |
} );
|
20 |
-
$
|
21 |
return strpos( $sIP, ':' ) > 0;
|
22 |
} );
|
23 |
-
asort( $
|
24 |
-
asort( $
|
25 |
-
$
|
26 |
}
|
27 |
-
return is_array( $
|
28 |
}
|
29 |
}
|
9 |
class IpListSort {
|
10 |
|
11 |
/**
|
12 |
+
* @param string[] $IPs
|
13 |
* @return array
|
14 |
*/
|
15 |
+
public static function Sort( $IPs ) :array {
|
16 |
+
if ( is_array( $IPs ) ) {
|
17 |
+
$ip4 = array_filter( $IPs, function ( $sIP ) {
|
18 |
return strpos( $sIP, '.' ) > 0;
|
19 |
} );
|
20 |
+
$ip6 = array_filter( $IPs, function ( $sIP ) {
|
21 |
return strpos( $sIP, ':' ) > 0;
|
22 |
} );
|
23 |
+
asort( $ip4 );
|
24 |
+
asort( $ip6 );
|
25 |
+
$IPs = array_merge( $ip4, $ip6 );
|
26 |
}
|
27 |
+
return is_array( $IPs ) ? $IPs : [];
|
28 |
}
|
29 |
}
|
src/lib/vendor/composer/autoload_classmap.php
CHANGED
@@ -62,6 +62,7 @@ return array(
|
|
62 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Ajax\\Init' => $baseDir . '/src/Controller/Ajax/Init.php',
|
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\\Urls' => $baseDir . '/src/Controller/Assets/Urls.php',
|
66 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Config\\ConfigVO' => $baseDir . '/src/Controller/Config/ConfigVO.php',
|
67 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Config\\Ops\\LoadConfig' => $baseDir . '/src/Controller/Config/Ops/LoadConfig.php',
|
@@ -70,6 +71,7 @@ return array(
|
|
70 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Controller' => $baseDir . '/src/Controller/Controller.php',
|
71 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\I18n\\GetAllAvailableLocales' => $baseDir . '/src/Controller/I18n/GetAllAvailableLocales.php',
|
72 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\I18n\\LoadTextDomain' => $baseDir . '/src/Controller/I18n/LoadTextDomain.php',
|
|
|
73 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Utilities\\DebugMode' => $baseDir . '/src/Controller/Utilities/DebugMode.php',
|
74 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Utilities\\Upgrade' => $baseDir . '/src/Controller/Utilities/Upgrade.php',
|
75 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Crons\\BaseCron' => $baseDir . '/src/Crons/BaseCron.php',
|
@@ -95,8 +97,17 @@ return array(
|
|
95 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Base\\Handler' => $baseDir . '/src/Databases/Base/Handler.php',
|
96 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Base\\HandlerConsumer' => $baseDir . '/src/Databases/Base/HandlerConsumer.php',
|
97 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Base\\Insert' => $baseDir . '/src/Databases/Base/Insert.php',
|
|
|
98 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Base\\Select' => $baseDir . '/src/Databases/Base/Select.php',
|
|
|
99 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Base\\Update' => $baseDir . '/src/Databases/Base/Update.php',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
100 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\ChangeTracking\\Delete' => $baseDir . '/src/Databases/ChangeTracking/Delete.php',
|
101 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\ChangeTracking\\EntryVO' => $baseDir . '/src/Databases/ChangeTracking/EntryVO.php',
|
102 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\ChangeTracking\\Handler' => $baseDir . '/src/Databases/ChangeTracking/Handler.php',
|
@@ -159,12 +170,6 @@ return array(
|
|
159 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Session\\Insert' => $baseDir . '/src/Databases/Session/Insert.php',
|
160 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Session\\Select' => $baseDir . '/src/Databases/Session/Select.php',
|
161 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Session\\Update' => $baseDir . '/src/Databases/Session/Update.php',
|
162 |
-
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Tally\\Delete' => $baseDir . '/src/Databases/Tally/Delete.php',
|
163 |
-
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Tally\\EntryVO' => $baseDir . '/src/Databases/Tally/EntryVO.php',
|
164 |
-
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Tally\\Handler' => $baseDir . '/src/Databases/Tally/Handler.php',
|
165 |
-
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Tally\\Insert' => $baseDir . '/src/Databases/Tally/Insert.php',
|
166 |
-
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Tally\\Select' => $baseDir . '/src/Databases/Tally/Select.php',
|
167 |
-
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Tally\\Update' => $baseDir . '/src/Databases/Tally/Update.php',
|
168 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Traffic\\BaseTraffic' => $baseDir . '/src/Databases/Traffic/BaseTraffic.php',
|
169 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Traffic\\Delete' => $baseDir . '/src/Databases/Traffic/Delete.php',
|
170 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Traffic\\EntryVO' => $baseDir . '/src/Databases/Traffic/EntryVO.php',
|
@@ -183,6 +188,7 @@ return array(
|
|
183 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Auditors\\Users' => $baseDir . '/src/Modules/AuditTrail/Auditors/Users.php',
|
184 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Auditors\\Wordpress' => $baseDir . '/src/Modules/AuditTrail/Auditors/Wordpress.php',
|
185 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Insights\\OverviewCards' => $baseDir . '/src/Modules/AuditTrail/Insights/OverviewCards.php',
|
|
|
186 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\AuditWriter' => $baseDir . '/src/Modules/AuditTrail/Lib/AuditWriter.php',
|
187 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\Ops\\Commit' => $baseDir . '/src/Modules/AuditTrail/Lib/Ops/Commit.php',
|
188 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\ModCon' => $baseDir . '/src/Modules/AuditTrail/ModCon.php',
|
@@ -203,11 +209,9 @@ return array(
|
|
203 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\ModCon' => $baseDir . '/src/Modules/BaseShield/ModCon.php',
|
204 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\Options' => $baseDir . '/src/Modules/BaseShield/Options.php',
|
205 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\Processor' => $baseDir . '/src/Modules/BaseShield/Processor.php',
|
206 |
-
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\ShieldProcessor' => $baseDir . '/src/Modules/BaseShield/ShieldProcessor.php',
|
207 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\UI' => $baseDir . '/src/Modules/BaseShield/UI.php',
|
208 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\AdminNotices' => $baseDir . '/src/Modules/Base/AdminNotices.php',
|
209 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\AjaxHandler' => $baseDir . '/src/Modules/Base/AjaxHandler.php',
|
210 |
-
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\BaseProcessor' => $baseDir . '/src/Modules/Base/BaseProcessor.php',
|
211 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Debug' => $baseDir . '/src/Modules/Base/Debug.php',
|
212 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Insights\\OverviewCards' => $baseDir . '/src/Modules/Base/Insights/OverviewCards.php',
|
213 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\ModCon' => $baseDir . '/src/Modules/Base/ModCon.php',
|
@@ -229,7 +233,9 @@ return array(
|
|
229 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\ModCon' => $baseDir . '/src/Modules/CommentsFilter/ModCon.php',
|
230 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Options' => $baseDir . '/src/Modules/CommentsFilter/Options.php',
|
231 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Processor' => $baseDir . '/src/Modules/CommentsFilter/Processor.php',
|
|
|
232 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Scan\\Bot' => $baseDir . '/src/Modules/CommentsFilter/Scan/Bot.php',
|
|
|
233 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Scan\\Human' => $baseDir . '/src/Modules/CommentsFilter/Scan/Human.php',
|
234 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Scan\\IsEmailTrusted' => $baseDir . '/src/Modules/CommentsFilter/Scan/IsEmailTrusted.php',
|
235 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Scan\\Scanner' => $baseDir . '/src/Modules/CommentsFilter/Scan/Scanner.php',
|
@@ -246,9 +252,6 @@ return array(
|
|
246 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Email\\Options' => $baseDir . '/src/Modules/Email/Options.php',
|
247 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Email\\Processor' => $baseDir . '/src/Modules/Email/Processor.php',
|
248 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Email\\Strings' => $baseDir . '/src/Modules/Email/Strings.php',
|
249 |
-
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\AjaxHandler' => $baseDir . '/src/Modules/Events/AjaxHandler.php',
|
250 |
-
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Charts\\BuildData' => $baseDir . '/src/Modules/Events/Charts/BuildData.php',
|
251 |
-
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Charts\\ChartRequestVO' => $baseDir . '/src/Modules/Events/Charts/ChartRequestVO.php',
|
252 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Consolidate\\ConsolidateAllEvents' => $baseDir . '/src/Modules/Events/Consolidate/ConsolidateAllEvents.php',
|
253 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Lib\\EventsListener' => $baseDir . '/src/Modules/Events/Lib/EventsListener.php',
|
254 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Lib\\EventsService' => $baseDir . '/src/Modules/Events/Lib/EventsService.php',
|
@@ -351,7 +354,9 @@ return array(
|
|
351 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\AjaxHandler' => $baseDir . '/src/Modules/IPs/AjaxHandler.php',
|
352 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\Base' => $baseDir . '/src/Modules/IPs/BotTrack/Base.php',
|
353 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\Track404' => $baseDir . '/src/Modules/IPs/BotTrack/Track404.php',
|
|
|
354 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\TrackFakeWebCrawler' => $baseDir . '/src/Modules/IPs/BotTrack/TrackFakeWebCrawler.php',
|
|
|
355 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\TrackLinkCheese' => $baseDir . '/src/Modules/IPs/BotTrack/TrackLinkCheese.php',
|
356 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\TrackLoginFailed' => $baseDir . '/src/Modules/IPs/BotTrack/TrackLoginFailed.php',
|
357 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\TrackLoginInvalid' => $baseDir . '/src/Modules/IPs/BotTrack/TrackLoginInvalid.php',
|
@@ -367,6 +372,13 @@ return array(
|
|
367 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\AutoUnblock' => $baseDir . '/src/Modules/IPs/Lib/AutoUnblock.php',
|
368 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\BlacklistHandler' => $baseDir . '/src/Modules/IPs/Lib/BlacklistHandler.php',
|
369 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\BlockRequest' => $baseDir . '/src/Modules/IPs/Lib/BlockRequest.php',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
370 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\IpAnalyse\\BuildDisplay' => $baseDir . '/src/Modules/IPs/Lib/IpAnalyse/BuildDisplay.php',
|
371 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\IpAnalyse\\FindAllPluginIps' => $baseDir . '/src/Modules/IPs/Lib/IpAnalyse/FindAllPluginIps.php',
|
372 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\OffenseTracker' => $baseDir . '/src/Modules/IPs/Lib/OffenseTracker.php',
|
@@ -418,6 +430,19 @@ return array(
|
|
418 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\MainWP\\Server\\UI\\PageRender\\NotShieldPro' => $baseDir . '/src/Modules/Integrations/Lib/MainWP/Server/UI/PageRender/NotShieldPro.php',
|
419 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\MainWP\\Server\\UI\\PageRender\\PluginOutOfDate' => $baseDir . '/src/Modules/Integrations/Lib/MainWP/Server/UI/PageRender/PluginOutOfDate.php',
|
420 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\MainWP\\Server\\UI\\PageRender\\SitesList' => $baseDir . '/src/Modules/Integrations/Lib/MainWP/Server/UI/PageRender/SitesList.php',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
421 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\ModCon' => $baseDir . '/src/Modules/Integrations/ModCon.php',
|
422 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Options' => $baseDir . '/src/Modules/Integrations/Options.php',
|
423 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Processor' => $baseDir . '/src/Modules/Integrations/Processor.php',
|
@@ -460,6 +485,7 @@ return array(
|
|
460 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\AntiBot\\FormProviders\\WPMembers' => $baseDir . '/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/WPMembers.php',
|
461 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\AntiBot\\FormProviders\\WooCommerce' => $baseDir . '/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/WooCommerce.php',
|
462 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\AntiBot\\FormProviders\\WordPress' => $baseDir . '/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/WordPress.php',
|
|
|
463 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\AntiBot\\ProtectionProviders\\BaseProtectionProvider' => $baseDir . '/src/Modules/LoginGuard/Lib/AntiBot/ProtectionProviders/BaseProtectionProvider.php',
|
464 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\AntiBot\\ProtectionProviders\\CoolDown' => $baseDir . '/src/Modules/LoginGuard/Lib/AntiBot/ProtectionProviders/CoolDown.php',
|
465 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\AntiBot\\ProtectionProviders\\GaspJs' => $baseDir . '/src/Modules/LoginGuard/Lib/AntiBot/ProtectionProviders/GaspJs.php',
|
@@ -529,6 +555,12 @@ return array(
|
|
529 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\WpCli\\Import' => $baseDir . '/src/Modules/Plugin/WpCli/Import.php',
|
530 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\WpCli\\Reset' => $baseDir . '/src/Modules/Plugin/WpCli/Reset.php',
|
531 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\WpCli\\ToggleDebug' => $baseDir . '/src/Modules/Plugin/WpCli/ToggleDebug.php',
|
|
|
|
|
|
|
|
|
|
|
|
|
532 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Reporting\\Debug' => $baseDir . '/src/Modules/Reporting/Debug.php',
|
533 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Reporting\\Insights\\OverviewCards' => $baseDir . '/src/Modules/Reporting/Insights/OverviewCards.php',
|
534 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Reporting\\Lib\\ReportingController' => $baseDir . '/src/Modules/Reporting/Lib/ReportingController.php',
|
@@ -745,11 +777,14 @@ return array(
|
|
745 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Consumer\\WpUserConsumer' => $baseDir . '/src/Utilities/Consumer/WpUserConsumer.php',
|
746 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Github\\ListTags' => $baseDir . '/src/Utilities/Github/ListTags.php',
|
747 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\HCaptcha\\TestRequest' => $baseDir . '/src/Utilities/HCaptcha/TestRequest.php',
|
|
|
748 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Options\\CleanStorage' => $baseDir . '/src/Utilities/Options/CleanStorage.php',
|
749 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\ReCaptcha\\Enqueue' => $baseDir . '/src/Utilities/ReCaptcha/Enqueue.php',
|
750 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\ReCaptcha\\TestRequest' => $baseDir . '/src/Utilities/ReCaptcha/TestRequest.php',
|
751 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\ReCaptcha\\WordpressPost' => $baseDir . '/src/Utilities/ReCaptcha/WordpressPost.php',
|
|
|
752 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Time\\WorldTimeApi' => $baseDir . '/src/Utilities/Time/WorldTimeApi.php',
|
|
|
753 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Tool\\FormatBytes' => $baseDir . '/src/Utilities/Tool/FormatBytes.php',
|
754 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Tool\\IpListSort' => $baseDir . '/src/Utilities/Tool/IpListSort.php',
|
755 |
'FernleafSystems\\Wordpress\\Services\\Core\\AdminNotices' => $vendorDir . '/fernleafsystems/wordpress-services/src/Core/AdminNotices.php',
|
@@ -835,6 +870,7 @@ return array(
|
|
835 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Integrations\\WpHashes\\Malware\\Whitelist\\RequestVO' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Malware/Whitelist/RequestVO.php',
|
836 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Integrations\\WpHashes\\Services\\Base' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Services/Base.php',
|
837 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Integrations\\WpHashes\\Services\\IPs' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Services/IPs.php',
|
|
|
838 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Integrations\\WpHashes\\Services\\RequestVO' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Services/RequestVO.php',
|
839 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Integrations\\WpHashes\\Token\\Base' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Token/Base.php',
|
840 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Integrations\\WpHashes\\Token\\RequestVO' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Token/RequestVO.php',
|
@@ -861,6 +897,7 @@ return array(
|
|
861 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Lookup' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Lookup.php',
|
862 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\BaseIP' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Net/BaseIP.php',
|
863 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\FindSourceFromIp' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Net/FindSourceFromIp.php',
|
|
|
864 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\IpIdentify' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Net/IpIdentify.php',
|
865 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\VisitorIpDetection' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Net/VisitorIpDetection.php',
|
866 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Obfuscate' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Obfuscate.php',
|
62 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Ajax\\Init' => $baseDir . '/src/Controller/Ajax/Init.php',
|
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',
|
71 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Controller' => $baseDir . '/src/Controller/Controller.php',
|
72 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\I18n\\GetAllAvailableLocales' => $baseDir . '/src/Controller/I18n/GetAllAvailableLocales.php',
|
73 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\I18n\\LoadTextDomain' => $baseDir . '/src/Controller/I18n/LoadTextDomain.php',
|
74 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Utilities\\CaptureMyUpgrade' => $baseDir . '/src/Controller/Utilities/CaptureMyUpgrade.php',
|
75 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Utilities\\DebugMode' => $baseDir . '/src/Controller/Utilities/DebugMode.php',
|
76 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Utilities\\Upgrade' => $baseDir . '/src/Controller/Utilities/Upgrade.php',
|
77 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Crons\\BaseCron' => $baseDir . '/src/Crons/BaseCron.php',
|
97 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Base\\Handler' => $baseDir . '/src/Databases/Base/Handler.php',
|
98 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Base\\HandlerConsumer' => $baseDir . '/src/Databases/Base/HandlerConsumer.php',
|
99 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Base\\Insert' => $baseDir . '/src/Databases/Base/Insert.php',
|
100 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Base\\Iterator' => $baseDir . '/src/Databases/Base/Iterator.php',
|
101 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Base\\Select' => $baseDir . '/src/Databases/Base/Select.php',
|
102 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Base\\Traits\\Select_IPTable' => $baseDir . '/src/Databases/Base/Traits/Select_IPTable.php',
|
103 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Base\\Update' => $baseDir . '/src/Databases/Base/Update.php',
|
104 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\BotSignals\\Common' => $baseDir . '/src/Databases/BotSignals/Common.php',
|
105 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\BotSignals\\Delete' => $baseDir . '/src/Databases/BotSignals/Delete.php',
|
106 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\BotSignals\\EntryVO' => $baseDir . '/src/Databases/BotSignals/EntryVO.php',
|
107 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\BotSignals\\Handler' => $baseDir . '/src/Databases/BotSignals/Handler.php',
|
108 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\BotSignals\\Insert' => $baseDir . '/src/Databases/BotSignals/Insert.php',
|
109 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\BotSignals\\Select' => $baseDir . '/src/Databases/BotSignals/Select.php',
|
110 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\BotSignals\\Update' => $baseDir . '/src/Databases/BotSignals/Update.php',
|
111 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\ChangeTracking\\Delete' => $baseDir . '/src/Databases/ChangeTracking/Delete.php',
|
112 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\ChangeTracking\\EntryVO' => $baseDir . '/src/Databases/ChangeTracking/EntryVO.php',
|
113 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\ChangeTracking\\Handler' => $baseDir . '/src/Databases/ChangeTracking/Handler.php',
|
170 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Session\\Insert' => $baseDir . '/src/Databases/Session/Insert.php',
|
171 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Session\\Select' => $baseDir . '/src/Databases/Session/Select.php',
|
172 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Session\\Update' => $baseDir . '/src/Databases/Session/Update.php',
|
|
|
|
|
|
|
|
|
|
|
|
|
173 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Traffic\\BaseTraffic' => $baseDir . '/src/Databases/Traffic/BaseTraffic.php',
|
174 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Traffic\\Delete' => $baseDir . '/src/Databases/Traffic/Delete.php',
|
175 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Traffic\\EntryVO' => $baseDir . '/src/Databases/Traffic/EntryVO.php',
|
188 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Auditors\\Users' => $baseDir . '/src/Modules/AuditTrail/Auditors/Users.php',
|
189 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Auditors\\Wordpress' => $baseDir . '/src/Modules/AuditTrail/Auditors/Wordpress.php',
|
190 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Insights\\OverviewCards' => $baseDir . '/src/Modules/AuditTrail/Insights/OverviewCards.php',
|
191 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\AuditMessageBuilder' => $baseDir . '/src/Modules/AuditTrail/Lib/AuditMessageBuilder.php',
|
192 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\AuditWriter' => $baseDir . '/src/Modules/AuditTrail/Lib/AuditWriter.php',
|
193 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\Ops\\Commit' => $baseDir . '/src/Modules/AuditTrail/Lib/Ops/Commit.php',
|
194 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\ModCon' => $baseDir . '/src/Modules/AuditTrail/ModCon.php',
|
209 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\ModCon' => $baseDir . '/src/Modules/BaseShield/ModCon.php',
|
210 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\Options' => $baseDir . '/src/Modules/BaseShield/Options.php',
|
211 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\Processor' => $baseDir . '/src/Modules/BaseShield/Processor.php',
|
|
|
212 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\UI' => $baseDir . '/src/Modules/BaseShield/UI.php',
|
213 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\AdminNotices' => $baseDir . '/src/Modules/Base/AdminNotices.php',
|
214 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\AjaxHandler' => $baseDir . '/src/Modules/Base/AjaxHandler.php',
|
|
|
215 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Debug' => $baseDir . '/src/Modules/Base/Debug.php',
|
216 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Insights\\OverviewCards' => $baseDir . '/src/Modules/Base/Insights/OverviewCards.php',
|
217 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\ModCon' => $baseDir . '/src/Modules/Base/ModCon.php',
|
233 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\ModCon' => $baseDir . '/src/Modules/CommentsFilter/ModCon.php',
|
234 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Options' => $baseDir . '/src/Modules/CommentsFilter/Options.php',
|
235 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Processor' => $baseDir . '/src/Modules/CommentsFilter/Processor.php',
|
236 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Scan\\AntiBot' => $baseDir . '/src/Modules/CommentsFilter/Scan/AntiBot.php',
|
237 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Scan\\Bot' => $baseDir . '/src/Modules/CommentsFilter/Scan/Bot.php',
|
238 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Scan\\CommentAdditiveCleaner' => $baseDir . '/src/Modules/CommentsFilter/Scan/CommentAdditiveCleaner.php',
|
239 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Scan\\Human' => $baseDir . '/src/Modules/CommentsFilter/Scan/Human.php',
|
240 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Scan\\IsEmailTrusted' => $baseDir . '/src/Modules/CommentsFilter/Scan/IsEmailTrusted.php',
|
241 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Scan\\Scanner' => $baseDir . '/src/Modules/CommentsFilter/Scan/Scanner.php',
|
252 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Email\\Options' => $baseDir . '/src/Modules/Email/Options.php',
|
253 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Email\\Processor' => $baseDir . '/src/Modules/Email/Processor.php',
|
254 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Email\\Strings' => $baseDir . '/src/Modules/Email/Strings.php',
|
|
|
|
|
|
|
255 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Consolidate\\ConsolidateAllEvents' => $baseDir . '/src/Modules/Events/Consolidate/ConsolidateAllEvents.php',
|
256 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Lib\\EventsListener' => $baseDir . '/src/Modules/Events/Lib/EventsListener.php',
|
257 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Lib\\EventsService' => $baseDir . '/src/Modules/Events/Lib/EventsService.php',
|
354 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\AjaxHandler' => $baseDir . '/src/Modules/IPs/AjaxHandler.php',
|
355 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\Base' => $baseDir . '/src/Modules/IPs/BotTrack/Base.php',
|
356 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\Track404' => $baseDir . '/src/Modules/IPs/BotTrack/Track404.php',
|
357 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\TrackCommentSpam' => $baseDir . '/src/Modules/IPs/BotTrack/TrackCommentSpam.php',
|
358 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\TrackFakeWebCrawler' => $baseDir . '/src/Modules/IPs/BotTrack/TrackFakeWebCrawler.php',
|
359 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\TrackInvalidScriptLoad' => $baseDir . '/src/Modules/IPs/BotTrack/TrackInvalidScriptLoad.php',
|
360 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\TrackLinkCheese' => $baseDir . '/src/Modules/IPs/BotTrack/TrackLinkCheese.php',
|
361 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\TrackLoginFailed' => $baseDir . '/src/Modules/IPs/BotTrack/TrackLoginFailed.php',
|
362 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\TrackLoginInvalid' => $baseDir . '/src/Modules/IPs/BotTrack/TrackLoginInvalid.php',
|
372 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\AutoUnblock' => $baseDir . '/src/Modules/IPs/Lib/AutoUnblock.php',
|
373 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\BlacklistHandler' => $baseDir . '/src/Modules/IPs/Lib/BlacklistHandler.php',
|
374 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\BlockRequest' => $baseDir . '/src/Modules/IPs/Lib/BlockRequest.php',
|
375 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\BotSignalsController' => $baseDir . '/src/Modules/IPs/Lib/Bots/BotSignalsController.php',
|
376 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\BotSignalsRecord' => $baseDir . '/src/Modules/IPs/Lib/Bots/BotSignalsRecord.php',
|
377 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\Calculator\\BuildScores' => $baseDir . '/src/Modules/IPs/Lib/Bots/Calculator/BuildScores.php',
|
378 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\Calculator\\CalculateVisitorBotScores' => $baseDir . '/src/Modules/IPs/Lib/Bots/Calculator/CalculateVisitorBotScores.php',
|
379 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\EventListener' => $baseDir . '/src/Modules/IPs/Lib/Bots/EventListener.php',
|
380 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\NotBot\\InsertNotBotJs' => $baseDir . '/src/Modules/IPs/Lib/Bots/NotBot/InsertNotBotJs.php',
|
381 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\NotBot\\NotBotHandler' => $baseDir . '/src/Modules/IPs/Lib/Bots/NotBot/NotBotHandler.php',
|
382 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\IpAnalyse\\BuildDisplay' => $baseDir . '/src/Modules/IPs/Lib/IpAnalyse/BuildDisplay.php',
|
383 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\IpAnalyse\\FindAllPluginIps' => $baseDir . '/src/Modules/IPs/Lib/IpAnalyse/FindAllPluginIps.php',
|
384 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\OffenseTracker' => $baseDir . '/src/Modules/IPs/Lib/OffenseTracker.php',
|
430 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\MainWP\\Server\\UI\\PageRender\\NotShieldPro' => $baseDir . '/src/Modules/Integrations/Lib/MainWP/Server/UI/PageRender/NotShieldPro.php',
|
431 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\MainWP\\Server\\UI\\PageRender\\PluginOutOfDate' => $baseDir . '/src/Modules/Integrations/Lib/MainWP/Server/UI/PageRender/PluginOutOfDate.php',
|
432 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\MainWP\\Server\\UI\\PageRender\\SitesList' => $baseDir . '/src/Modules/Integrations/Lib/MainWP/Server/UI/PageRender/SitesList.php',
|
433 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Spam\\Handlers\\Base' => $baseDir . '/src/Modules/Integrations/Lib/Spam/Handlers/Base.php',
|
434 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Spam\\Handlers\\ContactForm7' => $baseDir . '/src/Modules/Integrations/Lib/Spam/Handlers/ContactForm7.php',
|
435 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Spam\\Handlers\\ElementorPro' => $baseDir . '/src/Modules/Integrations/Lib/Spam/Handlers/ElementorPro.php',
|
436 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Spam\\Handlers\\FluentForms' => $baseDir . '/src/Modules/Integrations/Lib/Spam/Handlers/FluentForms.php',
|
437 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Spam\\Handlers\\FormidableForms' => $baseDir . '/src/Modules/Integrations/Lib/Spam/Handlers/FormidableForms.php',
|
438 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Spam\\Handlers\\Forminator' => $baseDir . '/src/Modules/Integrations/Lib/Spam/Handlers/Forminator.php',
|
439 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Spam\\Handlers\\GravityForms' => $baseDir . '/src/Modules/Integrations/Lib/Spam/Handlers/GravityForms.php',
|
440 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Spam\\Handlers\\Helpers\\NinjaForms_ShieldSpamAction' => $baseDir . '/src/Modules/Integrations/Lib/Spam/Handlers/Helpers/NinjaForms_ShieldSpamAction.php',
|
441 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Spam\\Handlers\\KaliForms' => $baseDir . '/src/Modules/Integrations/Lib/Spam/Handlers/KaliForms.php',
|
442 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Spam\\Handlers\\NinjaForms' => $baseDir . '/src/Modules/Integrations/Lib/Spam/Handlers/NinjaForms.php',
|
443 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Spam\\Handlers\\WPForms' => $baseDir . '/src/Modules/Integrations/Lib/Spam/Handlers/WPForms.php',
|
444 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Spam\\Handlers\\WpForo' => $baseDir . '/src/Modules/Integrations/Lib/Spam/Handlers/WpForo.php',
|
445 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Spam\\SpamController' => $baseDir . '/src/Modules/Integrations/Lib/Spam/SpamController.php',
|
446 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\ModCon' => $baseDir . '/src/Modules/Integrations/ModCon.php',
|
447 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Options' => $baseDir . '/src/Modules/Integrations/Options.php',
|
448 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Processor' => $baseDir . '/src/Modules/Integrations/Processor.php',
|
485 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\AntiBot\\FormProviders\\WPMembers' => $baseDir . '/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/WPMembers.php',
|
486 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\AntiBot\\FormProviders\\WooCommerce' => $baseDir . '/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/WooCommerce.php',
|
487 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\AntiBot\\FormProviders\\WordPress' => $baseDir . '/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/WordPress.php',
|
488 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\AntiBot\\ProtectionProviders\\AntiBot' => $baseDir . '/src/Modules/LoginGuard/Lib/AntiBot/ProtectionProviders/AntiBot.php',
|
489 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\AntiBot\\ProtectionProviders\\BaseProtectionProvider' => $baseDir . '/src/Modules/LoginGuard/Lib/AntiBot/ProtectionProviders/BaseProtectionProvider.php',
|
490 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\AntiBot\\ProtectionProviders\\CoolDown' => $baseDir . '/src/Modules/LoginGuard/Lib/AntiBot/ProtectionProviders/CoolDown.php',
|
491 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\AntiBot\\ProtectionProviders\\GaspJs' => $baseDir . '/src/Modules/LoginGuard/Lib/AntiBot/ProtectionProviders/GaspJs.php',
|
555 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\WpCli\\Import' => $baseDir . '/src/Modules/Plugin/WpCli/Import.php',
|
556 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\WpCli\\Reset' => $baseDir . '/src/Modules/Plugin/WpCli/Reset.php',
|
557 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\WpCli\\ToggleDebug' => $baseDir . '/src/Modules/Plugin/WpCli/ToggleDebug.php',
|
558 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Reporting\\AjaxHandler' => $baseDir . '/src/Modules/Reporting/AjaxHandler.php',
|
559 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Reporting\\Charts\\BaseBuildChartData' => $baseDir . '/src/Modules/Reporting/Charts/BaseBuildChartData.php',
|
560 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Reporting\\Charts\\ChartRequestConsumer' => $baseDir . '/src/Modules/Reporting/Charts/ChartRequestConsumer.php',
|
561 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Reporting\\Charts\\ChartRequestVO' => $baseDir . '/src/Modules/Reporting/Charts/ChartRequestVO.php',
|
562 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Reporting\\Charts\\CustomChartData' => $baseDir . '/src/Modules/Reporting/Charts/CustomChartData.php',
|
563 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Reporting\\Charts\\CustomChartRequestVO' => $baseDir . '/src/Modules/Reporting/Charts/CustomChartRequestVO.php',
|
564 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Reporting\\Debug' => $baseDir . '/src/Modules/Reporting/Debug.php',
|
565 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Reporting\\Insights\\OverviewCards' => $baseDir . '/src/Modules/Reporting/Insights/OverviewCards.php',
|
566 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Reporting\\Lib\\ReportingController' => $baseDir . '/src/Modules/Reporting/Lib/ReportingController.php',
|
777 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Consumer\\WpUserConsumer' => $baseDir . '/src/Utilities/Consumer/WpUserConsumer.php',
|
778 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Github\\ListTags' => $baseDir . '/src/Utilities/Github/ListTags.php',
|
779 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\HCaptcha\\TestRequest' => $baseDir . '/src/Utilities/HCaptcha/TestRequest.php',
|
780 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\HumanSpam\\TestContent' => $baseDir . '/src/Utilities/HumanSpam/TestContent.php',
|
781 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Options\\CleanStorage' => $baseDir . '/src/Utilities/Options/CleanStorage.php',
|
782 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\ReCaptcha\\Enqueue' => $baseDir . '/src/Utilities/ReCaptcha/Enqueue.php',
|
783 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\ReCaptcha\\TestRequest' => $baseDir . '/src/Utilities/ReCaptcha/TestRequest.php',
|
784 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\ReCaptcha\\WordpressPost' => $baseDir . '/src/Utilities/ReCaptcha/WordpressPost.php',
|
785 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Resources\\Dynamic' => $baseDir . '/src/Utilities/Resources/Dynamic.php',
|
786 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Time\\WorldTimeApi' => $baseDir . '/src/Utilities/Time/WorldTimeApi.php',
|
787 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Tool\\DbTableExport' => $baseDir . '/src/Utilities/Tool/DbTableExport.php',
|
788 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Tool\\FormatBytes' => $baseDir . '/src/Utilities/Tool/FormatBytes.php',
|
789 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Tool\\IpListSort' => $baseDir . '/src/Utilities/Tool/IpListSort.php',
|
790 |
'FernleafSystems\\Wordpress\\Services\\Core\\AdminNotices' => $vendorDir . '/fernleafsystems/wordpress-services/src/Core/AdminNotices.php',
|
870 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Integrations\\WpHashes\\Malware\\Whitelist\\RequestVO' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Malware/Whitelist/RequestVO.php',
|
871 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Integrations\\WpHashes\\Services\\Base' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Services/Base.php',
|
872 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Integrations\\WpHashes\\Services\\IPs' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Services/IPs.php',
|
873 |
+
'FernleafSystems\\Wordpress\\Services\\Utilities\\Integrations\\WpHashes\\Services\\ProviderIPs' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Services/ProviderIPs.php',
|
874 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Integrations\\WpHashes\\Services\\RequestVO' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Services/RequestVO.php',
|
875 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Integrations\\WpHashes\\Token\\Base' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Token/Base.php',
|
876 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Integrations\\WpHashes\\Token\\RequestVO' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Token/RequestVO.php',
|
897 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Lookup' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Lookup.php',
|
898 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\BaseIP' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Net/BaseIP.php',
|
899 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\FindSourceFromIp' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Net/FindSourceFromIp.php',
|
900 |
+
'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\IpID' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Net/IpID.php',
|
901 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\IpIdentify' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Net/IpIdentify.php',
|
902 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\VisitorIpDetection' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Net/VisitorIpDetection.php',
|
903 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Obfuscate' => $vendorDir . '/fernleafsystems/wordpress-services/src/Utilities/Obfuscate.php',
|
src/lib/vendor/composer/autoload_files.php
CHANGED
@@ -10,4 +10,5 @@ return array(
|
|
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 |
);
|
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',
|
14 |
);
|
src/lib/vendor/composer/autoload_static.php
CHANGED
@@ -11,6 +11,7 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
|
|
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 |
);
|
15 |
|
16 |
public static $prefixLengthsPsr4 = array (
|
@@ -229,6 +230,7 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
|
|
229 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Ajax\\Init' => __DIR__ . '/../..' . '/src/Controller/Ajax/Init.php',
|
230 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Ajax\\Response' => __DIR__ . '/../..' . '/src/Controller/Ajax/Response.php',
|
231 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Assets\\Enqueue' => __DIR__ . '/../..' . '/src/Controller/Assets/Enqueue.php',
|
|
|
232 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Assets\\Urls' => __DIR__ . '/../..' . '/src/Controller/Assets/Urls.php',
|
233 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Config\\ConfigVO' => __DIR__ . '/../..' . '/src/Controller/Config/ConfigVO.php',
|
234 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Config\\Ops\\LoadConfig' => __DIR__ . '/../..' . '/src/Controller/Config/Ops/LoadConfig.php',
|
@@ -237,6 +239,7 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
|
|
237 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Controller' => __DIR__ . '/../..' . '/src/Controller/Controller.php',
|
238 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\I18n\\GetAllAvailableLocales' => __DIR__ . '/../..' . '/src/Controller/I18n/GetAllAvailableLocales.php',
|
239 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\I18n\\LoadTextDomain' => __DIR__ . '/../..' . '/src/Controller/I18n/LoadTextDomain.php',
|
|
|
240 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Utilities\\DebugMode' => __DIR__ . '/../..' . '/src/Controller/Utilities/DebugMode.php',
|
241 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Utilities\\Upgrade' => __DIR__ . '/../..' . '/src/Controller/Utilities/Upgrade.php',
|
242 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Crons\\BaseCron' => __DIR__ . '/../..' . '/src/Crons/BaseCron.php',
|
@@ -262,8 +265,17 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
|
|
262 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Base\\Handler' => __DIR__ . '/../..' . '/src/Databases/Base/Handler.php',
|
263 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Base\\HandlerConsumer' => __DIR__ . '/../..' . '/src/Databases/Base/HandlerConsumer.php',
|
264 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Base\\Insert' => __DIR__ . '/../..' . '/src/Databases/Base/Insert.php',
|
|
|
265 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Base\\Select' => __DIR__ . '/../..' . '/src/Databases/Base/Select.php',
|
|
|
266 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Base\\Update' => __DIR__ . '/../..' . '/src/Databases/Base/Update.php',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
267 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\ChangeTracking\\Delete' => __DIR__ . '/../..' . '/src/Databases/ChangeTracking/Delete.php',
|
268 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\ChangeTracking\\EntryVO' => __DIR__ . '/../..' . '/src/Databases/ChangeTracking/EntryVO.php',
|
269 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\ChangeTracking\\Handler' => __DIR__ . '/../..' . '/src/Databases/ChangeTracking/Handler.php',
|
@@ -326,12 +338,6 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
|
|
326 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Session\\Insert' => __DIR__ . '/../..' . '/src/Databases/Session/Insert.php',
|
327 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Session\\Select' => __DIR__ . '/../..' . '/src/Databases/Session/Select.php',
|
328 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Session\\Update' => __DIR__ . '/../..' . '/src/Databases/Session/Update.php',
|
329 |
-
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Tally\\Delete' => __DIR__ . '/../..' . '/src/Databases/Tally/Delete.php',
|
330 |
-
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Tally\\EntryVO' => __DIR__ . '/../..' . '/src/Databases/Tally/EntryVO.php',
|
331 |
-
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Tally\\Handler' => __DIR__ . '/../..' . '/src/Databases/Tally/Handler.php',
|
332 |
-
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Tally\\Insert' => __DIR__ . '/../..' . '/src/Databases/Tally/Insert.php',
|
333 |
-
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Tally\\Select' => __DIR__ . '/../..' . '/src/Databases/Tally/Select.php',
|
334 |
-
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Tally\\Update' => __DIR__ . '/../..' . '/src/Databases/Tally/Update.php',
|
335 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Traffic\\BaseTraffic' => __DIR__ . '/../..' . '/src/Databases/Traffic/BaseTraffic.php',
|
336 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Traffic\\Delete' => __DIR__ . '/../..' . '/src/Databases/Traffic/Delete.php',
|
337 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Traffic\\EntryVO' => __DIR__ . '/../..' . '/src/Databases/Traffic/EntryVO.php',
|
@@ -350,6 +356,7 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
|
|
350 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Auditors\\Users' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/Auditors/Users.php',
|
351 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Auditors\\Wordpress' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/Auditors/Wordpress.php',
|
352 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Insights\\OverviewCards' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/Insights/OverviewCards.php',
|
|
|
353 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\AuditWriter' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/Lib/AuditWriter.php',
|
354 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\Ops\\Commit' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/Lib/Ops/Commit.php',
|
355 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\ModCon' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/ModCon.php',
|
@@ -370,11 +377,9 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
|
|
370 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\ModCon' => __DIR__ . '/../..' . '/src/Modules/BaseShield/ModCon.php',
|
371 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\Options' => __DIR__ . '/../..' . '/src/Modules/BaseShield/Options.php',
|
372 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\Processor' => __DIR__ . '/../..' . '/src/Modules/BaseShield/Processor.php',
|
373 |
-
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\ShieldProcessor' => __DIR__ . '/../..' . '/src/Modules/BaseShield/ShieldProcessor.php',
|
374 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\UI' => __DIR__ . '/../..' . '/src/Modules/BaseShield/UI.php',
|
375 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\AdminNotices' => __DIR__ . '/../..' . '/src/Modules/Base/AdminNotices.php',
|
376 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\AjaxHandler' => __DIR__ . '/../..' . '/src/Modules/Base/AjaxHandler.php',
|
377 |
-
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\BaseProcessor' => __DIR__ . '/../..' . '/src/Modules/Base/BaseProcessor.php',
|
378 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Debug' => __DIR__ . '/../..' . '/src/Modules/Base/Debug.php',
|
379 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Insights\\OverviewCards' => __DIR__ . '/../..' . '/src/Modules/Base/Insights/OverviewCards.php',
|
380 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\ModCon' => __DIR__ . '/../..' . '/src/Modules/Base/ModCon.php',
|
@@ -396,7 +401,9 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
|
|
396 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\ModCon' => __DIR__ . '/../..' . '/src/Modules/CommentsFilter/ModCon.php',
|
397 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Options' => __DIR__ . '/../..' . '/src/Modules/CommentsFilter/Options.php',
|
398 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Processor' => __DIR__ . '/../..' . '/src/Modules/CommentsFilter/Processor.php',
|
|
|
399 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Scan\\Bot' => __DIR__ . '/../..' . '/src/Modules/CommentsFilter/Scan/Bot.php',
|
|
|
400 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Scan\\Human' => __DIR__ . '/../..' . '/src/Modules/CommentsFilter/Scan/Human.php',
|
401 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Scan\\IsEmailTrusted' => __DIR__ . '/../..' . '/src/Modules/CommentsFilter/Scan/IsEmailTrusted.php',
|
402 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Scan\\Scanner' => __DIR__ . '/../..' . '/src/Modules/CommentsFilter/Scan/Scanner.php',
|
@@ -413,9 +420,6 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
|
|
413 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Email\\Options' => __DIR__ . '/../..' . '/src/Modules/Email/Options.php',
|
414 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Email\\Processor' => __DIR__ . '/../..' . '/src/Modules/Email/Processor.php',
|
415 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Email\\Strings' => __DIR__ . '/../..' . '/src/Modules/Email/Strings.php',
|
416 |
-
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\AjaxHandler' => __DIR__ . '/../..' . '/src/Modules/Events/AjaxHandler.php',
|
417 |
-
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Charts\\BuildData' => __DIR__ . '/../..' . '/src/Modules/Events/Charts/BuildData.php',
|
418 |
-
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Charts\\ChartRequestVO' => __DIR__ . '/../..' . '/src/Modules/Events/Charts/ChartRequestVO.php',
|
419 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Consolidate\\ConsolidateAllEvents' => __DIR__ . '/../..' . '/src/Modules/Events/Consolidate/ConsolidateAllEvents.php',
|
420 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Lib\\EventsListener' => __DIR__ . '/../..' . '/src/Modules/Events/Lib/EventsListener.php',
|
421 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Lib\\EventsService' => __DIR__ . '/../..' . '/src/Modules/Events/Lib/EventsService.php',
|
@@ -518,7 +522,9 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
|
|
518 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\AjaxHandler' => __DIR__ . '/../..' . '/src/Modules/IPs/AjaxHandler.php',
|
519 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\Base' => __DIR__ . '/../..' . '/src/Modules/IPs/BotTrack/Base.php',
|
520 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\Track404' => __DIR__ . '/../..' . '/src/Modules/IPs/BotTrack/Track404.php',
|
|
|
521 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\TrackFakeWebCrawler' => __DIR__ . '/../..' . '/src/Modules/IPs/BotTrack/TrackFakeWebCrawler.php',
|
|
|
522 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\TrackLinkCheese' => __DIR__ . '/../..' . '/src/Modules/IPs/BotTrack/TrackLinkCheese.php',
|
523 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\TrackLoginFailed' => __DIR__ . '/../..' . '/src/Modules/IPs/BotTrack/TrackLoginFailed.php',
|
524 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\TrackLoginInvalid' => __DIR__ . '/../..' . '/src/Modules/IPs/BotTrack/TrackLoginInvalid.php',
|
@@ -534,6 +540,13 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
|
|
534 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\AutoUnblock' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/AutoUnblock.php',
|
535 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\BlacklistHandler' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/BlacklistHandler.php',
|
536 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\BlockRequest' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/BlockRequest.php',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
537 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\IpAnalyse\\BuildDisplay' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/IpAnalyse/BuildDisplay.php',
|
538 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\IpAnalyse\\FindAllPluginIps' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/IpAnalyse/FindAllPluginIps.php',
|
539 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\OffenseTracker' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/OffenseTracker.php',
|
@@ -585,6 +598,19 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
|
|
585 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\MainWP\\Server\\UI\\PageRender\\NotShieldPro' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/MainWP/Server/UI/PageRender/NotShieldPro.php',
|
586 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\MainWP\\Server\\UI\\PageRender\\PluginOutOfDate' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/MainWP/Server/UI/PageRender/PluginOutOfDate.php',
|
587 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\MainWP\\Server\\UI\\PageRender\\SitesList' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/MainWP/Server/UI/PageRender/SitesList.php',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
588 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\ModCon' => __DIR__ . '/../..' . '/src/Modules/Integrations/ModCon.php',
|
589 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Options' => __DIR__ . '/../..' . '/src/Modules/Integrations/Options.php',
|
590 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Processor' => __DIR__ . '/../..' . '/src/Modules/Integrations/Processor.php',
|
@@ -627,6 +653,7 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
|
|
627 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\AntiBot\\FormProviders\\WPMembers' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/WPMembers.php',
|
628 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\AntiBot\\FormProviders\\WooCommerce' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/WooCommerce.php',
|
629 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\AntiBot\\FormProviders\\WordPress' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/WordPress.php',
|
|
|
630 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\AntiBot\\ProtectionProviders\\BaseProtectionProvider' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/AntiBot/ProtectionProviders/BaseProtectionProvider.php',
|
631 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\AntiBot\\ProtectionProviders\\CoolDown' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/AntiBot/ProtectionProviders/CoolDown.php',
|
632 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\AntiBot\\ProtectionProviders\\GaspJs' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/AntiBot/ProtectionProviders/GaspJs.php',
|
@@ -696,6 +723,12 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
|
|
696 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\WpCli\\Import' => __DIR__ . '/../..' . '/src/Modules/Plugin/WpCli/Import.php',
|
697 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\WpCli\\Reset' => __DIR__ . '/../..' . '/src/Modules/Plugin/WpCli/Reset.php',
|
698 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\WpCli\\ToggleDebug' => __DIR__ . '/../..' . '/src/Modules/Plugin/WpCli/ToggleDebug.php',
|
|
|
|
|
|
|
|
|
|
|
|
|
699 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Reporting\\Debug' => __DIR__ . '/../..' . '/src/Modules/Reporting/Debug.php',
|
700 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Reporting\\Insights\\OverviewCards' => __DIR__ . '/../..' . '/src/Modules/Reporting/Insights/OverviewCards.php',
|
701 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Reporting\\Lib\\ReportingController' => __DIR__ . '/../..' . '/src/Modules/Reporting/Lib/ReportingController.php',
|
@@ -912,11 +945,14 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
|
|
912 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Consumer\\WpUserConsumer' => __DIR__ . '/../..' . '/src/Utilities/Consumer/WpUserConsumer.php',
|
913 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Github\\ListTags' => __DIR__ . '/../..' . '/src/Utilities/Github/ListTags.php',
|
914 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\HCaptcha\\TestRequest' => __DIR__ . '/../..' . '/src/Utilities/HCaptcha/TestRequest.php',
|
|
|
915 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Options\\CleanStorage' => __DIR__ . '/../..' . '/src/Utilities/Options/CleanStorage.php',
|
916 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\ReCaptcha\\Enqueue' => __DIR__ . '/../..' . '/src/Utilities/ReCaptcha/Enqueue.php',
|
917 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\ReCaptcha\\TestRequest' => __DIR__ . '/../..' . '/src/Utilities/ReCaptcha/TestRequest.php',
|
918 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\ReCaptcha\\WordpressPost' => __DIR__ . '/../..' . '/src/Utilities/ReCaptcha/WordpressPost.php',
|
|
|
919 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Time\\WorldTimeApi' => __DIR__ . '/../..' . '/src/Utilities/Time/WorldTimeApi.php',
|
|
|
920 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Tool\\FormatBytes' => __DIR__ . '/../..' . '/src/Utilities/Tool/FormatBytes.php',
|
921 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Tool\\IpListSort' => __DIR__ . '/../..' . '/src/Utilities/Tool/IpListSort.php',
|
922 |
'FernleafSystems\\Wordpress\\Services\\Core\\AdminNotices' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Core/AdminNotices.php',
|
@@ -1002,6 +1038,7 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
|
|
1002 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Integrations\\WpHashes\\Malware\\Whitelist\\RequestVO' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Malware/Whitelist/RequestVO.php',
|
1003 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Integrations\\WpHashes\\Services\\Base' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Services/Base.php',
|
1004 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Integrations\\WpHashes\\Services\\IPs' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Services/IPs.php',
|
|
|
1005 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Integrations\\WpHashes\\Services\\RequestVO' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Services/RequestVO.php',
|
1006 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Integrations\\WpHashes\\Token\\Base' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Token/Base.php',
|
1007 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Integrations\\WpHashes\\Token\\RequestVO' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Token/RequestVO.php',
|
@@ -1028,6 +1065,7 @@ class ComposerStaticInit4fc2c6daaffaf40b64b79b6d26830171
|
|
1028 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Lookup' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Lookup.php',
|
1029 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\BaseIP' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Net/BaseIP.php',
|
1030 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\FindSourceFromIp' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Net/FindSourceFromIp.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',
|
15 |
);
|
16 |
|
17 |
public static $prefixLengthsPsr4 = array (
|
230 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Ajax\\Init' => __DIR__ . '/../..' . '/src/Controller/Ajax/Init.php',
|
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',
|
239 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Controller' => __DIR__ . '/../..' . '/src/Controller/Controller.php',
|
240 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\I18n\\GetAllAvailableLocales' => __DIR__ . '/../..' . '/src/Controller/I18n/GetAllAvailableLocales.php',
|
241 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\I18n\\LoadTextDomain' => __DIR__ . '/../..' . '/src/Controller/I18n/LoadTextDomain.php',
|
242 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Utilities\\CaptureMyUpgrade' => __DIR__ . '/../..' . '/src/Controller/Utilities/CaptureMyUpgrade.php',
|
243 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Utilities\\DebugMode' => __DIR__ . '/../..' . '/src/Controller/Utilities/DebugMode.php',
|
244 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Controller\\Utilities\\Upgrade' => __DIR__ . '/../..' . '/src/Controller/Utilities/Upgrade.php',
|
245 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Crons\\BaseCron' => __DIR__ . '/../..' . '/src/Crons/BaseCron.php',
|
265 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Base\\Handler' => __DIR__ . '/../..' . '/src/Databases/Base/Handler.php',
|
266 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Base\\HandlerConsumer' => __DIR__ . '/../..' . '/src/Databases/Base/HandlerConsumer.php',
|
267 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Base\\Insert' => __DIR__ . '/../..' . '/src/Databases/Base/Insert.php',
|
268 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Base\\Iterator' => __DIR__ . '/../..' . '/src/Databases/Base/Iterator.php',
|
269 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Base\\Select' => __DIR__ . '/../..' . '/src/Databases/Base/Select.php',
|
270 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Base\\Traits\\Select_IPTable' => __DIR__ . '/../..' . '/src/Databases/Base/Traits/Select_IPTable.php',
|
271 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Base\\Update' => __DIR__ . '/../..' . '/src/Databases/Base/Update.php',
|
272 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\BotSignals\\Common' => __DIR__ . '/../..' . '/src/Databases/BotSignals/Common.php',
|
273 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\BotSignals\\Delete' => __DIR__ . '/../..' . '/src/Databases/BotSignals/Delete.php',
|
274 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\BotSignals\\EntryVO' => __DIR__ . '/../..' . '/src/Databases/BotSignals/EntryVO.php',
|
275 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\BotSignals\\Handler' => __DIR__ . '/../..' . '/src/Databases/BotSignals/Handler.php',
|
276 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\BotSignals\\Insert' => __DIR__ . '/../..' . '/src/Databases/BotSignals/Insert.php',
|
277 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\BotSignals\\Select' => __DIR__ . '/../..' . '/src/Databases/BotSignals/Select.php',
|
278 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\BotSignals\\Update' => __DIR__ . '/../..' . '/src/Databases/BotSignals/Update.php',
|
279 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\ChangeTracking\\Delete' => __DIR__ . '/../..' . '/src/Databases/ChangeTracking/Delete.php',
|
280 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\ChangeTracking\\EntryVO' => __DIR__ . '/../..' . '/src/Databases/ChangeTracking/EntryVO.php',
|
281 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\ChangeTracking\\Handler' => __DIR__ . '/../..' . '/src/Databases/ChangeTracking/Handler.php',
|
338 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Session\\Insert' => __DIR__ . '/../..' . '/src/Databases/Session/Insert.php',
|
339 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Session\\Select' => __DIR__ . '/../..' . '/src/Databases/Session/Select.php',
|
340 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Session\\Update' => __DIR__ . '/../..' . '/src/Databases/Session/Update.php',
|
|
|
|
|
|
|
|
|
|
|
|
|
341 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Traffic\\BaseTraffic' => __DIR__ . '/../..' . '/src/Databases/Traffic/BaseTraffic.php',
|
342 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Traffic\\Delete' => __DIR__ . '/../..' . '/src/Databases/Traffic/Delete.php',
|
343 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Databases\\Traffic\\EntryVO' => __DIR__ . '/../..' . '/src/Databases/Traffic/EntryVO.php',
|
356 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Auditors\\Users' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/Auditors/Users.php',
|
357 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Auditors\\Wordpress' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/Auditors/Wordpress.php',
|
358 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Insights\\OverviewCards' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/Insights/OverviewCards.php',
|
359 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\AuditMessageBuilder' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/Lib/AuditMessageBuilder.php',
|
360 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\AuditWriter' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/Lib/AuditWriter.php',
|
361 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\Lib\\Ops\\Commit' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/Lib/Ops/Commit.php',
|
362 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\AuditTrail\\ModCon' => __DIR__ . '/../..' . '/src/Modules/AuditTrail/ModCon.php',
|
377 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\ModCon' => __DIR__ . '/../..' . '/src/Modules/BaseShield/ModCon.php',
|
378 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\Options' => __DIR__ . '/../..' . '/src/Modules/BaseShield/Options.php',
|
379 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\Processor' => __DIR__ . '/../..' . '/src/Modules/BaseShield/Processor.php',
|
|
|
380 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\BaseShield\\UI' => __DIR__ . '/../..' . '/src/Modules/BaseShield/UI.php',
|
381 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\AdminNotices' => __DIR__ . '/../..' . '/src/Modules/Base/AdminNotices.php',
|
382 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\AjaxHandler' => __DIR__ . '/../..' . '/src/Modules/Base/AjaxHandler.php',
|
|
|
383 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Debug' => __DIR__ . '/../..' . '/src/Modules/Base/Debug.php',
|
384 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\Insights\\OverviewCards' => __DIR__ . '/../..' . '/src/Modules/Base/Insights/OverviewCards.php',
|
385 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Base\\ModCon' => __DIR__ . '/../..' . '/src/Modules/Base/ModCon.php',
|
401 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\ModCon' => __DIR__ . '/../..' . '/src/Modules/CommentsFilter/ModCon.php',
|
402 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Options' => __DIR__ . '/../..' . '/src/Modules/CommentsFilter/Options.php',
|
403 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Processor' => __DIR__ . '/../..' . '/src/Modules/CommentsFilter/Processor.php',
|
404 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Scan\\AntiBot' => __DIR__ . '/../..' . '/src/Modules/CommentsFilter/Scan/AntiBot.php',
|
405 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Scan\\Bot' => __DIR__ . '/../..' . '/src/Modules/CommentsFilter/Scan/Bot.php',
|
406 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Scan\\CommentAdditiveCleaner' => __DIR__ . '/../..' . '/src/Modules/CommentsFilter/Scan/CommentAdditiveCleaner.php',
|
407 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Scan\\Human' => __DIR__ . '/../..' . '/src/Modules/CommentsFilter/Scan/Human.php',
|
408 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Scan\\IsEmailTrusted' => __DIR__ . '/../..' . '/src/Modules/CommentsFilter/Scan/IsEmailTrusted.php',
|
409 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\CommentsFilter\\Scan\\Scanner' => __DIR__ . '/../..' . '/src/Modules/CommentsFilter/Scan/Scanner.php',
|
420 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Email\\Options' => __DIR__ . '/../..' . '/src/Modules/Email/Options.php',
|
421 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Email\\Processor' => __DIR__ . '/../..' . '/src/Modules/Email/Processor.php',
|
422 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Email\\Strings' => __DIR__ . '/../..' . '/src/Modules/Email/Strings.php',
|
|
|
|
|
|
|
423 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Consolidate\\ConsolidateAllEvents' => __DIR__ . '/../..' . '/src/Modules/Events/Consolidate/ConsolidateAllEvents.php',
|
424 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Lib\\EventsListener' => __DIR__ . '/../..' . '/src/Modules/Events/Lib/EventsListener.php',
|
425 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Events\\Lib\\EventsService' => __DIR__ . '/../..' . '/src/Modules/Events/Lib/EventsService.php',
|
522 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\AjaxHandler' => __DIR__ . '/../..' . '/src/Modules/IPs/AjaxHandler.php',
|
523 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\Base' => __DIR__ . '/../..' . '/src/Modules/IPs/BotTrack/Base.php',
|
524 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\Track404' => __DIR__ . '/../..' . '/src/Modules/IPs/BotTrack/Track404.php',
|
525 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\TrackCommentSpam' => __DIR__ . '/../..' . '/src/Modules/IPs/BotTrack/TrackCommentSpam.php',
|
526 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\TrackFakeWebCrawler' => __DIR__ . '/../..' . '/src/Modules/IPs/BotTrack/TrackFakeWebCrawler.php',
|
527 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\TrackInvalidScriptLoad' => __DIR__ . '/../..' . '/src/Modules/IPs/BotTrack/TrackInvalidScriptLoad.php',
|
528 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\TrackLinkCheese' => __DIR__ . '/../..' . '/src/Modules/IPs/BotTrack/TrackLinkCheese.php',
|
529 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\TrackLoginFailed' => __DIR__ . '/../..' . '/src/Modules/IPs/BotTrack/TrackLoginFailed.php',
|
530 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\BotTrack\\TrackLoginInvalid' => __DIR__ . '/../..' . '/src/Modules/IPs/BotTrack/TrackLoginInvalid.php',
|
540 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\AutoUnblock' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/AutoUnblock.php',
|
541 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\BlacklistHandler' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/BlacklistHandler.php',
|
542 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\BlockRequest' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/BlockRequest.php',
|
543 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\BotSignalsController' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/Bots/BotSignalsController.php',
|
544 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\BotSignalsRecord' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/Bots/BotSignalsRecord.php',
|
545 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\Calculator\\BuildScores' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/Bots/Calculator/BuildScores.php',
|
546 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\Calculator\\CalculateVisitorBotScores' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/Bots/Calculator/CalculateVisitorBotScores.php',
|
547 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\EventListener' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/Bots/EventListener.php',
|
548 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\NotBot\\InsertNotBotJs' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/Bots/NotBot/InsertNotBotJs.php',
|
549 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\Bots\\NotBot\\NotBotHandler' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/Bots/NotBot/NotBotHandler.php',
|
550 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\IpAnalyse\\BuildDisplay' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/IpAnalyse/BuildDisplay.php',
|
551 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\IpAnalyse\\FindAllPluginIps' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/IpAnalyse/FindAllPluginIps.php',
|
552 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\IPs\\Lib\\OffenseTracker' => __DIR__ . '/../..' . '/src/Modules/IPs/Lib/OffenseTracker.php',
|
598 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\MainWP\\Server\\UI\\PageRender\\NotShieldPro' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/MainWP/Server/UI/PageRender/NotShieldPro.php',
|
599 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\MainWP\\Server\\UI\\PageRender\\PluginOutOfDate' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/MainWP/Server/UI/PageRender/PluginOutOfDate.php',
|
600 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\MainWP\\Server\\UI\\PageRender\\SitesList' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/MainWP/Server/UI/PageRender/SitesList.php',
|
601 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Spam\\Handlers\\Base' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Spam/Handlers/Base.php',
|
602 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Spam\\Handlers\\ContactForm7' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Spam/Handlers/ContactForm7.php',
|
603 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Spam\\Handlers\\ElementorPro' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Spam/Handlers/ElementorPro.php',
|
604 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Spam\\Handlers\\FluentForms' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Spam/Handlers/FluentForms.php',
|
605 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Spam\\Handlers\\FormidableForms' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Spam/Handlers/FormidableForms.php',
|
606 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Spam\\Handlers\\Forminator' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Spam/Handlers/Forminator.php',
|
607 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Spam\\Handlers\\GravityForms' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Spam/Handlers/GravityForms.php',
|
608 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Spam\\Handlers\\Helpers\\NinjaForms_ShieldSpamAction' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Spam/Handlers/Helpers/NinjaForms_ShieldSpamAction.php',
|
609 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Spam\\Handlers\\KaliForms' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Spam/Handlers/KaliForms.php',
|
610 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Spam\\Handlers\\NinjaForms' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Spam/Handlers/NinjaForms.php',
|
611 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Spam\\Handlers\\WPForms' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Spam/Handlers/WPForms.php',
|
612 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Spam\\Handlers\\WpForo' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Spam/Handlers/WpForo.php',
|
613 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Lib\\Spam\\SpamController' => __DIR__ . '/../..' . '/src/Modules/Integrations/Lib/Spam/SpamController.php',
|
614 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\ModCon' => __DIR__ . '/../..' . '/src/Modules/Integrations/ModCon.php',
|
615 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Options' => __DIR__ . '/../..' . '/src/Modules/Integrations/Options.php',
|
616 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Integrations\\Processor' => __DIR__ . '/../..' . '/src/Modules/Integrations/Processor.php',
|
653 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\AntiBot\\FormProviders\\WPMembers' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/WPMembers.php',
|
654 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\AntiBot\\FormProviders\\WooCommerce' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/WooCommerce.php',
|
655 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\AntiBot\\FormProviders\\WordPress' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/AntiBot/FormProviders/WordPress.php',
|
656 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\AntiBot\\ProtectionProviders\\AntiBot' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/AntiBot/ProtectionProviders/AntiBot.php',
|
657 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\AntiBot\\ProtectionProviders\\BaseProtectionProvider' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/AntiBot/ProtectionProviders/BaseProtectionProvider.php',
|
658 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\AntiBot\\ProtectionProviders\\CoolDown' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/AntiBot/ProtectionProviders/CoolDown.php',
|
659 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\LoginGuard\\Lib\\AntiBot\\ProtectionProviders\\GaspJs' => __DIR__ . '/../..' . '/src/Modules/LoginGuard/Lib/AntiBot/ProtectionProviders/GaspJs.php',
|
723 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\WpCli\\Import' => __DIR__ . '/../..' . '/src/Modules/Plugin/WpCli/Import.php',
|
724 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\WpCli\\Reset' => __DIR__ . '/../..' . '/src/Modules/Plugin/WpCli/Reset.php',
|
725 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Plugin\\WpCli\\ToggleDebug' => __DIR__ . '/../..' . '/src/Modules/Plugin/WpCli/ToggleDebug.php',
|
726 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Reporting\\AjaxHandler' => __DIR__ . '/../..' . '/src/Modules/Reporting/AjaxHandler.php',
|
727 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Reporting\\Charts\\BaseBuildChartData' => __DIR__ . '/../..' . '/src/Modules/Reporting/Charts/BaseBuildChartData.php',
|
728 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Reporting\\Charts\\ChartRequestConsumer' => __DIR__ . '/../..' . '/src/Modules/Reporting/Charts/ChartRequestConsumer.php',
|
729 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Reporting\\Charts\\ChartRequestVO' => __DIR__ . '/../..' . '/src/Modules/Reporting/Charts/ChartRequestVO.php',
|
730 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Reporting\\Charts\\CustomChartData' => __DIR__ . '/../..' . '/src/Modules/Reporting/Charts/CustomChartData.php',
|
731 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Reporting\\Charts\\CustomChartRequestVO' => __DIR__ . '/../..' . '/src/Modules/Reporting/Charts/CustomChartRequestVO.php',
|
732 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Reporting\\Debug' => __DIR__ . '/../..' . '/src/Modules/Reporting/Debug.php',
|
733 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Reporting\\Insights\\OverviewCards' => __DIR__ . '/../..' . '/src/Modules/Reporting/Insights/OverviewCards.php',
|
734 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Modules\\Reporting\\Lib\\ReportingController' => __DIR__ . '/../..' . '/src/Modules/Reporting/Lib/ReportingController.php',
|
945 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Consumer\\WpUserConsumer' => __DIR__ . '/../..' . '/src/Utilities/Consumer/WpUserConsumer.php',
|
946 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Github\\ListTags' => __DIR__ . '/../..' . '/src/Utilities/Github/ListTags.php',
|
947 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\HCaptcha\\TestRequest' => __DIR__ . '/../..' . '/src/Utilities/HCaptcha/TestRequest.php',
|
948 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\HumanSpam\\TestContent' => __DIR__ . '/../..' . '/src/Utilities/HumanSpam/TestContent.php',
|
949 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Options\\CleanStorage' => __DIR__ . '/../..' . '/src/Utilities/Options/CleanStorage.php',
|
950 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\ReCaptcha\\Enqueue' => __DIR__ . '/../..' . '/src/Utilities/ReCaptcha/Enqueue.php',
|
951 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\ReCaptcha\\TestRequest' => __DIR__ . '/../..' . '/src/Utilities/ReCaptcha/TestRequest.php',
|
952 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\ReCaptcha\\WordpressPost' => __DIR__ . '/../..' . '/src/Utilities/ReCaptcha/WordpressPost.php',
|
953 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Resources\\Dynamic' => __DIR__ . '/../..' . '/src/Utilities/Resources/Dynamic.php',
|
954 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Time\\WorldTimeApi' => __DIR__ . '/../..' . '/src/Utilities/Time/WorldTimeApi.php',
|
955 |
+
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Tool\\DbTableExport' => __DIR__ . '/../..' . '/src/Utilities/Tool/DbTableExport.php',
|
956 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Tool\\FormatBytes' => __DIR__ . '/../..' . '/src/Utilities/Tool/FormatBytes.php',
|
957 |
'FernleafSystems\\Wordpress\\Plugin\\Shield\\Utilities\\Tool\\IpListSort' => __DIR__ . '/../..' . '/src/Utilities/Tool/IpListSort.php',
|
958 |
'FernleafSystems\\Wordpress\\Services\\Core\\AdminNotices' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Core/AdminNotices.php',
|
1038 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Integrations\\WpHashes\\Malware\\Whitelist\\RequestVO' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Malware/Whitelist/RequestVO.php',
|
1039 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Integrations\\WpHashes\\Services\\Base' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Services/Base.php',
|
1040 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Integrations\\WpHashes\\Services\\IPs' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Services/IPs.php',
|
1041 |
+
'FernleafSystems\\Wordpress\\Services\\Utilities\\Integrations\\WpHashes\\Services\\ProviderIPs' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Services/ProviderIPs.php',
|
1042 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Integrations\\WpHashes\\Services\\RequestVO' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Services/RequestVO.php',
|
1043 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Integrations\\WpHashes\\Token\\Base' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Token/Base.php',
|
1044 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Integrations\\WpHashes\\Token\\RequestVO' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Integrations/WpHashes/Token/RequestVO.php',
|
1065 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Licenses\\Lookup' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Licenses/Lookup.php',
|
1066 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\BaseIP' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Net/BaseIP.php',
|
1067 |
'FernleafSystems\\Wordpress\\Services\\Utilities\\Net\\FindSourceFromIp' => __DIR__ . '/..' . '/fernleafsystems/wordpress-services/src/Utilities/Net/FindSourceFromIp.php',
|
1068 |
+
'FernleafSystems\\Wordpress\\Service
|