Sucuri Security – Auditing, Malware Scanner and Security Hardening - Version 1.7.18

Version Description

  • Added options library using external file instead of the database
  • Modified API calls using custom HTTP request using Curl
  • Fixed core files marked as broken in a Windows server
  • Fixed pagination links in last and failed logins page
  • Fixed password with ampersands in email notification
  • Fixed whitelist hardening using the authz_core module
  • Removed unnecessary emails to reduce spam
  • Added constant to stop execution of admin init hooks
  • Added explanation for invalid emails and no MX records
  • Added link to open the form to insert the API key manually
  • Added more options in the IP discoverer setting
  • Added option to configure malware scanner timeout
  • Added option to configure the API communication protocol
  • Added option to reset the malware scanner cache
  • Added scheduled task and email alert for available updates
  • Added tool to block user accounts from attempting a login
  • Added tool to debug HTTP requests to the API services
  • Various minor adjustments and fixes
Download this release

Release Info

Developer akresic
Plugin Icon 128x128 Sucuri Security – Auditing, Malware Scanner and Security Hardening
Version 1.7.18
Comparing to
See all releases

Code changes from version 1.7.17 to 1.7.18

Files changed (64) hide show
  1. inc/css/sucuri-scanner.min.css +1 -1
  2. inc/js/sucuri-scanner.min.js +1 -1
  3. inc/tpl/bsidebar.html.tpl +8 -5
  4. inc/tpl/corefiles.html.tpl +6 -0
  5. inc/tpl/firewall-auditlogs.html.tpl +1 -1
  6. inc/tpl/firewall-clearcache.html.tpl +1 -1
  7. inc/tpl/firewall-settings.html.tpl +1 -1
  8. inc/tpl/hardening-panel.html.tpl +4 -4
  9. inc/tpl/hardening-whitelist.html.tpl +1 -1
  10. inc/tpl/hardening.html.tpl +17 -1
  11. inc/tpl/hardening.snippet.tpl +1 -1
  12. inc/tpl/infosys-cronjobs.html.tpl +30 -35
  13. inc/tpl/infosys-errorlogs-flimit.html.tpl +24 -0
  14. inc/tpl/infosys-errorlogs-freader.html.tpl +61 -0
  15. inc/tpl/infosys-errorlogs-status.html.tpl +23 -0
  16. inc/tpl/infosys-errorlogs.html.tpl +4 -84
  17. inc/tpl/infosys-htaccess.html.tpl +1 -1
  18. inc/tpl/integrity-auditlogs.html.tpl +73 -13
  19. inc/tpl/integrity-modifiedfiles.html.tpl +1 -1
  20. inc/tpl/integrity.html.tpl +1 -1
  21. inc/tpl/lastlogins-all.html.tpl +1 -1
  22. inc/tpl/lastlogins-blockedusers.html.tpl +65 -0
  23. inc/tpl/lastlogins-blockedusers.snippet.tpl +10 -0
  24. inc/tpl/lastlogins-failedlogins.html.tpl +52 -32
  25. inc/tpl/lastlogins-failedlogins.snippet.tpl +3 -1
  26. inc/tpl/lastlogins.html.tpl +7 -0
  27. inc/tpl/notification-resetpwd.html.tpl +1 -1
  28. inc/tpl/posthack-resetpassword.html.tpl +1 -1
  29. inc/tpl/posthack-resetplugins.html.tpl +1 -1
  30. inc/tpl/posthack-resetplugins.snippet.tpl +3 -1
  31. inc/tpl/posthack-updates-notification.html.tpl +36 -0
  32. inc/tpl/posthack-updates.html.tpl +46 -0
  33. inc/tpl/posthack-updates.snippet.tpl +12 -0
  34. inc/tpl/posthack-updatesecretkeys.html.tpl +1 -1
  35. inc/tpl/posthack.html.tpl +7 -0
  36. inc/tpl/settings-alert.html.tpl +1 -1
  37. inc/tpl/settings-apiservice-protocol.html.tpl +105 -0
  38. inc/tpl/settings-apiservice-protocol.snippet.tpl +8 -0
  39. inc/tpl/settings-apiservice.html.tpl +3 -1
  40. inc/tpl/settings-corefiles-cache.html.tpl +42 -0
  41. inc/tpl/settings-corefiles-cache.snippet.tpl +6 -0
  42. inc/tpl/settings-corefiles-language.html.tpl +40 -0
  43. inc/tpl/settings-corefiles-status.html.tpl +42 -0
  44. inc/tpl/settings-general-apikey.html.tpl +16 -6
  45. inc/tpl/settings-general-datastorage.html.tpl +8 -0
  46. inc/tpl/settings-general.html.tpl +1 -1
  47. inc/tpl/settings-heartbeat.html.tpl +1 -1
  48. inc/tpl/settings-ignorerules.html.tpl +2 -2
  49. inc/tpl/settings-ignorescan-files.html.tpl +20 -0
  50. inc/tpl/settings-ignorescan-folders.html.tpl +59 -0
  51. inc/tpl/settings-ignorescan-status.html.tpl +25 -0
  52. inc/tpl/settings-ignorescan.html.tpl +8 -0
  53. inc/tpl/settings-ignorescan.snippet.tpl +8 -0
  54. inc/tpl/settings-ignorescanning.html.tpl +0 -95
  55. inc/tpl/settings-ignorescanning.snippet.tpl +0 -9
  56. inc/tpl/settings-scanner.html.tpl +15 -97
  57. inc/tpl/settings-selfhosting.html.tpl +1 -1
  58. inc/tpl/settings-sitecheck-cache.html.tpl +23 -0
  59. inc/tpl/settings-sitecheck-status.html.tpl +56 -0
  60. inc/tpl/settings-sitecheck-timeout.html.tpl +43 -0
  61. inc/tpl/settings-trustip.html.tpl +1 -1
  62. readme.txt +22 -2
  63. sucuri.php +2147 -931
  64. uninstall.php +6 -1
inc/css/sucuri-scanner.min.css CHANGED
@@ -1 +1 @@
1
- .sucuriscan-malware-payload,.sucuriscan-request-summary td+td,.sucuriscan-wraptext{word-break:break-all}.sucuriscan-wrap *,.sucuriscan-wrap :after,.sucuriscan-wrap :before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.sucuriscan-clearfix:after,.sucuriscan-clearfix:before{display:table;content:' '}.sucuriscan-clearfix:after{clear:both}.sucuriscan-hidden{display:none!important}.sucuriscan-opacity{opacity:.6}.sucuriscan-monospace{font-family:Menlo,Monaco,monospace,courier}.sucuriscan-ellipsis{overflow:hidden;display:inline-block;white-space:nowrap;text-overflow:ellipsis}.sucuriscan-pull-left{float:left}.sucuriscan-pull-right{float:right}.sucuriscan-list li{list-style:disc;margin:0 0 5px 15px}.sucuriscan-gradient,.sucuriscan-leftside #poststuff h3,.sucuriscan-maincontent .sucuriscan-table tr>th,.sucuriscan-modal-header{background-color:#f1f1f1;background-image:-webkit-gradient(linear,left top,left bottom,from(#f9f9f9),to(#ececec));background-image:-webkit-linear-gradient(top,#f9f9f9,#ececec);background-image:-moz-linear-gradient(top,#f9f9f9,#ececec);background-image:-ms-linear-gradient(top,#f9f9f9,#ececec);background-image:-o-linear-gradient(top,#f9f9f9,#ececec);background-image:linear-gradient(top,#f9f9f9,#ececec);filter:"progid: DXImageTransform.Microsoft.Gradient(startColorstr=#f9f9f9, endColorstr=#ececec)";-ms-filter:"progid: DXImageTransform.Microsoft.Gradient(startColorstr=#f9f9f9, endColorstr=#ececec)"}.wp-core-ui .button-success,.wp-core-ui .button-success.focus,.wp-core-ui .button-success.hover,.wp-core-ui .button-success:focus,.wp-core-ui .button-success:hover,.wp-core-ui .button.button-success.button-hero{-webkit-box-shadow:0 1px 0 #109900;-moz-box-shadow:0 1px 0 #109900;box-shadow:0 1px 0 #109900}.wp-core-ui .button-success,.wp-core-ui .button-success.focus,.wp-core-ui .button-success.hover,.wp-core-ui .button-success:focus,.wp-core-ui .button-success:hover{background:#8dcd5a;border-color:#48a325;box-shadow:0 1px 0 #109900;text-shadow:0 -1px 1px #109900,1px 0 1px #109900,0 1px 1px #109900,-1px 0 1px #109900}.wp-core-ui .button-success.focus,.wp-core-ui .button-success.hover,.wp-core-ui .button-success:focus,.wp-core-ui .button-success:hover{background:#69be48}.wp-core-ui .button-success.focus,.wp-core-ui .button-success:focus{border-color:#23500e}.wp-core-ui .button-success.active,.wp-core-ui .button-success.active:focus,.wp-core-ui .button-success.active:hover,.wp-core-ui .button-success:active{background:#47a61b;border-color:#358400}.wp-core-ui .button-success-disabled,.wp-core-ui .button-success.disabled,.wp-core-ui .button-success:disabled,.wp-core-ui .button-success[disabled]{color:#b2e794!important;background:#74ba29!important;border-color:#3f7f1b!important}.wp-core-ui .button-danger,.wp-core-ui .button-danger.focus,.wp-core-ui .button-danger.hover,.wp-core-ui .button-danger:focus,.wp-core-ui .button-danger:hover,.wp-core-ui .button.button-danger.button-hero{-webkit-box-shadow:0 1px 0 #99000e;-moz-box-shadow:0 1px 0 #99000e;box-shadow:0 1px 0 #99000e}.wp-core-ui .button-danger,.wp-core-ui .button-danger.focus,.wp-core-ui .button-danger.hover,.wp-core-ui .button-danger:focus,.wp-core-ui .button-danger:hover{background:#cd5050;border-color:#a52121;text-shadow:0 -1px 1px #99000e,1px 0 1px #99000e,0 1px 1px #99000e,-1px 0 1px #99000e}.wp-core-ui .button-danger.focus,.wp-core-ui .button-danger.hover,.wp-core-ui .button-danger:focus,.wp-core-ui .button-danger:hover{background:#be4242}.wp-core-ui .button-danger.focus,.wp-core-ui .button-danger:focus{border-color:#500e0e}.wp-core-ui .button-danger.active,.wp-core-ui .button-danger.active:focus,.wp-core-ui .button-danger.active:hover,.wp-core-ui .button-danger:active{background:#a61b1b;border-color:#840000}.wp-core-ui .button-danger-disabled,.wp-core-ui .button-danger.disabled,.wp-core-ui .button-danger:disabled,.wp-core-ui .button-danger[disabled]{color:#e79494!important;background:#ba2929!important;border-color:#7f1b1b!important}.wp-core-ui .sucuriscan-btnblock{display:block;width:100%;text-align:center}.sucuriscan-overlay{position:fixed;top:0;left:0;bottom:0;right:0;z-index:9990;background:#666;background:rgba(0,0,0,.5)}.sucuriscan-modal{position:absolute;top:25px;left:15%;z-index:9990;width:55%}.sucuriscan-modal-outside{position:relative;left:0;border:1px solid #ddd}.sucuriscan-modal-inside{background:#fff;padding:20px}.sucuriscan-modal-header{padding:0;border-bottom:1px solid #ddd}#poststuff h3.sucuriscan-modal-title,.sucuriscan-leftside #poststuff h3.sucuriscan-modal-title,.sucuriscan-modal-header .sucuriscan-modal-title{margin:0 0 0 10px;padding:0;float:left;line-height:38px;border-bottom:0}.sucuriscan-modal-header .sucuriscan-modal-logo{display:inline-block;float:left;margin-top:8px;margin-left:18px}.sucuriscan-modal-header .sucuriscan-modal-logo img{height:22px}.sucuriscan-modal-close{display:inline-block;position:absolute;top:0;right:0;font-size:16px;font-weight:700;text-decoration:none;line-height:38px;padding:0 15px;border-left:1px solid #ddd}.sucuriscan-modal-inside p:first-child{margin-top:0}.postbox .inside p:last-child,.sucuriscan-modal-inside p:last-child{margin-bottom:0}.sucuriscan-label,.sucuriscan-label-danger,.sucuriscan-label-default,.sucuriscan-label-error,.sucuriscan-label-info,.sucuriscan-label-notice,.sucuriscan-label-primary,.sucuriscan-label-success,.sucuriscan-label-unknown,.sucuriscan-label-warning{display:inline;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;padding:.2em .6em .3em;border-radius:.25em}.sucuriscan-label-default,.sucuriscan-label-unknown{background:#777}.sucuriscan-label-danger,.sucuriscan-label-error{background:#d9534f}.sucuriscan-label-info,.sucuriscan-label-notice{background:#5bc0de}.sucuriscan-label-warning{background:#f0ad4e}.sucuriscan-label-success{background:#5cb85c}.sucuriscan-label-primary{background:#428bca}.sucuriscan-wrap{margin-top:20px}.sucuriscan-wrap .sucuriscan-maincontent{margin:20px 0}.sucuriscan-wrap .sucuriscan-leftside{width:73.5%;float:left}.sucuriscan-wrap .sucuriscan-onecolumn{width:100%}.sucuriscan-wrap .sucuriscan-sidebar{width:25%;float:right}.sucuriscan-wrap #warnings_hook{line-height:normal;padding:0}.sucuriscan-wrap .sucuriscan-navbar{padding-top:20px;padding-left:6px}.sucuriscan-wrap .sucuriscan-navbar .nav-tab{margin-right:0}.sucuriscan-footer,.sucuriscan-header{position:relative;min-width:255px;background:#333;margin:0;padding:10px;border-radius:4px}.sucuriscan-footer .sucuriscan-help{color:#fff;float:right;text-align:right}.sucuriscan-footer .sucuriscan-help p{line-height:38px;margin:0 10px 0 0;padding:0}.sucuriscan-wrap .sucuriscan-footer h2,.sucuriscan-wrap .sucuriscan-header h2,.sucuriscan-wrap .sucuriscan-logo{float:left;margin:0;padding:0}.sucuriscan-wrap .sucuriscan-logo{display:inline-block}.sucuriscan-wrap .sucuriscan-logo img{display:block}.sucuriscan-wrap .sucuriscan-footer h2,.sucuriscan-wrap .sucuriscan-header h2{color:#fff;line-height:38px;margin-left:10px;text-shadow:#000 0 1px 0}.sucuriscan-leftside #poststuff .postbox:last-child{margin-bottom:0}.sucuriscan-leftside #poststuff .postbox h3{margin:0;padding:10px;border-bottom:1px solid #ddd}.sucuriscan-maincontent abbr{text-decoration:underline;cursor:help}.wrap div.sucuriscan-setup-notice{background:#bbe8f5;margin:0 0 20px;padding:0;border:1px solid #bbb;border-radius:3px;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.wrap div.sucuriscan-setup-notice .sucuriscan-setup-image,.wrap div.sucuriscan-setup-notice .sucuriscan-setup-image img{border-radius:3px 0 0 3px}.wrap div.sucuriscan-setup-notice .sucuriscan-setup-image{background:#333;margin:-1px 0 -1px -1px;padding:7px 10px;border-right:1px solid transparent}.wrap div.sucuriscan-setup-notice .sucuriscan-setup-form{padding:4px 4px 4px 0}.wrap div.sucuriscan-setup-notice p{font-size:14px;line-height:20px;margin:0 0 0 10px;padding:7px 0}.wrap div.sucuriscan-setup-notice,.wrap div.sucuriscan-setup-notice .sucuriscan-setup-image{border-color:#4393ac}.wp-core-ui .button.sucuriscan-review-hero,.wp-core-ui .sucuriscan-review-hero{height:initial;line-height:36px;float:right;padding:0 20px}.sucuriscan-input-group>label{display:inline-block;border:1px solid #ddd;border-right:0;line-height:26px;float:left;padding:0 10px;background:#eee}.sucuriscan-input-group>input[type=text]{margin:0;padding-bottom:4px}.sucuriscan-input-group>select{vertical-align:initial;margin:0}.sucuriscan-table-setup td{vertical-align:top}.sucuriscan-table-setup .sucuriscan-description{font-size:12px;margin-top:10px}.sucuriscan-dismiss-setup{font-size:10px;line-height:28px}.sucuriscan-maincontent .sucuriscan-table{margin-top:12px}.sucuriscan-maincontent .sucuriscan-table tr>th{border-top:1px solid #e5e5e5;border-bottom:1px solid #e5e5e5}.sucuriscan-maincontent .sucuriscan-table tr:first-child th{border-top:0}.sucuriscan-maincontent .sucuriscan-table td.check-column{padding:8px 10px}.sucuriscan-maincontent .sucuriscan-striped-table tr:nth-child(even){background:#f5f5f5}.sucuriscan-table-double-title tr:first-child th,.sucuriscan-table-quad-title tr:first-child th,.sucuriscan-table-quad-title tr:first-child+tr th,.sucuriscan-table-quad-title tr:first-child+tr+tr th,.sucuriscan-table-triple-title tr:first-child th,.sucuriscan-table-triple-title tr:first-child+tr th{border-bottom:0}.sucuriscan-table-description{border-left-width:1px!important;box-shadow:none}.sucuriscan-table-description .inside{border-bottom:0!important}.widefat td.td-with-button{text-align:right;padding:3px 10px}.widefat td.td-with-button button{min-width:90px}.widefat td.td-with-button select{height:initial;line-height:initial;vertical-align:top;margin:0;padding:2px 0 3px}.widefat th.check-column{line-height:36px;padding:0}.widefat th.check-column input[type=checkbox]{margin:1px 0 0 10px}.sucuriscan-list-as-table{background:#fff;border:1px solid #e5e5e5}.sucuriscan-list-as-table li{line-height:30px;word-break:break-all;margin:0;padding:0 10px}.sucuriscan-list-as-table li:nth-child(odd){background:#f5f5f5}.sucuriscan-list-as-table-scrollable{height:300px;overflow:hidden;overflow-y:scroll}.sucuriscan-maincontent .thead-with-button{padding:5px 5px 5px 10px}.sucuriscan-maincontent .thead-with-button>span{display:inline-block;line-height:28px}.sucuriscan-maincontent .thead-with-button .input-text{line-height:26px}.sucuriscan-maincontent .thead-with-button select{margin:0;padding:0}.sucuriscan-maincontent .thead-topright-action{display:inline-block;float:right}.sucuriscan-ad{color:#fff;padding:20px;margin-bottom:20px}.sucuriscan-ad .sucuriscan-ad-btn,.sucuriscan-ad h3,.sucuriscan-ad h4{font-family:Arial,Helvetica,sans-serif;color:#fff;margin:0}.sucuriscan-ad h3{font-size:18px;font-weight:300}.sucuriscan-ad h4{font-size:22px;font-weight:700;margin-top:10px}.sucuriscan-ad .sucuriscan-ad-btn{display:block;font-size:13px;font-weight:700;text-align:center;text-decoration:none;text-transform:uppercase;margin-top:20px;padding:5px;border-radius:20px}.sucuriscan-ad .sucuriscan-ad-footer{margin-top:20px;margin-bottom:0}.sucuriscan-ad .sucuriscan-ad-footer ul{margin:0}.sucuriscan-ad .sucuriscan-ad-footer li{font-size:12px;color:#fff;list-style:disc;margin:0 0 0 16px}.sucuriscan-ad .sucuriscan-ad-footer li.featured{color:#fde44c}.sucuriscan-scanner-video{width:100%;background:#fff;border:1px solid #ddd}.sucuriscan-sidebar .sucuriscan-supportbtn{width:100%;height:initial;text-align:center;line-height:36px;margin-top:15px;padding:0}.wp-core-ui .sucuriscan-hide-ads{display:block;color:#666;font-size:11px;text-decoration:underline;margin-top:15px;padding:0}.wp-core-ui .sucuriscan-hide-ads:focus{color:#000;box-shadow:none}.sucuriscan-ad-firewall{background:#606e77}.sucuriscan-ad-firewall .sucuriscan-ad-btn{background:#606e77;border:1px solid #fff}.sucuriscan-ad-firewall .sucuriscan-ad-btn:hover{background:#85929b}.sucuriscan-ad-antivirus{background:#04833e;padding-bottom:0}.sucuriscan-ad-antivirus .sucuriscan-ad-website{display:block;text-decoration:none;margin-top:20px}.sucuriscan-ad-antivirus .sucuriscan-ad-website img{display:block;max-width:100%}.sucuriscan-ad-antivirus .sucuriscan-ad-btn{background-color:#e8840a;background-image:-webkit-gradient(linear,left top,left bottom,from(#e8840a),to(#ef7f02));background-image:-webkit-linear-gradient(top,#e8840a,#ef7f02);background-image:-moz-linear-gradient(top,#e8840a,#ef7f02);background-image:-ms-linear-gradient(top,#e8840a,#ef7f02);background-image:-o-linear-gradient(top,#e8840a,#ef7f02);background-image:linear-gradient(top,#e8840a,#ef7f02);filter:"progid: DXImageTransform.Microsoft.Gradient(startColorstr=#e8840a, endColorstr=#ef7f02)";-ms-filter:"progid: DXImageTransform.Microsoft.Gradient(startColorstr=#e8840a, endColorstr=#ef7f02)";box-shadow:inset 0 1px 1px #eaac3a;border:1px solid #d17301}div.sucuriscan-alert{position:relative;margin:0 0 20px}div.sucuriscan-alert>a.close{position:absolute;top:10px;right:10px;font-size:18px;font-weight:700;text-decoration:none}.sucuriscan-inline-alert,.sucuriscan-inline-alert-error,.sucuriscan-inline-alert-info,.sucuriscan-inline-alert-updated,.sucuriscan-inline-alert-warning{background:#fff;box-shadow:0 1px 1px 0 rgba(0,0,0,.1);padding:0;border-left:4px solid #ddd}.sucuriscan-inline-alert-error>p,.sucuriscan-inline-alert-info>p,.sucuriscan-inline-alert-updated>p,.sucuriscan-inline-alert-warning>p,.sucuriscan-inline-alert>p{margin:0;padding:8px 12px;border:1px solid #ddd;border-left:0}.sucuriscan-inline-alert,.sucuriscan-inline-alert-error,.sucuriscan-inline-alert-info,.sucuriscan-inline-alert-updated,.sucuriscan-inline-alert-warning{margin-bottom:10px}.postbox .inside .sucuriscan-inline-alert-error:last-child,.postbox .inside .sucuriscan-inline-alert-info:last-child,.postbox .inside .sucuriscan-inline-alert-updated:last-child,.postbox .inside .sucuriscan-inline-alert-warning:last-child,.postbox .inside .sucuriscan-inline-alert:last-child,.sucuriscan-tabs>ul li{margin-bottom:0}.sucuriscan-inline-alert-updated{border-left-color:#7ad03a}.sucuriscan-inline-alert-warning{border-left-color:#ffba00}.sucuriscan-inline-alert-error{border-left-color:#dd3d36}.sucuriscan-inline-alert-info{border-left-color:#2ea2cc}.sucuriscan-tabs>ul{margin:0}.sucuriscan-tabs>ul li,.sucuriscan-tabs>ul li>a{display:inline-block}.sucuriscan-tabs>ul li>a{background:#e5e5e5;font-size:13px;font-weight:700;color:#333;line-height:38px;text-decoration:none;padding:0 10px}.sucuriscan-tabs>ul li>a.sucuriscan-tab-active{background:#fff;border:1px solid #e1e1e1;border-bottom:0}.sucuriscan-tabs>ul li.sucuriscan-red-tab a{background:#ff8a83;color:#fff}.sucuriscan-tabs>ul li.sucuriscan-red-tab a.sucuriscan-tab-active{background:#dd3d36;border-color:#dd3d36}.sucuriscan-maincontent .sucuriscan-tab-containers>div>#poststuff,.sucuriscan-maincontent .sucuriscan-tab-containers>div>table{margin-top:0}.sucuriscan-getapi-div{background:#fff;margin:0 0 20px;border:1px solid #e5e5e5;border-radius:3px}.sucuriscan-getapi-div p{margin:0;padding:10px}.sucuriscan-getapi-form button.button-primary{width:100%;height:initial;line-height:30px;margin:0 0 -1px;padding:0;border-radius:0 0 3px 3px}.sucuriscan-malwarescan-message{margin-bottom:20px!important}.sucuriscan-loading{background:#fff;text-align:center;padding:30px 30px 15px;border:1px solid #ddd;border-radius:4px}.sucuriscan-loading h3,.sucuriscan-loading p{margin:0;padding:0}.sucuriscan-loading .title{font-size:28px;margin-bottom:10px}.sucuriscan-loading .description{font-size:16px}.sucuriscan-sitelogo{width:190px;height:100px;background:url(https://sitecheck.sucuri.net/images/sucuri-sprite.png) no-repeat;margin:0 auto}.sucuriscan-sitecheck-form{margin:20px 0 0}.sucuriscan-sitecheck-form .button.button-hero{padding:0 46px}.sucuriscan-loading .sucuriscan-sitecheck-disclaimer{text-align:justify;padding-top:20px;border-top:1px solid #ddd}.sucuriscan-auditlogs .sucuriscan-maxper-page,.sucuriscan-scanner-results .sucuriscan-malware-link{text-align:right}.sucuriscan-loading .sucuriscan-sitecheck-disclaimer p{font-size:10px}.sucuriscan-maincontent .sucuriscan-border{border:0;border-left:4px solid #ddd}.sucuriscan-maincontent .sucuriscan-border>.inside,.sucuriscan-maincontent .sucuriscan-border>h3{border-top:1px solid #e5e5e5;border-right:1px solid #e5e5e5}.sucuriscan-maincontent .sucuriscan-border>h3{border-bottom:0}.sucuriscan-maincontent .sucuriscan-border>.inside{margin-top:0!important;border-bottom:1px solid #ddd}.sucuriscan-maincontent .sucuriscan-border-good,.sucuriscan-maincontent .sucuriscan-border-success{border-left-color:#7ad03a}.sucuriscan-maincontent .sucuriscan-border-bad,.sucuriscan-maincontent .sucuriscan-border-danger{border-left-color:#dd3d36}.sucuriscan-maincontent .sucuriscan-border-info{border-left-color:#2ea2cc}.sucuriscan-maincontent .sucuriscan-cleanup-btn{margin:20px 0 0}.sucuriscan-scanner-results .sucuriscan-scanner-details tr:nth-child(even),.sucuriscan-scanner-results .sucuriscan-scanner-links tr:nth-child(even){background:#f5f5f5}.sucuriscan-scanner-results td.sucuriscan-border-bad{border-left-width:4px;border-left-style:solid}.sucuriscan-scanner-results .sucuriscan-malware-link a:hover{color:#fff}.sucuriscan-malware-payload{background:#f5f5f5;margin:-2px -15px -15px;padding:15px}.sucuriscan-maincontent .sucuriscan-auditlogs,.sucuriscan-maincontent .sucuriscan-corefiles,.sucuriscan-maincontent .sucuriscan-wordpress-outdated{margin-top:0;margin-bottom:20px}.sucuriscan-auditlogs .sucuriscan-list-as-table,.sucuriscan-maincontent .sucuriscan-auditlogs{margin-bottom:0}.sucuriscan-auditlogs .sucuriscan-label{display:inline-block;width:18px;text-transform:uppercase;line-height:13px;cursor:pointer;border-radius:50%}.sucuriscan-auditlogs .sucuriscan-auditlog-success,.sucuriscan-label-added{background:#5cb85c}.sucuriscan-auditlogs .sucuriscan-auditlog-debug{background:#c690ec}.sucuriscan-auditlogs .sucuriscan-auditlog-info{background:#5bc0de}.sucuriscan-auditlogs .sucuriscan-auditlog-notice{background:#428bca}.sucuriscan-auditlogs .sucuriscan-auditlog-warning,.sucuriscan-label-modified{background:#f0ad4e}.sucuriscan-auditlogs .sucuriscan-auditlog-error,.sucuriscan-label-removed{background:#f27d7d}.sucuriscan-auditlogs .sucuriscan-auditlog-critical{background:#000}.sucuriscan-maincontent .sucuriscan-audit-report{border-left-width:1px}.sucuriscan-audit-report .sucuriscan-report-row{margin-bottom:10px}.sucuriscan-audit-report .sucuriscan-report-row:last-child,.sucuriscan-maincontent .sucuriscan-corefiles{margin-bottom:0}.sucuriscan-audit-report .sucuriscan-report-chart{width:49%;border:1px solid #ddd}.sucuriscan-audit-report .sucuriscan-report-chart h4,.sucuriscan-audit-report .sucuriscan-report-chart h5{font-weight:400;text-align:center;margin:0}.sucuriscan-firewall-accesslog .sucuriscan-accesslog-label,.sucuriscan-request-summary tr td:first-child{font-weight:700}.sucuriscan-audit-report .sucuriscan-report-chart h4{font-size:18px;margin-top:10px}.sucuriscan-audit-report .sucuriscan-report-chart h5{font-size:12px;margin-top:5px}.sucuriscan-firewall-auditlogs .sucuriscan-denial-type,.sucuriscan-request-summary td{font-size:14px}.sucuriscan-maincontent .sucuriscan-audit-report .sucuriscan-inline-alert-info{margin-top:10px}.sucuriscan-status-type{display:inline-block;width:20px;background:#ddd;text-align:center;text-transform:uppercase;margin-right:10px;padding:0 3px;border:1px solid transparent;border-radius:3px}.sucuriscan-maincontent .sucuriscan-corefiles .sucuriscan-label{text-transform:capitalize}.sucuriscan-maincontent .sucuriscan-ignoredfiles{margin-top:0}.sucuriscan-ignore-file form{padding:0 10px 10px;border-bottom:1px solid #ddd;border-right:1px solid #ddd}.sucuriscan-ignore-file p{border-bottom:none}.sucuriscan-ignore-file-input{width:80%}.sucuriscan-ignore-file-button{width:18%}.sucuriscan-maincontent .sucuriscan-modifiedfiles .sucuriscan-ellipsis{width:100px}.sucuriscan-maincontent .sucuriscan-firewall-apikey{margin-bottom:10px}.sucuriscan-firewall-settings .sucuriscan-list-as-table{margin-top:4px;margin-bottom:4px}.sucuriscan-firewall-auditlogs .thead-with-button .button{width:65px}.sucuriscan-firewall-auditlogs .thead-with-button .input-text,.sucuriscan-firewall-auditlogs .thead-with-button select{width:250px}.sucuriscan-firewall-auditlogs .sucuriscan-denial-type-date{font-style:italic;color:#999}.sucuriscan-firewall-auditlogs .sucuriscan-alert,.wrap .sucuriscan-firewall-auditlogs .error,.wrap .sucuriscan-firewall-auditlogs .updated{background:#eee;border:1px solid #ddd;border-left-width:4px;margin:10px}.sucuriscan-firewall-accesslog .sucuriscan-accesslog-origin img{margin-right:6px}.sucuriscan-firewall-accesslog .sucuriscan-accesslog-datetime,.sucuriscan-firewall-accesslog .sucuriscan-accesslog-origin,.sucuriscan-firewall-accesslog .sucuriscan-accesslog-referer,.sucuriscan-firewall-accesslog .sucuriscan-accesslog-request,.sucuriscan-firewall-accesslog .sucuriscan-accesslog-signature,.sucuriscan-firewall-accesslog .sucuriscan-accesslog-target,.sucuriscan-firewall-accesslog .sucuriscan-accesslog-useragent{display:block;padding-left:30px}.sucuriscan-firewall-accesslog .sucuriscan-accesslog-origin{padding-left:0}.sucuriscan-request-summary{margin:-3px -15px -15px}.sucuriscan-hstatus{position:relative;margin:0 -12px;padding:10px 12px;border:1px solid transparent}.sucuriscan-hstatus-0{background-color:#f2dede;color:#a94442;border-color:#ebccd1}.sucuriscan-hstatus-1{background-color:#dff0d8;color:#3c763d;border-color:#d6e9c6}.sucuriscan-hstatus-2{background-color:#dee4f2;color:#4263a9;border-color:#ccd0eb}.sucuriscan-hstatus .button-primary,.sucuriscan-hstatus .button-secondary{position:absolute;top:5px;right:5px}.sucuriscan-hardening .postbox .inside pre{background:#eaeaea;padding:10px}.sucuriscan-hardening-whitelist form{margin-top:15px}.sucuriscan-hardening-whitelist form label{line-height:29px;font-size:12px;background-color:#eee;padding:0 10px;display:inline-block;border:1px solid #ddd;border-right:0}.sucuriscan-hardening-whitelist form input[type=text]{margin:0;padding:5px}.sucuriscan-hardening-whitelist form select{height:initial;padding:4px;margin:0}.sucuriscan-hardening-whitelist form .button,.sucuriscan-hardening-whitelist form input[type=text],.sucuriscan-hardening-whitelist form select{margin-right:5px}.sucuriscan-maincontent .sucuriscan-table.sucuriscan-hardening-whitelist-table{margin-top:0}.sucuriscan-lastlogin-outof{font-style:italic;color:#999;margin-right:10px}.sucuriscan-admins-lastlogins .sucuriscan-ellipsis{width:170px}.sucuriscan-admins-lastlogins td{padding:4px 8px}.sucuriscan-pattern-search-inputbox{margin-top:12px}.sucuriscan-pattern-search-inputbox .input-text{width:84.7777%;line-height:30px;margin:0 6px 0 0}.sucuriscan-pattern-search-inputbox .input-button{width:14%;height:initial;line-height:35px}.sucuriscan-pattern-search .sucuriscan-cleanup-btn{margin-top:12px}.sucuriscan-pattern-search table label{color:#999}.sucuriscan-pattern-search .sucuriscan-grep-text em{color:#ea3838}.sucuriscan-about ul{margin-left:20px}.sucuriscan-about ul li{list-style:outside}.sucuriscan-about li label{font-weight:700;vertical-align:initial}.sucuriscan-apikey-registered .sucuriscan-pull-right{width:400px}.sucuriscan-apikey-registered .sucuriscan-sitelogo{background-position:0 -17px;height:83px}.sucuriscan-setup-instructions .form-table{margin-top:15px}.sucuriscan-setup-instructions .form-table td{padding:0 0 12px}.sucuriscan-setup-instructions .form-table select{max-width:400px}.sucuriscan-pagination{display:inline-block;margin:0;padding:0;border-radius:4px}.sucuriscan-pagination>li{display:inline}.c3-tooltip td>span,.sucuriscan-maincontent .sucuriscan-settings form{display:inline-block}.sucuriscan-pagination>li>a,.sucuriscan-pagination>li>span{position:relative;background:#fff;color:#428bca;line-height:1.42857143;text-decoration:none;float:left;margin-left:-1px;padding:6px 12px;border:1px solid #ddd}.sucuriscan-pagination>li:first-child>a,.sucuriscan-pagination>li:first-child>span{margin-left:0;border-radius:4px 0 0 4px}.sucuriscan-pagination>li:last-child>a,.sucuriscan-pagination>li:last-child>span{border-radius:0 4px 4px 0}.sucuriscan-pagination>li>a.sucuriscan-pagination-active,.sucuriscan-pagination>li>a:hover{background:#0074a2;color:#fff}.sucuriscan_wpconfig_keys_updated textarea{width:100%;height:250px;background:#f5f5f5;font-size:12px;resize:vertical;margin:20px 0 0}.sucuriscan-maincontent .sucuriscan-last-logins,.sucuriscan-maincontent .sucuriscan-settings{margin-top:0}.sucuriscan-maincontent .sucuriscan-last-logins .sucuriscan-ellipsis{width:150px;line-height:inherit}.sucuriscan-maincontent .sucuriscan-full-textarea{width:100%;height:400px;line-height:normal;resize:vertical;padding:10px}.sucuriscan-maincontent .sucuriscan-settings .input-text,.sucuriscan-maincontent .sucuriscan-settings select{width:220px;margin:0}.sucuriscan-maincontent .sucuriscan-infosys-htaccess .inside .sucuriscan-inline-alert-updated,.sucuriscan-maincontent .sucuriscan-monitor-fpath{margin-bottom:10px}.sucuriscan-maincontent .sucuriscan-recipient-form{margin-top:10px}.sucuriscan-maincontent .sucuriscan-settings-ignorescanning,.sucuriscan-maincontent .sucuriscan-settings-notifications,.sucuriscan-maincontent .sucuriscan-settings-trustip,.sucuriscan-maincontent .sucuriscan-wpcron-list{margin-top:0}.sucuriscan-maincontent .sucuriscan-settings-notifications .dashicons-before:before{margin-right:5px}.sucuriscan-maincontent .sucuriscan-infosys-htaccess .inside{border-bottom:1px solid #ddd!important}.sucuriscan-maincontent .sucuriscan-errorlogs .inside .sucuriscan-inline-alert-error{margin-top:10px}.sucuriscan-maincontent .sucuriscan-subject-formats{margin:0}.sucuriscan-maincontent .sucuriscan-subject-formats input[type=text]{width:40%;margin-left:10px}.sucuriscan-flag{width:16px;height:11px;background:url(../images/flags.sprite.png) no-repeat}.sucuriscan-flag-ad{background-position:-16px 0}.sucuriscan-flag-ae{background-position:-32px 0}.sucuriscan-flag-af{background-position:-48px 0}.sucuriscan-flag-ag{background-position:-64px 0}.sucuriscan-flag-ai{background-position:-80px 0}.sucuriscan-flag-al{background-position:-96px 0}.sucuriscan-flag-am{background-position:-112px 0}.sucuriscan-flag-an{background-position:-128px 0}.sucuriscan-flag-ao{background-position:-144px 0}.sucuriscan-flag-ar{background-position:-160px 0}.sucuriscan-flag-as{background-position:-176px 0}.sucuriscan-flag-at{background-position:-192px 0}.sucuriscan-flag-au{background-position:-208px 0}.sucuriscan-flag-aw{background-position:-224px 0}.sucuriscan-flag-az{background-position:-240px 0}.sucuriscan-flag-ba{background-position:0 -11px}.sucuriscan-flag-bb{background-position:-16px -11px}.sucuriscan-flag-bd{background-position:-32px -11px}.sucuriscan-flag-be{background-position:-48px -11px}.sucuriscan-flag-bf{background-position:-64px -11px}.sucuriscan-flag-bg{background-position:-80px -11px}.sucuriscan-flag-bh{background-position:-96px -11px}.sucuriscan-flag-bi{background-position:-112px -11px}.sucuriscan-flag-bj{background-position:-128px -11px}.sucuriscan-flag-bm{background-position:-144px -11px}.sucuriscan-flag-bn{background-position:-160px -11px}.sucuriscan-flag-bo{background-position:-176px -11px}.sucuriscan-flag-br{background-position:-192px -11px}.sucuriscan-flag-bs{background-position:-208px -11px}.sucuriscan-flag-bt{background-position:-224px -11px}.sucuriscan-flag-bv{background-position:-240px -11px}.sucuriscan-flag-bw{background-position:0 -22px}.sucuriscan-flag-by{background-position:-16px -22px}.sucuriscan-flag-bz{background-position:-32px -22px}.sucuriscan-flag-ca{background-position:-48px -22px}.sucuriscan-flag-catalonia{background-position:-64px -22px}.sucuriscan-flag-cd{background-position:-80px -22px}.sucuriscan-flag-cf{background-position:-96px -22px}.sucuriscan-flag-cg{background-position:-112px -22px}.sucuriscan-flag-ch{background-position:-128px -22px}.sucuriscan-flag-ci{background-position:-144px -22px}.sucuriscan-flag-ck{background-position:-160px -22px}.sucuriscan-flag-cl{background-position:-176px -22px}.sucuriscan-flag-cm{background-position:-192px -22px}.sucuriscan-flag-cn{background-position:-208px -22px}.sucuriscan-flag-co{background-position:-224px -22px}.sucuriscan-flag-cr{background-position:-240px -22px}.sucuriscan-flag-cu{background-position:0 -33px}.sucuriscan-flag-cv{background-position:-16px -33px}.sucuriscan-flag-cw{background-position:-32px -33px}.sucuriscan-flag-cy{background-position:-48px -33px}.sucuriscan-flag-cz{background-position:-64px -33px}.sucuriscan-flag-de{background-position:-80px -33px}.sucuriscan-flag-dj{background-position:-96px -33px}.sucuriscan-flag-dk{background-position:-112px -33px}.sucuriscan-flag-dm{background-position:-128px -33px}.sucuriscan-flag-do{background-position:-144px -33px}.sucuriscan-flag-dz{background-position:-160px -33px}.sucuriscan-flag-ec{background-position:-176px -33px}.sucuriscan-flag-ee{background-position:-192px -33px}.sucuriscan-flag-eg{background-position:-208px -33px}.sucuriscan-flag-eh{background-position:-224px -33px}.sucuriscan-flag-england{background-position:-240px -33px}.sucuriscan-flag-er{background-position:0 -44px}.sucuriscan-flag-es{background-position:-16px -44px}.sucuriscan-flag-et{background-position:-32px -44px}.sucuriscan-flag-eu{background-position:-48px -44px}.sucuriscan-flag-fi{background-position:-64px -44px}.sucuriscan-flag-fj{background-position:-80px -44px}.sucuriscan-flag-fk{background-position:-96px -44px}.sucuriscan-flag-fm{background-position:-112px -44px}.sucuriscan-flag-fo{background-position:-128px -44px}.sucuriscan-flag-fr{background-position:-144px -44px}.sucuriscan-flag-ga{background-position:-160px -44px}.sucuriscan-flag-gb{background-position:-176px -44px}.sucuriscan-flag-gd{background-position:-192px -44px}.sucuriscan-flag-ge{background-position:-208px -44px}.sucuriscan-flag-gf{background-position:-224px -44px}.sucuriscan-flag-gg{background-position:-240px -44px}.sucuriscan-flag-gh{background-position:0 -55px}.sucuriscan-flag-gi{background-position:-16px -55px}.sucuriscan-flag-gl{background-position:-32px -55px}.sucuriscan-flag-gm{background-position:-48px -55px}.sucuriscan-flag-gn{background-position:-64px -55px}.sucuriscan-flag-gp{background-position:-80px -55px}.sucuriscan-flag-gq{background-position:-96px -55px}.sucuriscan-flag-gr{background-position:-112px -55px}.sucuriscan-flag-gs{background-position:-128px -55px}.sucuriscan-flag-gt{background-position:-144px -55px}.sucuriscan-flag-gu{background-position:-160px -55px}.sucuriscan-flag-gw{background-position:-176px -55px}.sucuriscan-flag-gy{background-position:-192px -55px}.sucuriscan-flag-hk{background-position:-208px -55px}.sucuriscan-flag-hm{background-position:-224px -55px}.sucuriscan-flag-hn{background-position:-240px -55px}.sucuriscan-flag-hr{background-position:0 -66px}.sucuriscan-flag-ht{background-position:-16px -66px}.sucuriscan-flag-hu{background-position:-32px -66px}.sucuriscan-flag-ic{background-position:-48px -66px}.sucuriscan-flag-id{background-position:-64px -66px}.sucuriscan-flag-ie{background-position:-80px -66px}.sucuriscan-flag-il{background-position:-96px -66px}.sucuriscan-flag-im{background-position:-112px -66px}.sucuriscan-flag-in{background-position:-128px -66px}.sucuriscan-flag-io{background-position:-144px -66px}.sucuriscan-flag-iq{background-position:-160px -66px}.sucuriscan-flag-ir{background-position:-176px -66px}.sucuriscan-flag-is{background-position:-192px -66px}.sucuriscan-flag-it{background-position:-208px -66px}.sucuriscan-flag-je{background-position:-224px -66px}.sucuriscan-flag-jm{background-position:-240px -66px}.sucuriscan-flag-jo{background-position:0 -77px}.sucuriscan-flag-jp{background-position:-16px -77px}.sucuriscan-flag-ke{background-position:-32px -77px}.sucuriscan-flag-kg{background-position:-48px -77px}.sucuriscan-flag-kh{background-position:-64px -77px}.sucuriscan-flag-ki{background-position:-80px -77px}.sucuriscan-flag-km{background-position:-96px -77px}.sucuriscan-flag-kn{background-position:-112px -77px}.sucuriscan-flag-kp{background-position:-128px -77px}.sucuriscan-flag-kr{background-position:-144px -77px}.sucuriscan-flag-kurdistan{background-position:-160px -77px}.sucuriscan-flag-kw{background-position:-176px -77px}.sucuriscan-flag-ky{background-position:-192px -77px}.sucuriscan-flag-kz{background-position:-208px -77px}.sucuriscan-flag-la{background-position:-224px -77px}.sucuriscan-flag-lb{background-position:-240px -77px}.sucuriscan-flag-lc{background-position:0 -88px}.sucuriscan-flag-li{background-position:-16px -88px}.sucuriscan-flag-lk{background-position:-32px -88px}.sucuriscan-flag-lr{background-position:-48px -88px}.sucuriscan-flag-ls{background-position:-64px -88px}.sucuriscan-flag-lt{background-position:-80px -88px}.sucuriscan-flag-lu{background-position:-96px -88px}.sucuriscan-flag-lv{background-position:-112px -88px}.sucuriscan-flag-ly{background-position:-128px -88px}.sucuriscan-flag-ma{background-position:-144px -88px}.sucuriscan-flag-mc{background-position:-160px -88px}.sucuriscan-flag-md{background-position:-176px -88px}.sucuriscan-flag-me{background-position:-192px -88px}.sucuriscan-flag-mg{background-position:-208px -88px}.sucuriscan-flag-mh{background-position:-224px -88px}.sucuriscan-flag-mk{background-position:-240px -88px}.sucuriscan-flag-ml{background-position:0 -99px}.sucuriscan-flag-mm{background-position:-16px -99px}.sucuriscan-flag-mn{background-position:-32px -99px}.sucuriscan-flag-mo{background-position:-48px -99px}.sucuriscan-flag-mp{background-position:-64px -99px}.sucuriscan-flag-mq{background-position:-80px -99px}.sucuriscan-flag-mr{background-position:-96px -99px}.sucuriscan-flag-ms{background-position:-112px -99px}.sucuriscan-flag-mt{background-position:-128px -99px}.sucuriscan-flag-mu{background-position:-144px -99px}.sucuriscan-flag-mv{background-position:-160px -99px}.sucuriscan-flag-mw{background-position:-176px -99px}.sucuriscan-flag-mx{background-position:-192px -99px}.sucuriscan-flag-my{background-position:-208px -99px}.sucuriscan-flag-mz{background-position:-224px -99px}.sucuriscan-flag-na{background-position:-240px -99px}.sucuriscan-flag-nc{background-position:0 -110px}.sucuriscan-flag-ne{background-position:-16px -110px}.sucuriscan-flag-nf{background-position:-32px -110px}.sucuriscan-flag-ng{background-position:-48px -110px}.sucuriscan-flag-ni{background-position:-64px -110px}.sucuriscan-flag-nl{background-position:-80px -110px}.sucuriscan-flag-no{background-position:-96px -110px}.sucuriscan-flag-np{background-position:-112px -110px}.sucuriscan-flag-nr{background-position:-128px -110px}.sucuriscan-flag-nu{background-position:-144px -110px}.sucuriscan-flag-nz{background-position:-160px -110px}.sucuriscan-flag-om{background-position:-176px -110px}.sucuriscan-flag-pa{background-position:-192px -110px}.sucuriscan-flag-pe{background-position:-208px -110px}.sucuriscan-flag-pf{background-position:-224px -110px}.sucuriscan-flag-pg{background-position:-240px -110px}.sucuriscan-flag-ph{background-position:0 -121px}.sucuriscan-flag-pk{background-position:-16px -121px}.sucuriscan-flag-pl{background-position:-32px -121px}.sucuriscan-flag-pm{background-position:-48px -121px}.sucuriscan-flag-pn{background-position:-64px -121px}.sucuriscan-flag-pr{background-position:-80px -121px}.sucuriscan-flag-ps{background-position:-96px -121px}.sucuriscan-flag-pt{background-position:-112px -121px}.sucuriscan-flag-pw{background-position:-128px -121px}.sucuriscan-flag-py{background-position:-144px -121px}.sucuriscan-flag-qa{background-position:-160px -121px}.sucuriscan-flag-re{background-position:-176px -121px}.sucuriscan-flag-ro{background-position:-192px -121px}.sucuriscan-flag-rs{background-position:-208px -121px}.sucuriscan-flag-ru{background-position:-224px -121px}.sucuriscan-flag-rw{background-position:-240px -121px}.sucuriscan-flag-sa{background-position:0 -132px}.sucuriscan-flag-sb{background-position:-16px -132px}.sucuriscan-flag-sc{background-position:-32px -132px}.sucuriscan-flag-scotland{background-position:-48px -132px}.sucuriscan-flag-sd{background-position:-64px -132px}.sucuriscan-flag-se{background-position:-80px -132px}.sucuriscan-flag-sg{background-position:-96px -132px}.sucuriscan-flag-sh{background-position:-112px -132px}.sucuriscan-flag-si{background-position:-128px -132px}.sucuriscan-flag-sk{background-position:-144px -132px}.sucuriscan-flag-sl{background-position:-160px -132px}.sucuriscan-flag-sm{background-position:-176px -132px}.sucuriscan-flag-sn{background-position:-192px -132px}.sucuriscan-flag-so{background-position:-208px -132px}.sucuriscan-flag-somaliland{background-position:-224px -132px}.sucuriscan-flag-sr{background-position:-240px -132px}.sucuriscan-flag-ss{background-position:0 -143px}.sucuriscan-flag-st{background-position:-16px -143px}.sucuriscan-flag-sv{background-position:-32px -143px}.sucuriscan-flag-sx{background-position:-48px -143px}.sucuriscan-flag-sy{background-position:-64px -143px}.sucuriscan-flag-sz{background-position:-80px -143px}.sucuriscan-flag-tc{background-position:-96px -143px}.sucuriscan-flag-td{background-position:-112px -143px}.sucuriscan-flag-tf{background-position:-128px -143px}.sucuriscan-flag-tg{background-position:-144px -143px}.sucuriscan-flag-th{background-position:-160px -143px}.sucuriscan-flag-tj{background-position:-176px -143px}.sucuriscan-flag-tk{background-position:-192px -143px}.sucuriscan-flag-tl{background-position:-208px -143px}.sucuriscan-flag-tm{background-position:-224px -143px}.sucuriscan-flag-tn{background-position:-240px -143px}.sucuriscan-flag-to{background-position:0 -154px}.sucuriscan-flag-tr{background-position:-16px -154px}.sucuriscan-flag-tt{background-position:-32px -154px}.sucuriscan-flag-tv{background-position:-48px -154px}.sucuriscan-flag-tw{background-position:-64px -154px}.sucuriscan-flag-tz{background-position:-80px -154px}.sucuriscan-flag-ua{background-position:-96px -154px}.sucuriscan-flag-ug{background-position:-112px -154px}.sucuriscan-flag-um{background-position:-128px -154px}.sucuriscan-flag-us{background-position:-144px -154px}.sucuriscan-flag-uy{background-position:-160px -154px}.sucuriscan-flag-uz{background-position:-176px -154px}.sucuriscan-flag-va{background-position:-192px -154px}.sucuriscan-flag-vc{background-position:-208px -154px}.sucuriscan-flag-ve{background-position:-224px -154px}.sucuriscan-flag-vg{background-position:-240px -154px}.sucuriscan-flag-vi{background-position:0 -165px}.sucuriscan-flag-vn{background-position:-16px -165px}.sucuriscan-flag-vu{background-position:-32px -165px}.sucuriscan-flag-wales{background-position:-48px -165px}.sucuriscan-flag-wf{background-position:-64px -165px}.sucuriscan-flag-ws{background-position:-80px -165px}.sucuriscan-flag-ye{background-position:-96px -165px}.sucuriscan-flag-yt{background-position:-112px -165px}.sucuriscan-flag-za{background-position:-128px -165px}.sucuriscan-flag-zanzibar{background-position:-144px -165px}.sucuriscan-flag-zm{background-position:-160px -165px}.sucuriscan-flag-zw{background-position:-176px -165px}.c3 svg{font:10px sans-serif}.c3 line,.c3 path{fill:none;stroke:#000}.c3 text{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.c3-bars path,.c3-event-rect,.c3-legend-item-tile,.c3-xgrid-focus,.c3-ygrid{shape-rendering:crispEdges}.c3-chart-arc path{stroke:#fff}.c3-chart-arc text{fill:#fff;font-size:13px}.c3-grid line{stroke:#aaa}.c3-grid text{fill:#aaa}.c3-xgrid,.c3-ygrid{stroke-dasharray:3 3}.c3-text.c3-empty{fill:gray;font-size:2em}.c3-line{stroke-width:1px}.c3-circle._expanded_{stroke-width:1px;stroke:#fff}.c3-selected-circle{fill:#fff;stroke-width:2px}.c3-bar{stroke-width:0}.c3-bar._expanded_{fill-opacity:.75}.c3-chart-arcs-title{dominant-baseline:middle;font-size:1.3em}.c3-target.c3-focused{opacity:1}.c3-target.c3-focused path.c3-line,.c3-target.c3-focused path.c3-step{stroke-width:2px}.c3-target.c3-defocused{opacity:.3!important}.c3-region{fill:#4682b4;fill-opacity:.1}.c3-brush .extent{fill-opacity:.1}.c3-legend-item{font-size:12px}.c3-legend-item-hidden{opacity:.15}.c3-legend-background{opacity:.75;fill:#fff;stroke:#d3d3d3;stroke-width:1}.c3-tooltip-container{z-index:10}.c3-tooltip{border-collapse:collapse;border-spacing:0;background-color:#fff;empty-cells:show;-webkit-box-shadow:7px 7px 12px -9px #777;-moz-box-shadow:7px 7px 12px -9px #777;box-shadow:7px 7px 12px -9px #777}.c3-tooltip tr{border:1px solid #CCC}.c3-tooltip th{background-color:#aaa;font-size:14px;padding:2px 5px;text-align:left;color:#FFF}.c3-tooltip td{font-size:13px;padding:3px 6px;background-color:#fff;border-left:1px dotted #999}.c3-tooltip td>span{width:10px;height:10px;margin-right:6px}.c3-tooltip td.value{text-align:right}.c3-area{stroke-width:0;opacity:.2}.c3-chart-arcs .c3-chart-arcs-background{fill:#e0e0e0;stroke:none}.c3-chart-arcs .c3-chart-arcs-gauge-unit{fill:#000;font-size:16px}.c3-chart-arcs .c3-chart-arcs-gauge-max,.c3-chart-arcs .c3-chart-arcs-gauge-min{fill:#777}.c3-chart-arc .c3-gauge-value{fill:#000}@media (max-width:510px){.wp-core-ui .button.sucuriscan-review-hero,.wp-core-ui .sucuriscan-review-hero{display:none}}@media (max-width:620px){.sucuriscan-tabs>ul li,.sucuriscan-tabs>ul li>a{display:block}.sucuriscan-getapi-form button.button-primary{line-height:40px}}@media (max-width:768px){.sucuriscan-wrap .sucuriscan-footer .sucuriscan-help,.sucuriscan-wrap .sucuriscan-footer .sucuriscan-logo,.sucuriscan-wrap .sucuriscan-leftside,.sucuriscan-wrap .sucuriscan-sidebar{float:none}.sucuriscan-wrap .sucuriscan-leftside,.sucuriscan-wrap .sucuriscan-sidebar{width:100%}.sucuriscan-wrap .sucuriscan-sidebar{margin-top:20px}.sucuriscan-wrap .sucuriscan-footer .sucuriscan-logo{display:table;margin:0 auto}}@media (max-width:920px){.sucuriscan-wrap .sucuriscan-navbar{padding-left:0;padding-right:0}.sucuriscan-wrap .sucuriscan-navbar .nav-tab{display:block;line-height:20px;margin:0}.sucuriscan-wrap .sucuriscan-navbar .nav-tab:last-child{border-bottom:1px solid #ccc}}@media (min-width:600px) and (max-width:1060px){.sucuriscan-wrap .sucuriscan-leftside,.sucuriscan-wrap .sucuriscan-sidebar{width:initial;float:none}.sucuriscan-wrap .sucuriscan-sidebar{margin-top:20px}.sucuriscan-wrap .sucuriscan-sidebar>div{width:49%;float:left;min-height:339px}.sucuriscan-wrap .sucuriscan-sidebar .sucuriscan-ad-antivirus{margin-left:2%}.sucuriscan-wrap .sucuriscan-scanner-video{height:450px}}.sucuriscan-maincontent #poststuff{min-width:initial;padding-top:0}.sucuriscan-maincontent .widefat tbody th.check-column{padding:6px 0 3px}.sucuriscan-maincontent .hardening-box .primary-secondary{margin:0 0 0 10px}.sucuriscan-maincontent hr{border:none;border-top:1px solid #999}.sucuriscan-maincontent table td>table{background:#fff}.sucuriscan-maincontent table td>table th{padding:4px 8px}
1
+ .sucuriscan-malware-payload,.sucuriscan-request-summary td+td,.sucuriscan-wraptext{word-break:break-all}.sucuriscan-wrap *,.sucuriscan-wrap:after,.sucuriscan-wrap:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.sucuriscan-clearfix:after,.sucuriscan-clearfix:before{display:table;content:' '}.sucuriscan-clearfix:after{clear:both}.sucuriscan-hidden{display:none!important}.sucuriscan-opacity{opacity:.6}.sucuriscan-monospace{font-family:Menlo,Monaco,monospace,courier}.sucuriscan-ellipsis{overflow:hidden;display:inline-block;white-space:nowrap;text-overflow:ellipsis}.sucuriscan-pull-left{float:left}.sucuriscan-pull-right{float:right}.sucuriscan-list li{list-style:disc;margin:0 0 5px 15px}.sucuriscan-gradient,.sucuriscan-leftside #poststuff h3,.sucuriscan-leftside .sucuriscan-panelstuff h3,.sucuriscan-maincontent .sucuriscan-table tr>th,.sucuriscan-modal-header{background-color:#f1f1f1;background-image:-webkit-gradient(linear,left top,left bottom,from(#f9f9f9),to(#ececec));background-image:-webkit-linear-gradient(top,#f9f9f9,#ececec);background-image:-moz-linear-gradient(top,#f9f9f9,#ececec);background-image:-ms-linear-gradient(top,#f9f9f9,#ececec);background-image:-o-linear-gradient(top,#f9f9f9,#ececec);background-image:linear-gradient(top,#f9f9f9,#ececec);filter:"progid: DXImageTransform.Microsoft.Gradient(startColorstr=#f9f9f9, endColorstr=#ececec)";-ms-filter:"progid: DXImageTransform.Microsoft.Gradient(startColorstr=#f9f9f9, endColorstr=#ececec)"}.wp-core-ui .button-success,.wp-core-ui .button-success.focus,.wp-core-ui .button-success.hover,.wp-core-ui .button-success:focus,.wp-core-ui .button-success:hover,.wp-core-ui .button.button-success.button-hero{-webkit-box-shadow:0 1px 0 #109900;-moz-box-shadow:0 1px 0 #109900;box-shadow:0 1px 0 #109900}.wp-core-ui .button-success,.wp-core-ui .button-success.focus,.wp-core-ui .button-success.hover,.wp-core-ui .button-success:focus,.wp-core-ui .button-success:hover{background:#8dcd5a;border-color:#48a325;box-shadow:0 1px 0 #109900;text-shadow:0 -1px 1px #109900,1px 0 1px #109900,0 1px 1px #109900,-1px 0 1px #109900}.wp-core-ui .button-success.focus,.wp-core-ui .button-success.hover,.wp-core-ui .button-success:focus,.wp-core-ui .button-success:hover{background:#69be48}.wp-core-ui .button-success.focus,.wp-core-ui .button-success:focus{border-color:#23500e}.wp-core-ui .button-success.active,.wp-core-ui .button-success.active:focus,.wp-core-ui .button-success.active:hover,.wp-core-ui .button-success:active{background:#47a61b;border-color:#358400}.wp-core-ui .button-success-disabled,.wp-core-ui .button-success.disabled,.wp-core-ui .button-success:disabled,.wp-core-ui .button-success[disabled]{color:#b2e794!important;background:#74ba29!important;border-color:#3f7f1b!important}.wp-core-ui .button-danger,.wp-core-ui .button-danger.focus,.wp-core-ui .button-danger.hover,.wp-core-ui .button-danger:focus,.wp-core-ui .button-danger:hover,.wp-core-ui .button.button-danger.button-hero{-webkit-box-shadow:0 1px 0 #99000e;-moz-box-shadow:0 1px 0 #99000e;box-shadow:0 1px 0 #99000e}.wp-core-ui .button-danger,.wp-core-ui .button-danger.focus,.wp-core-ui .button-danger.hover,.wp-core-ui .button-danger:focus,.wp-core-ui .button-danger:hover{background:#cd5050;border-color:#a52121;text-shadow:0 -1px 1px #99000e,1px 0 1px #99000e,0 1px 1px #99000e,-1px 0 1px #99000e}.wp-core-ui .button-danger.focus,.wp-core-ui .button-danger.hover,.wp-core-ui .button-danger:focus,.wp-core-ui .button-danger:hover{background:#be4242}.wp-core-ui .button-danger.focus,.wp-core-ui .button-danger:focus{border-color:#500e0e}.wp-core-ui .button-danger.active,.wp-core-ui .button-danger.active:focus,.wp-core-ui .button-danger.active:hover,.wp-core-ui .button-danger:active{background:#a61b1b;border-color:#840000}.wp-core-ui .button-danger-disabled,.wp-core-ui .button-danger.disabled,.wp-core-ui .button-danger:disabled,.wp-core-ui .button-danger[disabled]{color:#e79494!important;background:#ba2929!important;border-color:#7f1b1b!important}.wp-core-ui .sucuriscan-btnblock{display:block;width:100%;text-align:center}.sucuriscan-overlay{position:fixed;top:0;left:0;bottom:0;right:0;z-index:9990;background:#666;background:rgba(0,0,0,.5)}.sucuriscan-modal{position:absolute;top:25px;left:15%;z-index:9990;width:65%}.sucuriscan-modal-outside{position:relative;left:0;border:1px solid #ddd}.sucuriscan-modal-inside{background:#fff;padding:20px}.sucuriscan-modal-header{padding:0;border-bottom:1px solid #ddd}#poststuff h3.sucuriscan-modal-title,.sucuriscan-leftside #poststuff h3.sucuriscan-modal-title,.sucuriscan-modal-header .sucuriscan-modal-title{margin:0 0 0 10px;padding:0;float:left;line-height:38px;border-bottom:0}.sucuriscan-modal-header .sucuriscan-modal-logo{display:inline-block;float:left;margin-top:8px;margin-left:18px}.sucuriscan-modal-header .sucuriscan-modal-logo img{height:22px}.sucuriscan-modal-close{display:inline-block;position:absolute;top:0;right:0;font-size:16px;font-weight:700;text-decoration:none;line-height:38px;padding:0 15px;border-left:1px solid #ddd}.sucuriscan-modal-inside p:first-child{margin-top:0}.sucuriscan-panelstuff .inside{margin:6px 0 0}.postbox .inside p:last-child,.sucuriscan-modal-inside p:last-child{margin-bottom:0}.sucuriscan-label,.sucuriscan-label-danger,.sucuriscan-label-default,.sucuriscan-label-error,.sucuriscan-label-info,.sucuriscan-label-notice,.sucuriscan-label-primary,.sucuriscan-label-success,.sucuriscan-label-unknown,.sucuriscan-label-warning{display:inline;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;padding:.2em .6em .3em;border-radius:.25em}.sucuriscan-label-default,.sucuriscan-label-unknown{background:#777}.sucuriscan-label-danger,.sucuriscan-label-error{background:#d9534f}.sucuriscan-label-info,.sucuriscan-label-notice{background:#5bc0de}.sucuriscan-label-warning{background:#f0ad4e}.sucuriscan-label-success{background:#5cb85c}.sucuriscan-label-primary{background:#428bca}.sucuriscan-wrap{margin-top:20px}.sucuriscan-wrap .sucuriscan-maincontent{margin:20px 0}.sucuriscan-wrap .sucuriscan-leftside{width:73.5%;float:left}.sucuriscan-wrap .sucuriscan-onecolumn{width:100%}.sucuriscan-wrap .sucuriscan-sidebar{width:25%;float:right}.sucuriscan-wrap #warnings_hook{line-height:normal;padding:0}.sucuriscan-wrap .sucuriscan-navbar{padding-top:20px;padding-left:6px}.sucuriscan-wrap .sucuriscan-navbar .nav-tab{margin-right:0}.sucuriscan-footer,.sucuriscan-header{position:relative;min-width:255px;background:#333;margin:0;padding:10px;border-radius:4px}.sucuriscan-footer .sucuriscan-help{color:#fff;float:right;text-align:right}.sucuriscan-footer .sucuriscan-help p{line-height:38px;margin:0 10px 0 0;padding:0}.sucuriscan-wrap .sucuriscan-footer h2,.sucuriscan-wrap .sucuriscan-header h2,.sucuriscan-wrap .sucuriscan-logo{float:left;margin:0;padding:0}.sucuriscan-wrap .sucuriscan-logo{display:inline-block}.sucuriscan-wrap .sucuriscan-logo img{display:block}.sucuriscan-wrap .sucuriscan-footer h2,.sucuriscan-wrap .sucuriscan-header h2{color:#fff;line-height:38px;margin-left:10px;text-shadow:#000 0 1px 0}.sucuriscan-leftside #poststuff .postbox:last-child,.sucuriscan-leftside .sucuriscan-panelstuff .postbox:last-child{margin-bottom:0}.sucuriscan-leftside #poststuff .postbox h3,.sucuriscan-leftside .sucuriscan-panelstuff .postbox h3{margin:0;padding:10px;border-bottom:1px solid #ddd}.sucuriscan-maincontent abbr{text-decoration:underline;cursor:help}.wrap div.sucuriscan-setup-notice{background:#bbe8f5;margin:0 0 20px;padding:0;border:1px solid #bbb;border-radius:3px;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.wrap div.sucuriscan-setup-notice .sucuriscan-setup-image,.wrap div.sucuriscan-setup-notice .sucuriscan-setup-image img{border-radius:3px 0 0 3px}.wrap div.sucuriscan-setup-notice .sucuriscan-setup-image{background:#333;margin:-1px 0 -1px -1px;padding:7px 10px;border-right:1px solid transparent}.wrap div.sucuriscan-setup-notice .sucuriscan-setup-form{padding:4px 4px 4px 0}.wrap div.sucuriscan-setup-notice p{font-size:14px;line-height:20px;margin:0 0 0 10px;padding:7px 0}.wrap div.sucuriscan-setup-notice,.wrap div.sucuriscan-setup-notice .sucuriscan-setup-image{border-color:#4393ac}.wp-core-ui .button.sucuriscan-review-hero,.wp-core-ui .sucuriscan-review-hero{height:initial;line-height:36px;float:right;padding:0 20px}.sucuriscan-input-group>label{display:inline-block;border:1px solid #ddd;border-right:0;line-height:26px;float:left;padding:0 10px;background:#eee}.sucuriscan-input-group>input[type=text]{margin:0;padding-bottom:4px}.sucuriscan-input-group>select{vertical-align:initial;margin:0}.sucuriscan-table-setup td{vertical-align:top}.sucuriscan-table-setup .sucuriscan-description{font-size:12px;margin-top:10px}.sucuriscan-dismiss-setup{font-size:10px;line-height:28px}.sucuriscan-maincontent .sucuriscan-table{margin-top:12px}.sucuriscan-maincontent .sucuriscan-table tr>th{border-top:1px solid #e5e5e5;border-bottom:1px solid #e5e5e5}.sucuriscan-maincontent .sucuriscan-table tr:first-child th{border-top:0}.sucuriscan-maincontent .sucuriscan-table td.check-column{padding:8px 10px}.sucuriscan-maincontent .sucuriscan-striped-table tr:nth-child(even){background:#f5f5f5}.sucuriscan-table-double-title tr:first-child th,.sucuriscan-table-quad-title tr:first-child th,.sucuriscan-table-quad-title tr:first-child+tr th,.sucuriscan-table-quad-title tr:first-child+tr+tr th,.sucuriscan-table-triple-title tr:first-child th,.sucuriscan-table-triple-title tr:first-child+tr th{border-bottom:0}.sucuriscan-table-description{border-left-width:1px!important;box-shadow:none}.sucuriscan-table-description .inside{border-bottom:0!important}.widefat td.td-with-button{text-align:right;padding:3px 10px}.widefat td.td-with-button button{min-width:90px}.widefat td.td-with-button select{height:initial;line-height:initial;vertical-align:top;margin:0;padding:2px 0 3px}.widefat th.check-column{line-height:36px;padding:0}.widefat th.check-column input[type=checkbox]{margin:1px 0 0 10px}.sucuriscan-list-as-table{background:#fff;border:1px solid #e5e5e5}.sucuriscan-list-as-table li{line-height:30px;word-break:break-all;margin:0;padding:0 10px}.sucuriscan-list-as-table li:nth-child(odd){background:#f5f5f5}.sucuriscan-list-as-table-scrollable{height:300px;overflow:hidden;overflow-y:scroll}.sucuriscan-maincontent .thead-with-button{padding:5px 5px 5px 10px}.sucuriscan-maincontent .thead-with-button>span{display:inline-block;line-height:28px}.sucuriscan-maincontent .thead-with-button .input-text{line-height:26px}.sucuriscan-maincontent .thead-with-button select{margin:0;padding:0}.sucuriscan-maincontent .thead-topright-action{display:inline-block;float:right}.sucuriscan-ad{color:#fff;padding:20px;margin-bottom:20px}.sucuriscan-ad .sucuriscan-ad-btn,.sucuriscan-ad h3,.sucuriscan-ad h4{font-family:Arial,Helvetica,sans-serif;color:#fff;margin:0}.sucuriscan-ad h3{font-size:18px;font-weight:300}.sucuriscan-ad h4{font-size:22px;font-weight:700;margin-top:10px}.sucuriscan-ad .sucuriscan-ad-btn{display:block;font-size:13px;font-weight:700;text-align:center;text-decoration:none;text-transform:uppercase;margin-top:20px;padding:5px;border-radius:20px}.sucuriscan-ad .sucuriscan-ad-footer{margin-top:20px;margin-bottom:0}.sucuriscan-ad .sucuriscan-ad-footer ul{margin:0}.sucuriscan-ad .sucuriscan-ad-footer li{font-size:12px;color:#fff;list-style:disc;margin:0 0 0 16px}.sucuriscan-ad .sucuriscan-ad-footer li.featured{color:#fde44c}.sucuriscan-scanner-video{width:100%;background:#fff;border:1px solid #ddd}.sucuriscan-sidebar .sucuriscan-supportbtn{width:100%;height:initial;text-align:center;line-height:36px;margin-top:15px;padding:0}.sucuriscan-hide-ads{min-height:initial!important;margin-top:15px}.sucuriscan-hide-ads .button-link{text-decoration:underline}.sucuriscan-hide-ads-instructions{border:1px solid #ddd;background:#fff;margin-top:15px;padding:10px}.sucuriscan-hide-ads .button-link,.sucuriscan-hide-ads-instructions,.sucuriscan-hide-ads-instructions code{font-size:11px}.sucuriscan-hide-ads-instructions code{display:block;margin-top:5px}.sucuriscan-ad-firewall{background:#606e77}.sucuriscan-ad-firewall .sucuriscan-ad-btn{background:#606e77;border:1px solid #fff}.sucuriscan-ad-firewall .sucuriscan-ad-btn:hover{background:#85929b}.sucuriscan-ad-antivirus{background:#04833e;padding-bottom:0}.sucuriscan-ad-antivirus .sucuriscan-ad-website{display:block;text-decoration:none;margin-top:20px}.sucuriscan-ad-antivirus .sucuriscan-ad-website img{display:block;max-width:100%}.sucuriscan-ad-antivirus .sucuriscan-ad-btn{background-color:#e8840a;background-image:-webkit-gradient(linear,left top,left bottom,from(#e8840a),to(#ef7f02));background-image:-webkit-linear-gradient(top,#e8840a,#ef7f02);background-image:-moz-linear-gradient(top,#e8840a,#ef7f02);background-image:-ms-linear-gradient(top,#e8840a,#ef7f02);background-image:-o-linear-gradient(top,#e8840a,#ef7f02);background-image:linear-gradient(top,#e8840a,#ef7f02);filter:"progid: DXImageTransform.Microsoft.Gradient(startColorstr=#e8840a, endColorstr=#ef7f02)";-ms-filter:"progid: DXImageTransform.Microsoft.Gradient(startColorstr=#e8840a, endColorstr=#ef7f02)";box-shadow:inset 0 1px 1px #eaac3a;border:1px solid #d17301}div.sucuriscan-alert{position:relative;margin:0 0 20px}div.sucuriscan-alert>a.close{position:absolute;top:10px;right:10px;font-size:18px;font-weight:700;text-decoration:none}.sucuriscan-inline-alert,.sucuriscan-inline-alert-error,.sucuriscan-inline-alert-info,.sucuriscan-inline-alert-updated,.sucuriscan-inline-alert-warning{background:#fff;box-shadow:0 1px 1px 0 rgba(0,0,0,.1);padding:0;border-left:4px solid #ddd}.sucuriscan-inline-alert-error>p,.sucuriscan-inline-alert-info>p,.sucuriscan-inline-alert-updated>p,.sucuriscan-inline-alert-warning>p,.sucuriscan-inline-alert>p{margin:0;padding:8px 12px;border:1px solid #ddd;border-left:0}.sucuriscan-inline-alert,.sucuriscan-inline-alert-error,.sucuriscan-inline-alert-info,.sucuriscan-inline-alert-updated,.sucuriscan-inline-alert-warning{margin-bottom:10px}.postbox .inside .sucuriscan-inline-alert-error:last-child,.postbox .inside .sucuriscan-inline-alert-info:last-child,.postbox .inside .sucuriscan-inline-alert-updated:last-child,.postbox .inside .sucuriscan-inline-alert-warning:last-child,.postbox .inside .sucuriscan-inline-alert:last-child,.sucuriscan-tabs>ul li{margin-bottom:0}.sucuriscan-inline-alert-updated{border-left-color:#7ad03a}.sucuriscan-inline-alert-warning{border-left-color:#ffba00}.sucuriscan-inline-alert-error{border-left-color:#dd3d36}.sucuriscan-inline-alert-info{border-left-color:#2ea2cc}.sucuriscan-tabs>ul{margin:0}.sucuriscan-tabs>ul li,.sucuriscan-tabs>ul li>a{display:inline-block}.sucuriscan-tabs>ul li>a{background:#e5e5e5;font-size:13px;font-weight:700;color:#333;line-height:38px;text-decoration:none;padding:0 10px}.sucuriscan-tabs>ul li>a.sucuriscan-tab-active{background:#fff;border:1px solid #e1e1e1;border-bottom:0}.sucuriscan-tabs>ul li.sucuriscan-red-tab a{background:#ff8a83;color:#fff}.sucuriscan-tabs>ul li.sucuriscan-red-tab a.sucuriscan-tab-active{background:#dd3d36;border-color:#dd3d36}.sucuriscan-maincontent .sucuriscan-tab-containers>div>#poststuff,.sucuriscan-maincontent .sucuriscan-tab-containers>div>table,.sucuriscan-panelstuff{margin-top:0}.sucuriscan-getapi-div{background:#fff;margin:0 0 20px;border:1px solid #e5e5e5;border-radius:3px}.sucuriscan-getapi-div p{margin:0;padding:10px}.sucuriscan-getapi-form button.button-primary{width:100%;height:initial;line-height:30px;margin:0 0 -1px;padding:0;border-radius:0 0 3px 3px}.sucuriscan-malwarescan-message{margin-bottom:20px!important}.sucuriscan-loading{background:#fff;text-align:center;padding:30px 30px 15px;border:1px solid #ddd;border-radius:4px}.sucuriscan-loading h3,.sucuriscan-loading p{margin:0;padding:0}.sucuriscan-loading .title{font-size:28px;margin-bottom:10px}.sucuriscan-loading .description{font-size:16px}.sucuriscan-sitelogo{width:190px;height:100px;background:url(https://sitecheck.sucuri.net/images/sucuri-sprite.png) no-repeat;margin:0 auto}.sucuriscan-sitecheck-form{margin:20px 0 0}.sucuriscan-sitecheck-form .button.button-hero{padding:0 46px}.sucuriscan-loading .sucuriscan-sitecheck-disclaimer{text-align:justify;padding-top:20px;border-top:1px solid #ddd}.sucuriscan-auditlogs .sucuriscan-maxper-page,.sucuriscan-scanner-results .sucuriscan-malware-link{text-align:right}.sucuriscan-loading .sucuriscan-sitecheck-disclaimer p{font-size:10px}.sucuriscan-maincontent .sucuriscan-border{border:0;border-left:4px solid #ddd}.sucuriscan-maincontent .sucuriscan-border>.inside,.sucuriscan-maincontent .sucuriscan-border>h3{border-top:1px solid #e5e5e5;border-right:1px solid #e5e5e5}.sucuriscan-maincontent .sucuriscan-border>h3{border-bottom:0}.sucuriscan-maincontent .sucuriscan-border>.inside{margin-top:0!important;border-bottom:1px solid #ddd}.sucuriscan-maincontent .sucuriscan-border-good,.sucuriscan-maincontent .sucuriscan-border-success{border-left-color:#7ad03a}.sucuriscan-maincontent .sucuriscan-border-bad,.sucuriscan-maincontent .sucuriscan-border-danger{border-left-color:#dd3d36}.sucuriscan-maincontent .sucuriscan-border-info{border-left-color:#2ea2cc}.sucuriscan-maincontent .sucuriscan-cleanup-btn{margin:20px 0 0}.sucuriscan-scanner-results .sucuriscan-scanner-details tr:nth-child(even),.sucuriscan-scanner-results .sucuriscan-scanner-links tr:nth-child(even){background:#f5f5f5}.sucuriscan-scanner-results td.sucuriscan-border-bad{border-left-width:4px;border-left-style:solid}.sucuriscan-scanner-results .sucuriscan-malware-link a:hover{color:#fff}.sucuriscan-malware-payload{background:#f5f5f5;margin:-2px -15px -15px;padding:15px}.sucuriscan-maincontent .sucuriscan-auditlogs,.sucuriscan-maincontent .sucuriscan-corefiles,.sucuriscan-maincontent .sucuriscan-wordpress-outdated{margin-top:0;margin-bottom:20px}.sucuriscan-auditlogs .sucuriscan-list-as-table,.sucuriscan-maincontent .sucuriscan-auditlogs{margin-bottom:0}.sucuriscan-auditlogs .sucuriscan-pagination-loading{line-height:32px;color:#666}.sucuriscan-auditlogs .sucuriscan-label{display:inline-block;width:18px;text-transform:uppercase;line-height:13px;cursor:pointer;border-radius:50%}.sucuriscan-auditlogs .sucuriscan-auditlog-success,.sucuriscan-label-added{background:#5cb85c}.sucuriscan-auditlogs .sucuriscan-auditlog-debug{background:#c690ec}.sucuriscan-auditlogs .sucuriscan-auditlog-info{background:#5bc0de}.sucuriscan-auditlogs .sucuriscan-auditlog-notice{background:#428bca}.sucuriscan-auditlogs .sucuriscan-auditlog-warning,.sucuriscan-label-modified{background:#f0ad4e}.sucuriscan-auditlogs .sucuriscan-auditlog-error,.sucuriscan-label-removed{background:#f27d7d}.sucuriscan-auditlogs .sucuriscan-auditlog-critical{background:#000}.sucuriscan-maincontent .sucuriscan-audit-report{border-left-width:1px}.sucuriscan-audit-report .sucuriscan-report-row{margin-bottom:10px}.sucuriscan-audit-report .sucuriscan-report-row:last-child,.sucuriscan-maincontent .sucuriscan-corefiles{margin-bottom:0}.sucuriscan-audit-report .sucuriscan-report-chart{width:49%;border:1px solid #ddd}.sucuriscan-audit-report .sucuriscan-report-chart h4,.sucuriscan-audit-report .sucuriscan-report-chart h5{font-weight:400;text-align:center;margin:0}.sucuriscan-firewall-accesslog .sucuriscan-accesslog-label,.sucuriscan-request-summary tr td:first-child{font-weight:700}.sucuriscan-audit-report .sucuriscan-report-chart h4{font-size:18px;margin-top:10px}.sucuriscan-audit-report .sucuriscan-report-chart h5{font-size:12px;margin-top:5px}.sucuriscan-firewall-auditlogs .sucuriscan-denial-type,.sucuriscan-request-summary td{font-size:14px}.sucuriscan-maincontent .sucuriscan-audit-report .sucuriscan-inline-alert-info{margin-top:10px}.sucuriscan-status-type{display:inline-block;width:20px;background:#ddd;text-align:center;text-transform:uppercase;margin-right:10px;padding:0 3px;border:1px solid transparent;border-radius:3px}.sucuriscan-maincontent .sucuriscan-corefiles .sucuriscan-label{text-transform:capitalize}.sucuriscan-maincontent .sucuriscan-ignoredfiles{margin-top:0}.sucuriscan-maincontent .sucuriscan-modifiedfiles .sucuriscan-ellipsis{width:100px}.sucuriscan-maincontent .sucuriscan-firewall-apikey{margin-bottom:10px}.sucuriscan-firewall-settings .sucuriscan-list-as-table{margin-top:4px;margin-bottom:4px}.sucuriscan-firewall-auditlogs .thead-with-button .button{width:65px}.sucuriscan-firewall-auditlogs .thead-with-button .input-text,.sucuriscan-firewall-auditlogs .thead-with-button select{width:250px}.sucuriscan-firewall-auditlogs .sucuriscan-denial-type-date{font-style:italic;color:#999}.sucuriscan-firewall-auditlogs .sucuriscan-alert,.wrap .sucuriscan-firewall-auditlogs .error,.wrap .sucuriscan-firewall-auditlogs .updated{background:#eee;border:1px solid #ddd;border-left-width:4px;margin:10px}.sucuriscan-firewall-accesslog .sucuriscan-accesslog-origin img{margin-right:6px}.sucuriscan-firewall-accesslog .sucuriscan-accesslog-datetime,.sucuriscan-firewall-accesslog .sucuriscan-accesslog-origin,.sucuriscan-firewall-accesslog .sucuriscan-accesslog-referer,.sucuriscan-firewall-accesslog .sucuriscan-accesslog-request,.sucuriscan-firewall-accesslog .sucuriscan-accesslog-signature,.sucuriscan-firewall-accesslog .sucuriscan-accesslog-target,.sucuriscan-firewall-accesslog .sucuriscan-accesslog-useragent{display:block;padding-left:30px}.sucuriscan-firewall-accesslog .sucuriscan-accesslog-origin{padding-left:0}.sucuriscan-request-summary{margin:-3px -15px -15px}.sucuriscan-hstatus{position:relative;margin:0 -12px;padding:10px 12px;border:1px solid transparent}.sucuriscan-hstatus-0{background-color:#f2dede;color:#a94442;border-color:#ebccd1}.sucuriscan-hstatus-1{background-color:#dff0d8;color:#3c763d;border-color:#d6e9c6}.sucuriscan-hstatus-2{background-color:#dee4f2;color:#4263a9;border-color:#ccd0eb}.sucuriscan-hstatus .button-primary,.sucuriscan-hstatus .button-secondary{position:absolute;top:5px;right:5px}.sucuriscan-hardening-whitelist form{margin-top:15px}.sucuriscan-hardening-whitelist form label{line-height:29px;font-size:12px;background-color:#eee;padding:0 10px;display:inline-block;border:1px solid #ddd;border-right:0}.sucuriscan-hardening-whitelist form input[type=text]{margin:0;padding:5px}.sucuriscan-hardening-whitelist form select{height:initial;padding:4px;margin:0}.sucuriscan-hardening-whitelist form .button,.sucuriscan-hardening-whitelist form input[type=text],.sucuriscan-hardening-whitelist form select{margin-right:5px}.sucuriscan-maincontent .sucuriscan-table.sucuriscan-hardening-whitelist-table{margin-top:0}.sucuriscan-lastlogin-outof{font-style:italic;color:#999;margin-right:10px}.sucuriscan-admins-lastlogins .sucuriscan-ellipsis{width:170px}.sucuriscan-admins-lastlogins td{padding:4px 8px}.sucuriscan-pattern-search-inputbox{margin-top:12px}.sucuriscan-pattern-search-inputbox .input-text{width:84.7777%;line-height:30px;margin:0 6px 0 0}.sucuriscan-pattern-search-inputbox .input-button{width:14%;height:initial;line-height:35px}.sucuriscan-pattern-search .sucuriscan-cleanup-btn{margin-top:12px}.sucuriscan-pattern-search table label{color:#999}.sucuriscan-pattern-search .sucuriscan-grep-text em{color:#ea3838}.sucuriscan-updates .dashicons-before:before{margin-right:10px}.sucuriscan-updates .dashicons-admin-plugins{color:#32373c}.sucuriscan-updates .dashicons-admin-appearance{color:#d54e21}.sucuriscan-about ul{margin-left:20px}.sucuriscan-about ul li{list-style:outside}.sucuriscan-about li label{font-weight:700;vertical-align:initial}.sucuriscan-apikey-registered .sucuriscan-pull-right{width:400px}.sucuriscan-apikey-registered .sucuriscan-sitelogo{background-position:0 -17px;height:83px}.sucuriscan-setup-instructions .form-table{margin-top:15px}.sucuriscan-setup-instructions .form-table td{padding:0 0 12px}.sucuriscan-setup-instructions .form-table select{max-width:400px}.sucuriscan-pagination{display:inline-block;margin:0;padding:0;border-radius:4px}.sucuriscan-pagination>li{display:inline}.c3-tooltip td>span,.sucuriscan-maincontent .sucuriscan-settings form{display:inline-block}.sucuriscan-pagination>li>a,.sucuriscan-pagination>li>span{position:relative;background:#fff;color:#428bca;line-height:1.42857143;text-decoration:none;float:left;margin-left:-1px;padding:6px 12px;border:1px solid #ddd}.sucuriscan-pagination>li:first-child>a,.sucuriscan-pagination>li:first-child>span{margin-left:0;border-radius:4px 0 0 4px}.sucuriscan-pagination>li:last-child>a,.sucuriscan-pagination>li:last-child>span{border-radius:0 4px 4px 0}.sucuriscan-pagination>li>a.sucuriscan-pagination-active,.sucuriscan-pagination>li>a:hover{background:#0074a2;color:#fff}.sucuriscan_wpconfig_keys_updated textarea{width:100%;height:250px;background:#f5f5f5;font-size:12px;resize:vertical;margin:20px 0 0}.sucuriscan-maincontent .sucuriscan-last-logins,.sucuriscan-maincontent .sucuriscan-settings{margin-top:0}.sucuriscan-maincontent .sucuriscan-last-logins .sucuriscan-ellipsis{width:150px;line-height:inherit}.sucuriscan-maincontent .sucuriscan-full-textarea{width:100%;height:400px;line-height:normal;resize:vertical;padding:10px}.sucuriscan-maincontent .sucuriscan-settings .input-text,.sucuriscan-maincontent .sucuriscan-settings select{width:220px;margin:0}.sucuriscan-maincontent .sucuriscan-infosys-htaccess .inside .sucuriscan-inline-alert-updated,.sucuriscan-maincontent .sucuriscan-monitor-fpath{margin-bottom:10px}.sucuriscan-maincontent .sucuriscan-recipient-form{margin-top:10px}.sucuriscan-maincontent .sucuriscan-settings-ignorescanning,.sucuriscan-maincontent .sucuriscan-settings-notifications,.sucuriscan-maincontent .sucuriscan-settings-trustip,.sucuriscan-maincontent .sucuriscan-wpcron-list{margin-top:0}.sucuriscan-maincontent .sucuriscan-settings-notifications .dashicons-before:before{margin-right:5px}.sucuriscan-maincontent .sucuriscan-infosys-htaccess .inside{border-bottom:1px solid #ddd!important}.sucuriscan-maincontent .sucuriscan-errorlogs .inside .sucuriscan-inline-alert-error{margin-top:10px}.sucuriscan-maincontent .sucuriscan-subject-formats{margin:0}.sucuriscan-maincontent .sucuriscan-subject-formats input[type=text]{width:40%;margin-left:10px}.sucuriscan-flag{width:16px;height:11px;background:url(../images/flags.sprite.png) no-repeat}.sucuriscan-flag-ad{background-position:-16px 0}.sucuriscan-flag-ae{background-position:-32px 0}.sucuriscan-flag-af{background-position:-48px 0}.sucuriscan-flag-ag{background-position:-64px 0}.sucuriscan-flag-ai{background-position:-80px 0}.sucuriscan-flag-al{background-position:-96px 0}.sucuriscan-flag-am{background-position:-112px 0}.sucuriscan-flag-an{background-position:-128px 0}.sucuriscan-flag-ao{background-position:-144px 0}.sucuriscan-flag-ar{background-position:-160px 0}.sucuriscan-flag-as{background-position:-176px 0}.sucuriscan-flag-at{background-position:-192px 0}.sucuriscan-flag-au{background-position:-208px 0}.sucuriscan-flag-aw{background-position:-224px 0}.sucuriscan-flag-az{background-position:-240px 0}.sucuriscan-flag-ba{background-position:0 -11px}.sucuriscan-flag-bb{background-position:-16px -11px}.sucuriscan-flag-bd{background-position:-32px -11px}.sucuriscan-flag-be{background-position:-48px -11px}.sucuriscan-flag-bf{background-position:-64px -11px}.sucuriscan-flag-bg{background-position:-80px -11px}.sucuriscan-flag-bh{background-position:-96px -11px}.sucuriscan-flag-bi{background-position:-112px -11px}.sucuriscan-flag-bj{background-position:-128px -11px}.sucuriscan-flag-bm{background-position:-144px -11px}.sucuriscan-flag-bn{background-position:-160px -11px}.sucuriscan-flag-bo{background-position:-176px -11px}.sucuriscan-flag-br{background-position:-192px -11px}.sucuriscan-flag-bs{background-position:-208px -11px}.sucuriscan-flag-bt{background-position:-224px -11px}.sucuriscan-flag-bv{background-position:-240px -11px}.sucuriscan-flag-bw{background-position:0 -22px}.sucuriscan-flag-by{background-position:-16px -22px}.sucuriscan-flag-bz{background-position:-32px -22px}.sucuriscan-flag-ca{background-position:-48px -22px}.sucuriscan-flag-catalonia{background-position:-64px -22px}.sucuriscan-flag-cd{background-position:-80px -22px}.sucuriscan-flag-cf{background-position:-96px -22px}.sucuriscan-flag-cg{background-position:-112px -22px}.sucuriscan-flag-ch{background-position:-128px -22px}.sucuriscan-flag-ci{background-position:-144px -22px}.sucuriscan-flag-ck{background-position:-160px -22px}.sucuriscan-flag-cl{background-position:-176px -22px}.sucuriscan-flag-cm{background-position:-192px -22px}.sucuriscan-flag-cn{background-position:-208px -22px}.sucuriscan-flag-co{background-position:-224px -22px}.sucuriscan-flag-cr{background-position:-240px -22px}.sucuriscan-flag-cu{background-position:0 -33px}.sucuriscan-flag-cv{background-position:-16px -33px}.sucuriscan-flag-cw{background-position:-32px -33px}.sucuriscan-flag-cy{background-position:-48px -33px}.sucuriscan-flag-cz{background-position:-64px -33px}.sucuriscan-flag-de{background-position:-80px -33px}.sucuriscan-flag-dj{background-position:-96px -33px}.sucuriscan-flag-dk{background-position:-112px -33px}.sucuriscan-flag-dm{background-position:-128px -33px}.sucuriscan-flag-do{background-position:-144px -33px}.sucuriscan-flag-dz{background-position:-160px -33px}.sucuriscan-flag-ec{background-position:-176px -33px}.sucuriscan-flag-ee{background-position:-192px -33px}.sucuriscan-flag-eg{background-position:-208px -33px}.sucuriscan-flag-eh{background-position:-224px -33px}.sucuriscan-flag-england{background-position:-240px -33px}.sucuriscan-flag-er{background-position:0 -44px}.sucuriscan-flag-es{background-position:-16px -44px}.sucuriscan-flag-et{background-position:-32px -44px}.sucuriscan-flag-eu{background-position:-48px -44px}.sucuriscan-flag-fi{background-position:-64px -44px}.sucuriscan-flag-fj{background-position:-80px -44px}.sucuriscan-flag-fk{background-position:-96px -44px}.sucuriscan-flag-fm{background-position:-112px -44px}.sucuriscan-flag-fo{background-position:-128px -44px}.sucuriscan-flag-fr{background-position:-144px -44px}.sucuriscan-flag-ga{background-position:-160px -44px}.sucuriscan-flag-gb{background-position:-176px -44px}.sucuriscan-flag-gd{background-position:-192px -44px}.sucuriscan-flag-ge{background-position:-208px -44px}.sucuriscan-flag-gf{background-position:-224px -44px}.sucuriscan-flag-gg{background-position:-240px -44px}.sucuriscan-flag-gh{background-position:0 -55px}.sucuriscan-flag-gi{background-position:-16px -55px}.sucuriscan-flag-gl{background-position:-32px -55px}.sucuriscan-flag-gm{background-position:-48px -55px}.sucuriscan-flag-gn{background-position:-64px -55px}.sucuriscan-flag-gp{background-position:-80px -55px}.sucuriscan-flag-gq{background-position:-96px -55px}.sucuriscan-flag-gr{background-position:-112px -55px}.sucuriscan-flag-gs{background-position:-128px -55px}.sucuriscan-flag-gt{background-position:-144px -55px}.sucuriscan-flag-gu{background-position:-160px -55px}.sucuriscan-flag-gw{background-position:-176px -55px}.sucuriscan-flag-gy{background-position:-192px -55px}.sucuriscan-flag-hk{background-position:-208px -55px}.sucuriscan-flag-hm{background-position:-224px -55px}.sucuriscan-flag-hn{background-position:-240px -55px}.sucuriscan-flag-hr{background-position:0 -66px}.sucuriscan-flag-ht{background-position:-16px -66px}.sucuriscan-flag-hu{background-position:-32px -66px}.sucuriscan-flag-ic{background-position:-48px -66px}.sucuriscan-flag-id{background-position:-64px -66px}.sucuriscan-flag-ie{background-position:-80px -66px}.sucuriscan-flag-il{background-position:-96px -66px}.sucuriscan-flag-im{background-position:-112px -66px}.sucuriscan-flag-in{background-position:-128px -66px}.sucuriscan-flag-io{background-position:-144px -66px}.sucuriscan-flag-iq{background-position:-160px -66px}.sucuriscan-flag-ir{background-position:-176px -66px}.sucuriscan-flag-is{background-position:-192px -66px}.sucuriscan-flag-it{background-position:-208px -66px}.sucuriscan-flag-je{background-position:-224px -66px}.sucuriscan-flag-jm{background-position:-240px -66px}.sucuriscan-flag-jo{background-position:0 -77px}.sucuriscan-flag-jp{background-position:-16px -77px}.sucuriscan-flag-ke{background-position:-32px -77px}.sucuriscan-flag-kg{background-position:-48px -77px}.sucuriscan-flag-kh{background-position:-64px -77px}.sucuriscan-flag-ki{background-position:-80px -77px}.sucuriscan-flag-km{background-position:-96px -77px}.sucuriscan-flag-kn{background-position:-112px -77px}.sucuriscan-flag-kp{background-position:-128px -77px}.sucuriscan-flag-kr{background-position:-144px -77px}.sucuriscan-flag-kurdistan{background-position:-160px -77px}.sucuriscan-flag-kw{background-position:-176px -77px}.sucuriscan-flag-ky{background-position:-192px -77px}.sucuriscan-flag-kz{background-position:-208px -77px}.sucuriscan-flag-la{background-position:-224px -77px}.sucuriscan-flag-lb{background-position:-240px -77px}.sucuriscan-flag-lc{background-position:0 -88px}.sucuriscan-flag-li{background-position:-16px -88px}.sucuriscan-flag-lk{background-position:-32px -88px}.sucuriscan-flag-lr{background-position:-48px -88px}.sucuriscan-flag-ls{background-position:-64px -88px}.sucuriscan-flag-lt{background-position:-80px -88px}.sucuriscan-flag-lu{background-position:-96px -88px}.sucuriscan-flag-lv{background-position:-112px -88px}.sucuriscan-flag-ly{background-position:-128px -88px}.sucuriscan-flag-ma{background-position:-144px -88px}.sucuriscan-flag-mc{background-position:-160px -88px}.sucuriscan-flag-md{background-position:-176px -88px}.sucuriscan-flag-me{background-position:-192px -88px}.sucuriscan-flag-mg{background-position:-208px -88px}.sucuriscan-flag-mh{background-position:-224px -88px}.sucuriscan-flag-mk{background-position:-240px -88px}.sucuriscan-flag-ml{background-position:0 -99px}.sucuriscan-flag-mm{background-position:-16px -99px}.sucuriscan-flag-mn{background-position:-32px -99px}.sucuriscan-flag-mo{background-position:-48px -99px}.sucuriscan-flag-mp{background-position:-64px -99px}.sucuriscan-flag-mq{background-position:-80px -99px}.sucuriscan-flag-mr{background-position:-96px -99px}.sucuriscan-flag-ms{background-position:-112px -99px}.sucuriscan-flag-mt{background-position:-128px -99px}.sucuriscan-flag-mu{background-position:-144px -99px}.sucuriscan-flag-mv{background-position:-160px -99px}.sucuriscan-flag-mw{background-position:-176px -99px}.sucuriscan-flag-mx{background-position:-192px -99px}.sucuriscan-flag-my{background-position:-208px -99px}.sucuriscan-flag-mz{background-position:-224px -99px}.sucuriscan-flag-na{background-position:-240px -99px}.sucuriscan-flag-nc{background-position:0 -110px}.sucuriscan-flag-ne{background-position:-16px -110px}.sucuriscan-flag-nf{background-position:-32px -110px}.sucuriscan-flag-ng{background-position:-48px -110px}.sucuriscan-flag-ni{background-position:-64px -110px}.sucuriscan-flag-nl{background-position:-80px -110px}.sucuriscan-flag-no{background-position:-96px -110px}.sucuriscan-flag-np{background-position:-112px -110px}.sucuriscan-flag-nr{background-position:-128px -110px}.sucuriscan-flag-nu{background-position:-144px -110px}.sucuriscan-flag-nz{background-position:-160px -110px}.sucuriscan-flag-om{background-position:-176px -110px}.sucuriscan-flag-pa{background-position:-192px -110px}.sucuriscan-flag-pe{background-position:-208px -110px}.sucuriscan-flag-pf{background-position:-224px -110px}.sucuriscan-flag-pg{background-position:-240px -110px}.sucuriscan-flag-ph{background-position:0 -121px}.sucuriscan-flag-pk{background-position:-16px -121px}.sucuriscan-flag-pl{background-position:-32px -121px}.sucuriscan-flag-pm{background-position:-48px -121px}.sucuriscan-flag-pn{background-position:-64px -121px}.sucuriscan-flag-pr{background-position:-80px -121px}.sucuriscan-flag-ps{background-position:-96px -121px}.sucuriscan-flag-pt{background-position:-112px -121px}.sucuriscan-flag-pw{background-position:-128px -121px}.sucuriscan-flag-py{background-position:-144px -121px}.sucuriscan-flag-qa{background-position:-160px -121px}.sucuriscan-flag-re{background-position:-176px -121px}.sucuriscan-flag-ro{background-position:-192px -121px}.sucuriscan-flag-rs{background-position:-208px -121px}.sucuriscan-flag-ru{background-position:-224px -121px}.sucuriscan-flag-rw{background-position:-240px -121px}.sucuriscan-flag-sa{background-position:0 -132px}.sucuriscan-flag-sb{background-position:-16px -132px}.sucuriscan-flag-sc{background-position:-32px -132px}.sucuriscan-flag-scotland{background-position:-48px -132px}.sucuriscan-flag-sd{background-position:-64px -132px}.sucuriscan-flag-se{background-position:-80px -132px}.sucuriscan-flag-sg{background-position:-96px -132px}.sucuriscan-flag-sh{background-position:-112px -132px}.sucuriscan-flag-si{background-position:-128px -132px}.sucuriscan-flag-sk{background-position:-144px -132px}.sucuriscan-flag-sl{background-position:-160px -132px}.sucuriscan-flag-sm{background-position:-176px -132px}.sucuriscan-flag-sn{background-position:-192px -132px}.sucuriscan-flag-so{background-position:-208px -132px}.sucuriscan-flag-somaliland{background-position:-224px -132px}.sucuriscan-flag-sr{background-position:-240px -132px}.sucuriscan-flag-ss{background-position:0 -143px}.sucuriscan-flag-st{background-position:-16px -143px}.sucuriscan-flag-sv{background-position:-32px -143px}.sucuriscan-flag-sx{background-position:-48px -143px}.sucuriscan-flag-sy{background-position:-64px -143px}.sucuriscan-flag-sz{background-position:-80px -143px}.sucuriscan-flag-tc{background-position:-96px -143px}.sucuriscan-flag-td{background-position:-112px -143px}.sucuriscan-flag-tf{background-position:-128px -143px}.sucuriscan-flag-tg{background-position:-144px -143px}.sucuriscan-flag-th{background-position:-160px -143px}.sucuriscan-flag-tj{background-position:-176px -143px}.sucuriscan-flag-tk{background-position:-192px -143px}.sucuriscan-flag-tl{background-position:-208px -143px}.sucuriscan-flag-tm{background-position:-224px -143px}.sucuriscan-flag-tn{background-position:-240px -143px}.sucuriscan-flag-to{background-position:0 -154px}.sucuriscan-flag-tr{background-position:-16px -154px}.sucuriscan-flag-tt{background-position:-32px -154px}.sucuriscan-flag-tv{background-position:-48px -154px}.sucuriscan-flag-tw{background-position:-64px -154px}.sucuriscan-flag-tz{background-position:-80px -154px}.sucuriscan-flag-ua{background-position:-96px -154px}.sucuriscan-flag-ug{background-position:-112px -154px}.sucuriscan-flag-um{background-position:-128px -154px}.sucuriscan-flag-us{background-position:-144px -154px}.sucuriscan-flag-uy{background-position:-160px -154px}.sucuriscan-flag-uz{background-position:-176px -154px}.sucuriscan-flag-va{background-position:-192px -154px}.sucuriscan-flag-vc{background-position:-208px -154px}.sucuriscan-flag-ve{background-position:-224px -154px}.sucuriscan-flag-vg{background-position:-240px -154px}.sucuriscan-flag-vi{background-position:0 -165px}.sucuriscan-flag-vn{background-position:-16px -165px}.sucuriscan-flag-vu{background-position:-32px -165px}.sucuriscan-flag-wales{background-position:-48px -165px}.sucuriscan-flag-wf{background-position:-64px -165px}.sucuriscan-flag-ws{background-position:-80px -165px}.sucuriscan-flag-ye{background-position:-96px -165px}.sucuriscan-flag-yt{background-position:-112px -165px}.sucuriscan-flag-za{background-position:-128px -165px}.sucuriscan-flag-zanzibar{background-position:-144px -165px}.sucuriscan-flag-zm{background-position:-160px -165px}.sucuriscan-flag-zw{background-position:-176px -165px}.c3 svg{font:10px sans-serif}.c3 line,.c3 path{fill:none;stroke:#000}.c3 text{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.c3-bars path,.c3-event-rect,.c3-legend-item-tile,.c3-xgrid-focus,.c3-ygrid{shape-rendering:crispEdges}.c3-chart-arc path{stroke:#fff}.c3-chart-arc text{fill:#fff;font-size:13px}.c3-grid line{stroke:#aaa}.c3-grid text{fill:#aaa}.c3-xgrid,.c3-ygrid{stroke-dasharray:3 3}.c3-text.c3-empty{fill:gray;font-size:2em}.c3-line{stroke-width:1px}.c3-circle._expanded_{stroke-width:1px;stroke:#fff}.c3-selected-circle{fill:#fff;stroke-width:2px}.c3-bar{stroke-width:0}.c3-bar._expanded_{fill-opacity:.75}.c3-chart-arcs-title{dominant-baseline:middle;font-size:1.3em}.c3-target.c3-focused{opacity:1}.c3-target.c3-focused path.c3-line,.c3-target.c3-focused path.c3-step{stroke-width:2px}.c3-target.c3-defocused{opacity:.3!important}.c3-region{fill:#4682b4;fill-opacity:.1}.c3-brush .extent{fill-opacity:.1}.c3-legend-item{font-size:12px}.c3-legend-item-hidden{opacity:.15}.c3-legend-background{opacity:.75;fill:#fff;stroke:#d3d3d3;stroke-width:1}.c3-tooltip-container{z-index:10}.c3-tooltip{border-collapse:collapse;border-spacing:0;background-color:#fff;empty-cells:show;-webkit-box-shadow:7px 7px 12px -9px #777;-moz-box-shadow:7px 7px 12px -9px #777;box-shadow:7px 7px 12px -9px #777}.c3-tooltip tr{border:1px solid #CCC}.c3-tooltip th{background-color:#aaa;font-size:14px;padding:2px 5px;text-align:left;color:#FFF}.c3-tooltip td{font-size:13px;padding:3px 6px;background-color:#fff;border-left:1px dotted #999}.c3-tooltip td>span{width:10px;height:10px;margin-right:6px}.c3-tooltip td.value{text-align:right}.c3-area{stroke-width:0;opacity:.2}.c3-chart-arcs .c3-chart-arcs-background{fill:#e0e0e0;stroke:none}.c3-chart-arcs .c3-chart-arcs-gauge-unit{fill:#000;font-size:16px}.c3-chart-arcs .c3-chart-arcs-gauge-max,.c3-chart-arcs .c3-chart-arcs-gauge-min{fill:#777}.c3-chart-arc .c3-gauge-value{fill:#000}@media (max-width:510px){.wp-core-ui .button.sucuriscan-review-hero,.wp-core-ui .sucuriscan-review-hero{display:none}}@media (max-width:620px){.sucuriscan-tabs>ul li,.sucuriscan-tabs>ul li>a{display:block}.sucuriscan-getapi-form button.button-primary{line-height:40px}}@media (max-width:768px){.sucuriscan-wrap .sucuriscan-footer .sucuriscan-help,.sucuriscan-wrap .sucuriscan-footer .sucuriscan-logo,.sucuriscan-wrap .sucuriscan-leftside,.sucuriscan-wrap .sucuriscan-sidebar{float:none}.sucuriscan-wrap .sucuriscan-leftside,.sucuriscan-wrap .sucuriscan-sidebar{width:100%}.sucuriscan-wrap .sucuriscan-sidebar{margin-top:20px}.sucuriscan-wrap .sucuriscan-footer .sucuriscan-logo{display:table;margin:0 auto}}@media (max-width:920px){.sucuriscan-wrap .sucuriscan-navbar{padding-left:0;padding-right:0}.sucuriscan-wrap .sucuriscan-navbar .nav-tab{display:block;line-height:20px;margin:0}.sucuriscan-wrap .sucuriscan-navbar .nav-tab:last-child{border-bottom:1px solid #ccc}}@media (max-width:1170px){.sucuriscan-modal{width:76%;left:10%}}@media (min-width:600px) and (max-width:1060px){.sucuriscan-wrap .sucuriscan-leftside,.sucuriscan-wrap .sucuriscan-sidebar{width:initial;float:none}.sucuriscan-wrap .sucuriscan-sidebar{margin-top:20px}.sucuriscan-wrap .sucuriscan-sidebar>div{width:49%;float:left;min-height:339px}.sucuriscan-wrap .sucuriscan-sidebar .sucuriscan-ad-antivirus{margin-left:2%}.sucuriscan-wrap .sucuriscan-scanner-video{height:450px}}.sucuriscan-maincontent #poststuff,.sucuriscan-panelstuff{min-width:initial;padding-top:0}.sucuriscan-maincontent .widefat tbody th.check-column{padding:6px 0 3px}.sucuriscan-maincontent .hardening-box .primary-secondary{margin:0 0 0 10px}.sucuriscan-maincontent hr{border:none;border-top:1px solid #999}.sucuriscan-maincontent table td>table{background:#fff}.sucuriscan-maincontent table td>table th{padding:4px 8px}
inc/js/sucuri-scanner.min.js CHANGED
@@ -1 +1 @@
1
- function sucuriscan_alert_close(b){var a=document.getElementById("sucuriscan-alert-"+b);a.parentNode.removeChild(a)}jQuery(document).ready(function(c){c(".sucuriscan-modal-btn").on("click",function(e){e.preventDefault();var f=c(this).data("modalid");c("div."+f).removeClass("sucuriscan-hidden")});c(".sucuriscan-overlay, .sucuriscan-modal-close").on("click",function(e){e.preventDefault();c(".sucuriscan-overlay").addClass("sucuriscan-hidden");c(".sucuriscan-modal").addClass("sucuriscan-hidden")});if(c(".sucuriscan-tabs").length){var d="sucuriscan-hidden";var b="sucuriscan-tab-active";var a=location.href.split("#")[1];c(".sucuriscan-tabs > ul a").on("click",function(k){k.preventDefault();var h=c(this);var j=h.data("tabname");var f=c(".sucuriscan-tab-containers > #sucuriscan-"+j);if(f.length){var g=location.href.replace(location.hash,"");var i=g+"#"+j;window.history.pushState({},document.title,i);c(".sucuriscan-tabs > ul a").removeClass(b);c(".sucuriscan-tab-containers > div").addClass(d);h.addClass(b);f.removeClass(d)}});c(".sucuriscan-tab-containers > div").addClass(d);if(a!==undefined){c(".sucuriscan-tabs > ul li a").each(function(e,f){if(c(f).data("tabname")===a){c(f).trigger("click")}})}else{c(".sucuriscan-tabs > ul li:first-child a").trigger("click")}}c("body").on("click",".sucuriscan-corefiles .manage-column :checkbox",function(e){c(".sucuriscan-corefiles tbody :checkbox").each(function(g,h){var f=c(h).is(":checked");c(h).attr("checked",!f)})})});
1
+ function sucuriscan_alert_close(c){var b=document.getElementById("sucuriscan-alert-"+c);b.parentNode.removeChild(b)}jQuery(document).ready(function(f){f(".sucuriscan-modal-btn").on("click",function(a){a.preventDefault();var b=f(this).data("modalid");f("div."+b).removeClass("sucuriscan-hidden")});f(".sucuriscan-overlay, .sucuriscan-modal-close").on("click",function(a){a.preventDefault();f(".sucuriscan-overlay").addClass("sucuriscan-hidden");f(".sucuriscan-modal").addClass("sucuriscan-hidden")});if(f(".sucuriscan-tabs").length){var g="sucuriscan-hidden";var c="sucuriscan-tab-active";var e=location.href.split("#")[1];f(".sucuriscan-tabs > ul a").on("click",function(h){h.preventDefault();var a=f(this);var k=a.data("tabname");var j=f(".sucuriscan-tab-containers > #sucuriscan-"+k);if(j.length){var d=location.href.replace(location.hash,"");var b=d+"#"+k;window.history.pushState({},document.title,b);f(".sucuriscan-tabs > ul a").removeClass(c);f(".sucuriscan-tab-containers > div").addClass(g);a.addClass(c);j.removeClass(g)}});f(".sucuriscan-tab-containers > div").addClass(g);if(e!==undefined){f(".sucuriscan-tabs > ul li a").each(function(b,a){if(f(a).data("tabname")===e){f(a).trigger("click")}})}else{f(".sucuriscan-tabs > ul li:first-child a").trigger("click")}}f("body").on("click",".sucuriscan-reveal",function(a){a.preventDefault();var b=f(this).attr("data-target");f(".sucuriscan-"+b).removeClass("sucuriscan-hidden")});f("body").on("click",".sucuriscan-corefiles .manage-column :checkbox",function(){f(".sucuriscan-corefiles tbody :checkbox").each(function(b,a){var d=f(a).is(":checked");f(a).attr("checked",!d)})})});
inc/tpl/bsidebar.html.tpl CHANGED
@@ -58,10 +58,13 @@
58
  <a href="https://wordpress.org/support/plugin/sucuri-scanner" target="_blank"
59
  class="button button-primary sucuriscan-supportbtn">Visit Support Forum</a>
60
 
61
- <form action="%%SUCURI.URL.Settings%%" method="post">
62
- <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
63
- <input type="hidden" name="sucuriscan_ads_visibility" value="disable" />
64
- <button type="submit" class="button-link sucuriscan-hide-ads">Hide this column</button>
65
- </form>
 
 
 
66
 
67
  </div>
58
  <a href="https://wordpress.org/support/plugin/sucuri-scanner" target="_blank"
59
  class="button button-primary sucuriscan-supportbtn">Visit Support Forum</a>
60
 
61
+ <div class="sucuriscan-hide-ads">
62
+ <button class="button-link sucuriscan-reveal"
63
+ data-target="hide-ads-instructions">Hide this column</button>
64
+ <div class="sucuriscan-hidden sucuriscan-hide-ads-instructions">
65
+ Add this to your wp-config.php file:<br>
66
+ <code>define('SUCURISCAN_HIDE_ADS', true);</code>
67
+ </div>
68
+ </div>
69
 
70
  </div>
inc/tpl/corefiles.html.tpl CHANGED
@@ -12,6 +12,12 @@
12
  </p>
13
  </div>
14
 
 
 
 
 
 
 
15
  <div class="sucuriscan-inline-alert-error sucuriscan-%%SUCURI.CoreFiles.FailureVisibility%%">
16
  <p>
17
  Error retrieving the <a href="%%SUCURI.CoreFiles.RemoteChecksumsURL%%" target="_blank">
12
  </p>
13
  </div>
14
 
15
+ <div class="sucuriscan-inline-alert-error sucuriscan-%%SUCURI.CoreFiles.DisabledVisibility%%">
16
+ <p>
17
+ The file scanner to check the integrity of the project is disabled.
18
+ </p>
19
+ </div>
20
+
21
  <div class="sucuriscan-inline-alert-error sucuriscan-%%SUCURI.CoreFiles.FailureVisibility%%">
22
  <p>
23
  Error retrieving the <a href="%%SUCURI.CoreFiles.RemoteChecksumsURL%%" target="_blank">
inc/tpl/firewall-auditlogs.html.tpl CHANGED
@@ -1,5 +1,5 @@
1
 
2
- <div id="poststuff">
3
  <div class="postbox">
4
  <h3>Firewall Audit Logs</h3>
5
 
1
 
2
+ <div class="sucuriscan-panelstuff">
3
  <div class="postbox">
4
  <h3>Firewall Audit Logs</h3>
5
 
inc/tpl/firewall-clearcache.html.tpl CHANGED
@@ -1,5 +1,5 @@
1
 
2
- <div id="poststuff">
3
  <div class="postbox">
4
  <h3>Clear Cache</h3>
5
 
1
 
2
+ <div class="sucuriscan-panelstuff">
3
  <div class="postbox">
4
  <h3>Clear Cache</h3>
5
 
inc/tpl/firewall-settings.html.tpl CHANGED
@@ -1,5 +1,5 @@
1
 
2
- <div id="poststuff">
3
  <div class="postbox">
4
  <h3>Firewall Settings</h3>
5
 
1
 
2
+ <div class="sucuriscan-panelstuff">
3
  <div class="postbox">
4
  <h3>Firewall Settings</h3>
5
 
inc/tpl/hardening-panel.html.tpl CHANGED
@@ -1,12 +1,14 @@
1
 
2
- <div id="poststuff">
3
  <form method="post">
4
  <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
5
  <input type="hidden" name="sucuriscan_run_hardening" value="1" />
6
 
 
 
7
  %%%SUCURI.Hardening.Version%%%
8
 
9
- %%%SUCURI.Hardening.CloudProxy%%%
10
 
11
  %%%SUCURI.Hardening.RemoveGenerator%%%
12
 
@@ -18,8 +20,6 @@
18
 
19
  %%%SUCURI.Hardening.WpIncludes%%%
20
 
21
- %%%SUCURI.Hardening.PhpVersion%%%
22
-
23
  %%%SUCURI.Hardening.SecretKeys%%%
24
 
25
  %%%SUCURI.Hardening.Readme%%%
1
 
2
+ <div class="sucuriscan-panelstuff sucuriscan-hardening-boxes">
3
  <form method="post">
4
  <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
5
  <input type="hidden" name="sucuriscan_run_hardening" value="1" />
6
 
7
+ %%%SUCURI.Hardening.CloudProxy%%%
8
+
9
  %%%SUCURI.Hardening.Version%%%
10
 
11
+ %%%SUCURI.Hardening.PhpVersion%%%
12
 
13
  %%%SUCURI.Hardening.RemoveGenerator%%%
14
 
20
 
21
  %%%SUCURI.Hardening.WpIncludes%%%
22
 
 
 
23
  %%%SUCURI.Hardening.SecretKeys%%%
24
 
25
  %%%SUCURI.Hardening.Readme%%%
inc/tpl/hardening-whitelist.html.tpl CHANGED
@@ -1,5 +1,5 @@
1
 
2
- <div id="poststuff" class="sucuriscan-hardening-whitelist">
3
  <div class="postbox sucuriscan-border sucuriscan-table-description">
4
  <h3>Whitelist Blocked PHP Files</h3>
5
 
1
 
2
+ <div class="sucuriscan-panelstuff sucuriscan-hardening-whitelist">
3
  <div class="postbox sucuriscan-border sucuriscan-table-description">
4
  <h3>Whitelist Blocked PHP Files</h3>
5
 
inc/tpl/hardening.html.tpl CHANGED
@@ -1,8 +1,24 @@
1
 
2
  <div class="sucuriscan-tabs">
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  <ul>
4
  <li>
5
- <a href="#hardening" data-tabname="hardening">Hardening Options</a>
 
 
 
6
  </li>
7
  <li>
8
  <a href="#whitelist" data-tabname="whitelist">Whitelist Blocked PHP Files</a>
1
 
2
  <div class="sucuriscan-tabs">
3
+ <script type="text/javascript">
4
+ jQuery(document).ready(function ($) {
5
+ var total = $('.sucuriscan-hardening-boxes .postbox').length;
6
+ var applied = $('.sucuriscan-hardening-boxes .postbox .sucuriscan-hstatus-1').length;
7
+
8
+ $('#sucuriscan-hardening-stats').html(
9
+ '({{APPLIED}}/{{TOTAL}})'
10
+ .replace('{{TOTAL}}', total)
11
+ .replace('{{APPLIED}}', applied)
12
+ );
13
+ });
14
+ </script>
15
+
16
  <ul>
17
  <li>
18
+ <a href="#hardening" data-tabname="hardening">
19
+ <span>Hardening Options</span>
20
+ <em id="sucuriscan-hardening-stats">(Loading...)</em>
21
+ </a>
22
  </li>
23
  <li>
24
  <a href="#whitelist" data-tabname="whitelist">Whitelist Blocked PHP Files</a>
inc/tpl/hardening.snippet.tpl CHANGED
@@ -5,7 +5,7 @@
5
  <div class="inside">
6
  %%%SUCURI.Hardening.Description%%%
7
 
8
- <div class="sucuriscan-hstatus sucuriscan-hstatus-%%SUCURI.Hardening.Status%%">
9
  <input type="submit" name="%%SUCURI.Hardening.FieldName%%"
10
  value="%%SUCURI.Hardening.FieldValue%%"
11
  %%SUCURI.Hardening.FieldAttributes%%
5
  <div class="inside">
6
  %%%SUCURI.Hardening.Description%%%
7
 
8
+ <div class="sucuriscan-hstatus sucuriscan-hstatus-%%SUCURI.Hardening.Status%% sucuriscan-%%SUCURI.Hardening.StatusVisibility%%">
9
  <input type="submit" name="%%SUCURI.Hardening.FieldName%%"
10
  value="%%SUCURI.Hardening.FieldValue%%"
11
  %%SUCURI.Hardening.FieldAttributes%%
inc/tpl/infosys-cronjobs.html.tpl CHANGED
@@ -1,6 +1,6 @@
1
 
2
- <div id="poststuff">
3
- <div class="postbox sucuriscan-border sucuriscan-table-description sucuriscan-%%SUCURI.IgnoreRules.TableVisibility%%">
4
  <h3>Scheduled Tasks (%%SUCURI.Cronjobs.Total%% tasks)</h3>
5
 
6
  <div class="inside">
@@ -20,34 +20,30 @@
20
  required by the site to work correctly.
21
  </p>
22
  </div>
23
- </div>
24
- </div>
25
- </div>
26
-
27
- <form action="%%SUCURI.URL.Infosys%%#wordpress-cronjobs" method="post">
28
- <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
29
-
30
- <table class="wp-list-table widefat sucuriscan-table sucuriscan-wpcron-list">
31
- <thead>
32
- <tr>
33
- <th class="manage-column column-cb check-column">
34
- <label class="screen-reader-text" for="cb-select-all-1">Select All</label>
35
- <input id="cb-select-all-1" type="checkbox">
36
- </th>
37
- <th>Task</th>
38
- <th>Schedule</th>
39
- <th>Next due</th>
40
- <th>Arguments</th>
41
- </tr>
42
- </thead>
43
 
44
- <tbody>
45
- %%%SUCURI.Cronjobs.List%%%
46
- </tbody>
47
-
48
- <tfoot>
49
- <tr>
50
- <td colspan="5">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  <label>
52
  <select name="sucuriscan_cronjob_action">
53
  <option value="">Choose action</option>
@@ -59,9 +55,8 @@
59
  </select>
60
  </label>
61
  <button type="submit" class="button button-primary">Send action</button>
62
- </td>
63
- </tr>
64
- </tfoot>
65
- </table>
66
-
67
- </form>
1
 
2
+ <div class="sucuriscan-panelstuff">
3
+ <div class="postbox sucuriscan-border sucuriscan-table-description">
4
  <h3>Scheduled Tasks (%%SUCURI.Cronjobs.Total%% tasks)</h3>
5
 
6
  <div class="inside">
20
  required by the site to work correctly.
21
  </p>
22
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
+ <form action="%%SUCURI.URL.Infosys%%#wordpress-cronjobs" method="post">
25
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
26
+
27
+ <table class="wp-list-table widefat sucuriscan-table sucuriscan-wpcron-list">
28
+ <thead>
29
+ <tr>
30
+ <th class="manage-column column-cb check-column">
31
+ <label class="screen-reader-text" for="cb-select-all-1">Select All</label>
32
+ <input id="cb-select-all-1" type="checkbox">
33
+ </th>
34
+ <th>Task</th>
35
+ <th>Schedule</th>
36
+ <th>Next due</th>
37
+ <th>Arguments</th>
38
+ </tr>
39
+ </thead>
40
+
41
+ <tbody>
42
+ %%%SUCURI.Cronjobs.List%%%
43
+ </tbody>
44
+ </table>
45
+
46
+ <div class="sucuriscan-recipient-form">
47
  <label>
48
  <select name="sucuriscan_cronjob_action">
49
  <option value="">Choose action</option>
55
  </select>
56
  </label>
57
  <button type="submit" class="button button-primary">Send action</button>
58
+ </div>
59
+ </form>
60
+ </div>
61
+ </div>
62
+ </div>
 
inc/tpl/infosys-errorlogs-flimit.html.tpl ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <div class="postbox">
3
+ <h3>Error Logs - File Limit</h3>
4
+
5
+ <div class="inside">
6
+ <p>
7
+ If you are a developer, you may want to check the latest errors encountered by
8
+ the server before delete the log file, that way you can see where the application
9
+ is failing and fix the errors. Note that a log file may have thousand of lines,
10
+ so to prevent an overflow in the memory of the PHP interpreter the plugin limits
11
+ the process to the <strong>latest %%SUCURI.ErrorLogs.LogsLimit%% lines</strong>
12
+ inserted in the log file.
13
+ </p>
14
+
15
+ <form action="%%SUCURI.URL.Infosys%%#error-logs" method="post">
16
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
17
+ <span class="sucuriscan-input-group">
18
+ <label>Error Logs - File Limit:</label>
19
+ <input type="text" name="sucuriscan_errorlogs_limit" class="input-text" placeholder="e.g. 30" />
20
+ </span>
21
+ <button type="submit" class="button-primary">Save</button>
22
+ </form>
23
+ </div>
24
+ </div>
inc/tpl/infosys-errorlogs-freader.html.tpl ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <div class="postbox">
3
+ <h3>Error Logs - File Reader</h3>
4
+
5
+ <div class="inside">
6
+ <p>
7
+ Note that if the log file is not empty but the table is, it means that the
8
+ format of the logs used by the web server is not supported by the scanner,
9
+ you can try to increase the number of lines processed or ask your hosting
10
+ provider to change the format of the PHP error log generator.
11
+ </p>
12
+
13
+ <div class="sucuriscan-inline-alert-warning">
14
+ <p>
15
+ Note that only the main error log file <em>(usually located in the document
16
+ root)</em> will be read, parsed, and listed below, if there are more log files
17
+ in sub-directories they will be ignored.
18
+ </p>
19
+ </div>
20
+
21
+ <script type="text/javascript">
22
+ jQuery(function($){
23
+ $('.sucuriscan-errorlogs-list tbody').html(
24
+ '<tr><td colspan="5"><span>Loading <em>(may take '
25
+ + 'several seconds)</em>...</span></td></tr>'
26
+ );
27
+ $.post('%%SUCURI.AjaxURL.Settings%%', {
28
+ action: 'sucuriscan_infosys_ajax',
29
+ sucuriscan_page_nonce: '%%SUCURI.PageNonce%%',
30
+ form_action: 'get_error_logs',
31
+ }, function(data){
32
+ $('.sucuriscan-errorlogs-list tbody').html(data);
33
+ });
34
+ });
35
+ </script>
36
+
37
+ <table class="wp-list-table widefat sucuriscan-table sucuriscan-errorlogs-list">
38
+ <thead>
39
+ <tr>
40
+ <th width="100">Date Time</th>
41
+ <th width="50">Type</th>
42
+ <th>Error Message</th>
43
+ <th width="300">File</th>
44
+ <th width="50">Line</th>
45
+ </tr>
46
+ </thead>
47
+
48
+ <tbody>
49
+ </tbody>
50
+ </table>
51
+
52
+ <div class="sucuriscan-recipient-form">
53
+ <form action="%%SUCURI.URL.Hardening%%" method="post">
54
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
55
+ <input type="hidden" name="sucuriscan_run_hardening" value="1" />
56
+ <input type="hidden" name="sucuriscan_harden_errorlog" value="Harden" />
57
+ <button type="submit" class="button-primary">Delete Logs</button>
58
+ </form>
59
+ </div>
60
+ </div>
61
+ </div>
inc/tpl/infosys-errorlogs-status.html.tpl ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <div class="postbox">
3
+ <h3>Error Logs</h3>
4
+
5
+ <div class="inside">
6
+ <p>
7
+ Web servers like Apache, Nginx and others use files to record errors encountered
8
+ during the execution of a dynamic language or the server processes. Depending on
9
+ the configuration of the server, these files may be accessible from the web
10
+ opening a hole in your site to allow an attacker to gather sensitive information
11
+ of your project, so it is highly recommended to delete them.
12
+ </p>
13
+
14
+ <div class="sucuriscan-hstatus sucuriscan-hstatus-2">
15
+ <span>Ignore Scanning is %%SUCURI.ErrorLogs.Status%%</span>
16
+ <form action="%%SUCURI.URL.Infosys%%#error-logs" method="post">
17
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
18
+ <input type="hidden" name="sucuriscan_parse_errorlogs" value="%%SUCURI.ErrorLogs.SwitchValue%%" />
19
+ <button type="submit" class="button-primary %%SUCURI.ErrorLogs.SwitchCssClass%%">%%SUCURI.ErrorLogs.SwitchText%%</button>
20
+ </form>
21
+ </div>
22
+ </div>
23
+ </div>
inc/tpl/infosys-errorlogs.html.tpl CHANGED
@@ -1,88 +1,8 @@
1
 
2
- <div id="poststuff">
3
- <div class="postbox sucuriscan-border sucuriscan-table-description sucuriscan-errorlogs">
4
- <h3>Error Logs</h3>
5
 
6
- <div class="inside">
7
 
8
- <p>
9
- Web servers like Apache, Nginx and others use files to record errors encountered
10
- during the execution of a dynamic language or the server processes. Depending on
11
- the configuration of the server, these files may be accessible from the web
12
- opening a hole in your site to allow an attacker to gather sensitive information
13
- of your project, so it is highly recommended to delete them.
14
- </p>
15
-
16
- <div class="sucuriscan-inline-alert-info">
17
- <p>
18
- If you are a developer, you may want to check the latest errors encountered by
19
- the server before delete the log file, that way you can see where the
20
- application is failing and fix the errors. Note that a log file may have
21
- thousand of lines, so to prevent an overflow in the memory of the PHP
22
- interpreter the plugin limits the process to the <strong>latest
23
- %%SUCURI.ErrorLog.LogsLimit%% lines</strong> inserted in the log file.
24
- </p>
25
- </div>
26
-
27
- <div class="sucuriscan-inline-alert-error sucuriscan-%%SUCURI.ErrorLog.DisabledVisibility%%">
28
- <p>
29
- The analysis of error logs is disabled, go to the <em>Scanner Settings</em>
30
- panel in the <em>Settings</em> page to enable it.
31
- </p>
32
- </div>
33
-
34
- <div class="sucuriscan-inline-alert-warning sucuriscan-%%SUCURI.ErrorLog.InvalidFormatVisibility%%">
35
- <p>
36
- Note that if the log file is not empty but the table is, it means that the
37
- format of the logs used by the web server is not supported by the scanner,
38
- you can try to increase the number of lines processed though from
39
- <a href="%%SUCURI.URL.Settings%%#scanner">here</a> in case that
40
- other lines have a different format which is very common on servers with
41
- mixed configurations.
42
- </p>
43
- </div>
44
-
45
- </div>
46
- </div>
47
  </div>
48
-
49
- <table class="wp-list-table widefat sucuriscan-table sucuriscan-table-double-title sucuriscan-errorlogs-list">
50
- <thead>
51
- <tr>
52
- <th colspan="5" class="thead-with-button">
53
- <span>Error Logs (%%SUCURI.ErrorLog.FileSize%%)</span>
54
-
55
- <form action="%%SUCURI.URL.Hardening%%#error-logs" method="post" class="thead-topright-action">
56
- <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
57
- <input type="hidden" name="sucuriscan_run_hardening" value="1" />
58
- <input type="hidden" name="sucuriscan_harden_errorlog" value="Harden" />
59
- <button type="submit" class="button-primary">Delete logs</button>
60
- </form>
61
- </th>
62
- </tr>
63
-
64
- <tr>
65
- <th width="100">Date Time</th>
66
- <th width="50">Type</th>
67
- <th>Error Message</th>
68
- <th width="300">File</th>
69
- <th width="50">Line</th>
70
- </tr>
71
- </thead>
72
-
73
- <tbody>
74
- %%%SUCURI.ErrorLog.List%%%
75
-
76
- <tr class="sucuriscan-%%SUCURI.ErrorLog.InvalidFormatVisibility%%">
77
- <td colspan="5">
78
- <em>No valid logs in the last %%SUCURI.ErrorLog.LogsLimit%% lines of the error log file.</em>
79
- </td>
80
- </tr>
81
-
82
- <tr class="sucuriscan-%%SUCURI.ErrorLog.NoItemsVisibility%%">
83
- <td colspan="5">
84
- <em>No logs so far.</em>
85
- </td>
86
- </tr>
87
- </tbody>
88
- </table>
1
 
2
+ <div class="sucuriscan-panelstuff sucuriscan-general-errorlogs">
3
+ %%%SUCURI.ErrorLogs.Status%%%
 
4
 
5
+ %%%SUCURI.ErrorLogs.FileLimit%%%
6
 
7
+ %%%SUCURI.ErrorLogs.FileReader%%%
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
inc/tpl/infosys-htaccess.html.tpl CHANGED
@@ -1,5 +1,5 @@
1
 
2
- <div id="poststuff" class="sucuriscan-infosys-htaccess">
3
  <div class="postbox sucuriscan-border sucuriscan-table-description">
4
  <h3>Access File Integrity</h3>
5
 
1
 
2
+ <div class="sucuriscan-panelstuff sucuriscan-infosys-htaccess">
3
  <div class="postbox sucuriscan-border sucuriscan-table-description">
4
  <h3>Access File Integrity</h3>
5
 
inc/tpl/integrity-auditlogs.html.tpl CHANGED
@@ -1,11 +1,67 @@
1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  <table class="wp-list-table widefat sucuriscan-table sucuriscan-table-double-title sucuriscan-auditlogs">
3
  <thead>
4
  <tr>
5
  <th colspan="5" class="thead-with-button">
6
- <span>Audit Logs (%%SUCURI.AuditLogs.Count%% latest logs)</span>
 
 
7
  <form action="%%SUCURI.URL.Settings%%" method="post"
8
- class="thead-topright-action sucuriscan-%%SUCURI.AuditLogs.EnableAuditReportVisibility%%">
9
  <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
10
  <input type="hidden" name="sucuriscan_audit_report" value="enable" />
11
  <button type="submit" class="button-primary">Enable Audit Report</button>
@@ -23,20 +79,24 @@
23
  </thead>
24
 
25
  <tbody>
26
- %%%SUCURI.AuditLogs.List%%%
27
-
28
- <tr class="sucuriscan-%%SUCURI.AuditLogs.NoItemsVisibility%%">
29
  <td colspan="5">
30
- <em>No logs so far.</em>
31
  </td>
32
  </tr>
 
33
 
34
- <tr class="sucuriscan-%%SUCURI.AuditLogs.PaginationVisibility%%">
35
- <td colspan="5">
36
- <ul class="sucuriscan-pagination">
37
- %%%SUCURI.AuditLogs.PaginationLinks%%%
 
38
  </ul>
39
- </td>
40
- </tr>
41
- </tbody>
 
 
 
 
42
  </table>
1
 
2
+ <script type="text/javascript">
3
+ jQuery(function ($) {
4
+ var sucuriscanLoadAuditLogs = function (page, reset) {
5
+ var url = '%%SUCURI.AjaxURL.Home%%';
6
+
7
+ if (page !== undefined && page > 0) {
8
+ url += '&paged=' + page;
9
+ }
10
+
11
+ if (reset === true) {
12
+ var loading = '<tr><td colspan="5"><em>Loading...</em></td></tr>';
13
+ $('.sucuriscan-auditlogs tbody').html(loading);
14
+ }
15
+
16
+ $('.sucuriscan-pagination-loading').html('Loading...');
17
+
18
+ $.post(url, {
19
+ action: 'sucuriscan_ajax',
20
+ sucuriscan_page_nonce: '%%SUCURI.PageNonce%%',
21
+ form_action: 'get_audit_logs',
22
+ }, function (data) {
23
+ if (data.content) {
24
+ $('.sucuriscan-auditlogs tbody').html(data.content);
25
+ $('.sucuriscan-pagination-loading').html('');
26
+ $('.sucuriscan-auditlogs-count').html('(' + data.count + ' latest logs)');
27
+
28
+ if (data.pagination !== '') {
29
+ $('.sucuriscan-auditlogs .sucuriscan-pagination').html(data.pagination);
30
+ }
31
+
32
+ if (data.enable_report) {
33
+ $('.sucuriscan-audit-report').removeClass('sucuriscan-hidden');
34
+ }
35
+ } else if (typeof data === 'object') {
36
+ $('.sucuriscan-auditlogs tbody').html(
37
+ '<tr><td colspan="5">Unrecoverable error</td></tr>');
38
+ } else {
39
+ $('.sucuriscan-auditlogs tbody').html(
40
+ '<tr><td colspan="5">' + data + '</td></tr>');
41
+ }
42
+ });
43
+ }
44
+
45
+ setTimeout(function () {
46
+ sucuriscanLoadAuditLogs(0, true);
47
+ }, 100);
48
+
49
+ $('.sucuriscan-auditlogs').on('click', '.sucuriscan-pagination-link', function (event) {
50
+ event.preventDefault();
51
+ sucuriscanLoadAuditLogs($(this).attr('data-page'));
52
+ });
53
+ });
54
+ </script>
55
+
56
  <table class="wp-list-table widefat sucuriscan-table sucuriscan-table-double-title sucuriscan-auditlogs">
57
  <thead>
58
  <tr>
59
  <th colspan="5" class="thead-with-button">
60
+ <span>Audit Logs</span>
61
+ <span class="sucuriscan-auditlogs-count">(Loading...)</span>
62
+
63
  <form action="%%SUCURI.URL.Settings%%" method="post"
64
+ class="thead-topright-action sucuriscan-hidden sucuriscan-audit-report">
65
  <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
66
  <input type="hidden" name="sucuriscan_audit_report" value="enable" />
67
  <button type="submit" class="button-primary">Enable Audit Report</button>
79
  </thead>
80
 
81
  <tbody>
82
+ <tr>
 
 
83
  <td colspan="5">
84
+ <em>Loading...</em>
85
  </td>
86
  </tr>
87
+ </tbody>
88
 
89
+ <tfoot>
90
+ <td colspan="5">
91
+ <div class="sucuriscan-clearfix">
92
+ <ul class="sucuriscan-pull-left sucuriscan-pagination">
93
+ <!-- Populated via JavaScript -->
94
  </ul>
95
+
96
+ <div class="sucuriscan-pull-right sucuriscan-pagination-loading">
97
+ <!-- Populated via JavaScript -->
98
+ </div>
99
+ </div>
100
+ </td>
101
+ </tfoot>
102
  </table>
inc/tpl/integrity-modifiedfiles.html.tpl CHANGED
@@ -1,5 +1,5 @@
1
 
2
- <div id="poststuff">
3
  <div class="postbox sucuriscan-border sucuriscan-table-description">
4
  <h3>Modified Files</h3>
5
 
1
 
2
+ <div class="sucuriscan-panelstuff">
3
  <div class="postbox sucuriscan-border sucuriscan-table-description">
4
  <h3>Modified Files</h3>
5
 
inc/tpl/integrity.html.tpl CHANGED
@@ -1,5 +1,5 @@
1
 
2
- <div id="poststuff">
3
  %%%SUCURI.WordpressVersion%%%
4
 
5
  %%%SUCURI.CoreFiles%%%
1
 
2
+ <div class="sucuriscan-panelstuff">
3
  %%%SUCURI.WordpressVersion%%%
4
 
5
  %%%SUCURI.CoreFiles%%%
inc/tpl/lastlogins-all.html.tpl CHANGED
@@ -34,7 +34,7 @@
34
  <tr class="sucuriscan-%%SUCURI.UserList.PaginationVisibility%%">
35
  <td colspan="6">
36
  <ul class="sucuriscan-pagination">
37
- %%SUCURI.UserList.Pagination%%
38
  </ul>
39
  </td>
40
  </tr>
34
  <tr class="sucuriscan-%%SUCURI.UserList.PaginationVisibility%%">
35
  <td colspan="6">
36
  <ul class="sucuriscan-pagination">
37
+ %%%SUCURI.UserList.Pagination%%%
38
  </ul>
39
  </td>
40
  </tr>
inc/tpl/lastlogins-blockedusers.html.tpl ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <div class="sucuriscan-panelstuff">
3
+ <div class="postbox sucuriscan-border sucuriscan-table-description">
4
+ <h3>Blocked Users</h3>
5
+
6
+ <div class="inside">
7
+ <p>
8
+ Any user login passing accross the built-in mechanism that WordPress provides to
9
+ authentication the session will be intercepted by the plugin and analyzed to see
10
+ if the username is in the list of blocked accounts, if yes then the request will
11
+ be stopped. No logs will be registered and no alerts will be sent to your email.
12
+ </p>
13
+
14
+ <div class="sucuriscan-inline-alert-info">
15
+ <p>
16
+ Take in consideration that this is not a 100% bulletproof mechanism
17
+ to block unwanted user authentications from malicious users. Depending
18
+ on the configuration of your website, installed plugins, installed
19
+ themes, and even the version of WordPress there might still be weak
20
+ points that automated tools can take advantage of to brute force the
21
+ user accounts registered in your website. <a target="_blank"
22
+ href="https://sucuri.net/website-firewall/?wp=bu">Install a firewall</a>
23
+ to have full protection and mitigate this and a myriad of other attacks.
24
+ </p>
25
+ </div>
26
+
27
+ <div class="sucuriscan-inline-alert-warning">
28
+ <p>Do not block existent accounts, they will lose access forever.</p>
29
+ </div>
30
+
31
+ <form method="post">
32
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
33
+
34
+ <table class="wp-list-table widefat sucuriscan-table">
35
+ <thead>
36
+ <tr>
37
+ <th class="manage-column column-cb check-column">
38
+ <label class="screen-reader-text" for="cb-select-all-1">Select All</label>
39
+ <input id="cb-select-all-1" type="checkbox">
40
+ </th>
41
+ <th class="manage-column">Username</th>
42
+ <th class="manage-column">Blocked At</th>
43
+ <th class="manage-column">First Attempt</th>
44
+ <th class="manage-column">Last Attempt</th>
45
+ </tr>
46
+ </thead>
47
+
48
+ <tbody>
49
+ %%%SUCURI.BlockedUsers.List%%%
50
+
51
+ <tr class="sucuriscan-%%SUCURI.BlockedUsers.NoItemsVisibility%%">
52
+ <td colspan="5">
53
+ <em>The table is empty.</em>
54
+ </td>
55
+ </tr>
56
+ </tbody>
57
+ </table>
58
+
59
+ <div class="sucuriscan-recipient-form">
60
+ <button type="submit" class="button button-primary">Unblock User</button>
61
+ </div>
62
+ </form>
63
+ </div>
64
+ </div>
65
+ </div>
inc/tpl/lastlogins-blockedusers.snippet.tpl ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <tr class="%%SUCURI.BlockedUsers.CssClass%%">
3
+ <td class="check-column">
4
+ <input type="checkbox" name="sucuriscan_unblock_user[]" value="%%SUCURI.BlockedUsers.Username%%">
5
+ </td>
6
+ <td><span class="sucuriscan-monospace">%%SUCURI.BlockedUsers.Username%%</span></td>
7
+ <td><em>%%SUCURI.BlockedUsers.BlockedAt%%</em></td>
8
+ <td><em>%%SUCURI.BlockedUsers.FirstAttempt%%</em></td>
9
+ <td><em>%%SUCURI.BlockedUsers.LastAttempt%%</em></td>
10
+ </tr>
inc/tpl/lastlogins-failedlogins.html.tpl CHANGED
@@ -1,7 +1,16 @@
1
 
2
- <div id="poststuff">
3
  <div class="postbox sucuriscan-border sucuriscan-table-description">
4
- <h3>Failed logins</h3>
 
 
 
 
 
 
 
 
 
5
 
6
  <div class="inside">
7
  <p>
@@ -37,37 +46,48 @@
37
  href="%%SUCURI.URL.Settings%%#general">general settings</a>
38
  </p>
39
  </div>
40
- </div>
41
- </div>
42
- </div>
43
 
44
- <table class="wp-list-table widefat sucuriscan-table sucuriscan-lastlogins-failed sucuriscan-%%SUCURI.IgnoreRules.TableVisibility%%">
45
- <thead>
46
- <tr>
47
- <th class="manage-column">&nbsp;</th>
48
- <th class="manage-column">User</th>
49
- <th class="manage-column">Password</th>
50
- <th class="manage-column">IP Address</th>
51
- <th class="manage-column">Date/Time</th>
52
- <th class="manage-column" width="300">User-Agent</th>
53
- </tr>
54
- </thead>
 
 
 
 
 
 
55
 
56
- <tbody>
57
- %%%SUCURI.FailedLogins.List%%%
58
 
59
- <tr class="sucuriscan-%%SUCURI.FailedLogins.NoItemsVisibility%%">
60
- <td colspan="6">
61
- <em>No logs so far.</em>
62
- </td>
63
- </tr>
64
 
65
- <tr class="sucuriscan-%%SUCURI.FailedLogins.PaginationVisibility%%">
66
- <td colspan="6">
67
- <ul class="sucuriscan-pagination">
68
- %%SUCURI.FailedLogins.PaginationLinks%%
69
- </ul>
70
- </td>
71
- </tr>
72
- </tbody>
73
- </table>
 
 
 
 
 
 
 
 
1
 
2
+ <div class="sucuriscan-panelstuff">
3
  <div class="postbox sucuriscan-border sucuriscan-table-description">
4
+ <h3 class="thead-with-button">
5
+ <span>Failed logins</span>
6
+ <span class="thead-topright-action">
7
+ <form action="%%SUCURI.URL.Settings%%#scanner" method="post">
8
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
9
+ <input type="hidden" name="sucuriscan_reset_logfile" value="failedlogins" />
10
+ <button type="submit" class="button button-primary">Reset logs</button>
11
+ </form>
12
+ </span>
13
+ </h3>
14
 
15
  <div class="inside">
16
  <p>
46
  href="%%SUCURI.URL.Settings%%#general">general settings</a>
47
  </p>
48
  </div>
 
 
 
49
 
50
+ <form method="post">
51
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
52
+
53
+ <table class="wp-list-table widefat sucuriscan-table sucuriscan-lastlogins-failed">
54
+ <thead>
55
+ <tr>
56
+ <th class="manage-column column-cb check-column">
57
+ <label class="screen-reader-text" for="cb-select-all-1">Select All</label>
58
+ <input id="cb-select-all-1" type="checkbox">
59
+ </th>
60
+ <th class="manage-column">User</th>
61
+ <th class="manage-column">Password</th>
62
+ <th class="manage-column">IP Address</th>
63
+ <th class="manage-column">Date/Time</th>
64
+ <th class="manage-column" width="300">User-Agent</th>
65
+ </tr>
66
+ </thead>
67
 
68
+ <tbody>
69
+ %%%SUCURI.FailedLogins.List%%%
70
 
71
+ <tr class="sucuriscan-%%SUCURI.FailedLogins.NoItemsVisibility%%">
72
+ <td colspan="6">
73
+ <em>No logs so far.</em>
74
+ </td>
75
+ </tr>
76
 
77
+ <tr class="sucuriscan-%%SUCURI.FailedLogins.PaginationVisibility%%">
78
+ <td colspan="6">
79
+ <ul class="sucuriscan-pagination">
80
+ %%%SUCURI.FailedLogins.PaginationLinks%%%
81
+ </ul>
82
+ </td>
83
+ </tr>
84
+ </tbody>
85
+ </table>
86
+
87
+ <div class="sucuriscan-recipient-form">
88
+ <button type="submit" class="button button-primary">Block Selected Users</button>
89
+ </div>
90
+ </form>
91
+ </div>
92
+ </div>
93
+ </div>
inc/tpl/lastlogins-failedlogins.snippet.tpl CHANGED
@@ -1,6 +1,8 @@
1
 
2
  <tr class="%%SUCURI.FailedLogins.CssClass%%">
3
- <td>%%SUCURI.FailedLogins.Num%%</td>
 
 
4
  <td><span class="sucuriscan-monospace">%%SUCURI.FailedLogins.Username%%</span></td>
5
  <td><span class="sucuriscan-label-%%SUCURI.FailedLogins.PasswordColor%%">%%SUCURI.FailedLogins.Password%%</span></td>
6
  <td><span class="sucuriscan-monospace">%%SUCURI.FailedLogins.RemoteAddr%%</span></td>
1
 
2
  <tr class="%%SUCURI.FailedLogins.CssClass%%">
3
+ <td class="check-column">
4
+ <input type="checkbox" name="sucuriscan_block_user[]" value="%%SUCURI.FailedLogins.Username%%">
5
+ </td>
6
  <td><span class="sucuriscan-monospace">%%SUCURI.FailedLogins.Username%%</span></td>
7
  <td><span class="sucuriscan-label-%%SUCURI.FailedLogins.PasswordColor%%">%%SUCURI.FailedLogins.Password%%</span></td>
8
  <td><span class="sucuriscan-monospace">%%SUCURI.FailedLogins.RemoteAddr%%</span></td>
inc/tpl/lastlogins.html.tpl CHANGED
@@ -13,6 +13,9 @@
13
  <li>
14
  <a href="#failed-logins" data-tabname="failed-logins">Failed Logins</a>
15
  </li>
 
 
 
16
  </ul>
17
 
18
  <div class="sucuriscan-tab-containers">
@@ -31,5 +34,9 @@
31
  <div id="sucuriscan-failed-logins">
32
  %%%SUCURI.FailedLogins%%%
33
  </div>
 
 
 
 
34
  </div>
35
  </div>
13
  <li>
14
  <a href="#failed-logins" data-tabname="failed-logins">Failed Logins</a>
15
  </li>
16
+ <li>
17
+ <a href="#blocked-users" data-tabname="blocked-users">Blocked Users</a>
18
+ </li>
19
  </ul>
20
 
21
  <div class="sucuriscan-tab-containers">
34
  <div id="sucuriscan-failed-logins">
35
  %%%SUCURI.FailedLogins%%%
36
  </div>
37
+
38
+ <div id="sucuriscan-blocked-users">
39
+ %%%SUCURI.BlockedUsers%%%
40
+ </div>
41
  </div>
42
  </div>
inc/tpl/notification-resetpwd.html.tpl CHANGED
@@ -7,5 +7,5 @@ has been reset for security reasons.<br>
7
  You can use this temporary password to log in:
8
  <span style="display:inline-block;background:#f5f5f5;padding:2px 6px;
9
  font-family:Menlo, Monaco, monospace, serif;border:1px solid #ddd">
10
- %%SUCURI.ResetPassword.Password%%</span><br>
11
  Please change your password after you log in.
7
  You can use this temporary password to log in:
8
  <span style="display:inline-block;background:#f5f5f5;padding:2px 6px;
9
  font-family:Menlo, Monaco, monospace, serif;border:1px solid #ddd">
10
+ %%%SUCURI.ResetPassword.Password%%%</span><br>
11
  Please change your password after you log in.
inc/tpl/posthack-resetpassword.html.tpl CHANGED
@@ -1,5 +1,5 @@
1
 
2
- <div id="poststuff" class="sucuriscan-reset-users-password">
3
  <div class="postbox">
4
  <div class="inside">
5
  <form method="post">
1
 
2
+ <div class="sucuriscan-panelstuff sucuriscan-reset-users-password">
3
  <div class="postbox">
4
  <div class="inside">
5
  <form method="post">
inc/tpl/posthack-resetplugins.html.tpl CHANGED
@@ -1,5 +1,5 @@
1
 
2
- <div id="poststuff" class="sucuriscan-reset-plugins">
3
  <div class="postbox">
4
  <div class="inside">
5
  <form action="%%SUCURI.URL.Posthack%%#reset-plugins" method="post">
1
 
2
+ <div class="sucuriscan-panelstuff sucuriscan-reset-plugins">
3
  <div class="postbox">
4
  <div class="inside">
5
  <form action="%%SUCURI.URL.Posthack%%#reset-plugins" method="post">
inc/tpl/posthack-resetplugins.snippet.tpl CHANGED
@@ -3,7 +3,9 @@
3
  <td class="check-column">
4
  <input type="checkbox" name="plugin_path[]" value="%%SUCURI.ResetPlugin.PluginPath%%" %%SUCURI.ResetPlugin.Disabled%% />
5
  </td>
6
- <td>%%SUCURI.ResetPlugin.Plugin%%</td>
 
 
7
  <td><span class="sucuriscan-monospace">%%SUCURI.ResetPlugin.Version%%</span></td>
8
  <td><span class="sucuriscan-label-%%SUCURI.ResetPlugin.TypeClass%%">%%SUCURI.ResetPlugin.Type%%</span></td>
9
  <td><span class="sucuriscan-label-%%SUCURI.ResetPlugin.StatusClass%%">%%SUCURI.ResetPlugin.Status%%</span></td>
3
  <td class="check-column">
4
  <input type="checkbox" name="plugin_path[]" value="%%SUCURI.ResetPlugin.PluginPath%%" %%SUCURI.ResetPlugin.Disabled%% />
5
  </td>
6
+ <td>
7
+ <a href="%%SUCURI.ResetPlugin.Repository%%" target="_blank">%%SUCURI.ResetPlugin.Plugin%%</a>
8
+ </td>
9
  <td><span class="sucuriscan-monospace">%%SUCURI.ResetPlugin.Version%%</span></td>
10
  <td><span class="sucuriscan-label-%%SUCURI.ResetPlugin.TypeClass%%">%%SUCURI.ResetPlugin.Type%%</span></td>
11
  <td><span class="sucuriscan-label-%%SUCURI.ResetPlugin.StatusClass%%">%%SUCURI.ResetPlugin.Status%%</span></td>
inc/tpl/posthack-updates-notification.html.tpl ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <p>
3
+ WordPress has a big user base in the public Internet, this brings interest to
4
+ malicious people to find vulnerabilities in the code code, 3rd-party extensions,
5
+ and themes that other companies develop. You should keep every piece of code
6
+ installed in your website update to prevent attacks as soon as disclosed
7
+ vulnerabilities are patched.
8
+ </p>
9
+
10
+ <table border="1" cellspacing="1" cellpadding="5">
11
+ <thead>
12
+ <tr>
13
+ <th>Extension</th>
14
+ <th>Installed</th>
15
+ <th>Available</th>
16
+ <th>Tested With</th>
17
+ <th>&nbsp;</th>
18
+ </tr>
19
+ </thead>
20
+
21
+ <tbody>
22
+ %%%SUCURI.AvailableUpdates.Content%%%
23
+ </tbody>
24
+
25
+ <tfoot>
26
+ <tr>
27
+ <td colspan="5">
28
+ <p>
29
+ Update all extensions from your website's <a href="%%SUCURI.URL.Home%%">
30
+ admin panel</a>, and/or disable the email notifications for available
31
+ updates from the <a href="%%SUCURI.URL.Settings%%">settings</a> page.
32
+ </p>
33
+ </td>
34
+ </tr>
35
+ </tfoot>
36
+ </table>
inc/tpl/posthack-updates.html.tpl ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <div class="sucuriscan-panelstuff sucuriscan-updates">
3
+ <div class="postbox">
4
+ <div class="inside">
5
+ <p>
6
+ WordPress has a big user base in the public Internet, this brings interest to
7
+ malicious people to find vulnerabilities in the code code, 3rd-party extensions,
8
+ and themes that other companies develop. You should keep every piece of code
9
+ installed in your website update to prevent attacks as soon as disclosed
10
+ vulnerabilities are patched.
11
+ </p>
12
+
13
+ <table class="wp-list-table widefat sucuriscan-table sucuriscan-updates-table">
14
+ <thead>
15
+ <tr>
16
+ <th class="manage-column">Extension</th>
17
+ <th class="manage-column">Installed</th>
18
+ <th class="manage-column">Available</th>
19
+ <th class="manage-column">Tested With</th>
20
+ <th class="manage-column">&nbsp;</th>
21
+ </tr>
22
+ </thead>
23
+
24
+ <tbody>
25
+ <tr>
26
+ <td colspan="5">
27
+ <span>Loading <em>(may take several seconds)</em>...</span>
28
+ </td>
29
+ </tr>
30
+ </tbody>
31
+ </table>
32
+
33
+ <script type="text/javascript">
34
+ jQuery(function($){
35
+ $.post('%%SUCURI.AjaxURL.Posthack%%', {
36
+ action: 'sucuriscan_posthack_ajax',
37
+ sucuriscan_page_nonce: '%%SUCURI.PageNonce%%',
38
+ form_action: 'get_available_updates',
39
+ }, function(data){
40
+ $('.sucuriscan-updates-table tbody').html(data);
41
+ });
42
+ });
43
+ </script>
44
+ </div>
45
+ </div>
46
+ </div>
inc/tpl/posthack-updates.snippet.tpl ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <tr class="%%SUCURI.Update.CssClass%%">
3
+ <td>
4
+ <span class="dashicons-before dashicons-admin-%%SUCURI.Update.IconType%%">
5
+ <a href="%%SUCURI.Update.MarketUrl%%" target="_blank">%%SUCURI.Update.Extension%%</a>
6
+ </span>
7
+ </td>
8
+ <td><span class="sucuriscan-monospace">%%SUCURI.Update.Version%%</span></td>
9
+ <td><span class="sucuriscan-monospace">%%SUCURI.Update.NewVersion%%</span></td>
10
+ <td>%%SUCURI.Update.TestedWith%%</td>
11
+ <td><a href="%%SUCURI.Update.ArchiveUrl%%" target="_blank">download</a></td>
12
+ </tr>
inc/tpl/posthack-updatesecretkeys.html.tpl CHANGED
@@ -1,5 +1,5 @@
1
 
2
- <div id="poststuff" class="sucuriscan-update-security-keys">
3
  <div class="postbox">
4
  <div class="inside">
5
  <p>
1
 
2
+ <div class="sucuriscan-panelstuff sucuriscan-update-security-keys">
3
  <div class="postbox">
4
  <div class="inside">
5
  <p>
inc/tpl/posthack.html.tpl CHANGED
@@ -10,6 +10,9 @@
10
  <li>
11
  <a href="#reset-plugins" data-tabname="reset-plugins">Reset Plugins</a>
12
  </li>
 
 
 
13
  </ul>
14
 
15
  <div class="sucuriscan-tab-containers">
@@ -24,5 +27,9 @@
24
  <div id="sucuriscan-reset-plugins">
25
  %%%SUCURI.ResetPlugins%%%
26
  </div>
 
 
 
 
27
  </div>
28
  </div>
10
  <li>
11
  <a href="#reset-plugins" data-tabname="reset-plugins">Reset Plugins</a>
12
  </li>
13
+ <li>
14
+ <a href="#updates" data-tabname="updates">Available Updates</a>
15
+ </li>
16
  </ul>
17
 
18
  <div class="sucuriscan-tab-containers">
27
  <div id="sucuriscan-reset-plugins">
28
  %%%SUCURI.ResetPlugins%%%
29
  </div>
30
+
31
+ <div id="sucuriscan-updates">
32
+ %%%SUCURI.AvailableUpdates%%%
33
+ </div>
34
  </div>
35
  </div>
inc/tpl/settings-alert.html.tpl CHANGED
@@ -1,5 +1,5 @@
1
 
2
- <div id="poststuff">
3
  %%%SUCURI.AlertSettings.Recipients%%%
4
 
5
  %%%SUCURI.AlertSettings.Subject%%%
1
 
2
+ <div class="sucuriscan-panelstuff">
3
  %%%SUCURI.AlertSettings.Recipients%%%
4
 
5
  %%%SUCURI.AlertSettings.Subject%%%
inc/tpl/settings-apiservice-protocol.html.tpl ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <div class="postbox">
3
+ <h3>API Communication Protocol</h3>
4
+
5
+ <div class="inside">
6
+ <p>
7
+ HTTPS is a protocol for secure communication over a computer network which is
8
+ widely used on the Internet. HTTPS consists of communication over Hypertext
9
+ Transfer Protocol (HTTP) within a connection encrypted by Transport Layer
10
+ Security or its predecessor, Secure Sockets Layer. The main motivation for HTTPS
11
+ is authentication of the visited website and protection of the privacy and
12
+ integrity of the exchanged data.
13
+ </p>
14
+
15
+ <div class="sucuriscan-inline-alert-info">
16
+ <p>
17
+ HTTPS provides authentication of the website and associated web server with
18
+ which one is communicating, which protects against <a target="_blank"
19
+ href="https://en.wikipedia.org/wiki/Man-in-the-middle_attack">man-in-the-middle
20
+ attacks</a>. Additionally, it provides bidirectional encryption of communications
21
+ between a client and server, which protects against eavesdropping and tampering
22
+ with and/or forging the contents of the communication. In practice, this provides
23
+ a reasonable guarantee that one is communicating with precisely the website that
24
+ one intended to communicate with (as opposed to an impostor), as well as ensuring
25
+ that the contents of communications between the user and site cannot be read or
26
+ forged by any third party.
27
+ </p>
28
+ </div>
29
+
30
+ <p>
31
+ More info at <a href="https://en.wikipedia.org/wiki/HTTPS" target="_blank">WikiPedia HTTPS</a>
32
+ </p>
33
+
34
+ <div class="sucuriscan-hstatus sucuriscan-hstatus-%%SUCURI.ApiProtocol.StatusNum%%">
35
+ <span>API Communication via HTTPS is %%SUCURI.ApiProtocol.Status%%</span>
36
+ <form action="%%SUCURI.URL.Settings%%#apiservice" method="post">
37
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
38
+ <input type="hidden" name="sucuriscan_api_protocol" value="%%SUCURI.ApiProtocol.SwitchValue%%" />
39
+ <button type="submit" class="button-primary %%SUCURI.ApiProtocol.SwitchCssClass%%">%%SUCURI.ApiProtocol.SwitchText%%</button>
40
+ </form>
41
+ </div>
42
+
43
+ <script type="text/javascript">
44
+ jQuery(function ($) {
45
+ $('body').on('click', '#sucuriscan-debug-api-calls button', function (ev) {
46
+ ev.preventDefault();
47
+ var apiUnique;
48
+ var testedUrls = 0;
49
+ var button = $(this);
50
+ var apiUrls = $('#sucuriscan-debug-api-calls tbody :checkbox:checked');
51
+ var totalApiUrls = apiUrls.length;
52
+
53
+ button.attr('disabled', true);
54
+ button.html('Test API Calls &mdash; Loading...');
55
+ $('#sucuriscan-debug-api-calls tbody td > div').html('');
56
+
57
+ apiUrls.each(function (key, el) {
58
+ apiUnique = $(el).val();
59
+ $('#sucuriscan-api-' + apiUnique).html('Loading...');
60
+
61
+ $.post('%%SUCURI.AjaxURL.Settings%%', {
62
+ action: 'sucuriscan_settings_ajax',
63
+ sucuriscan_page_nonce: '%%SUCURI.PageNonce%%',
64
+ form_action: 'debug_api_call',
65
+ api_unique: apiUnique
66
+ }, function (data) {
67
+ testedUrls++;
68
+ $('#sucuriscan-api-' + data.unique).html(data.output);
69
+
70
+ if (testedUrls === totalApiUrls) {
71
+ button.attr('disabled', false);
72
+ button.html('Test API Calls');
73
+ }
74
+ });
75
+ });
76
+ });
77
+ });
78
+ </script>
79
+
80
+ <form id="sucuriscan-debug-api-calls" action="%%SUCURI.URL.Settings%%#apiservice" method="post">
81
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
82
+
83
+ <table class="wp-list-table widefat sucuriscan-table">
84
+ <thead>
85
+ <tr>
86
+ <th class="manage-column column-cb check-column">
87
+ <label class="screen-reader-text" for="cb-select-all-1">Select All</label>
88
+ <input id="cb-select-all-1" type="checkbox">
89
+ </th>
90
+ <th class="manage-column" colspan="2">API URL <em>(URLs affected by this setting)</em></th>
91
+ </tr>
92
+ </thead>
93
+
94
+ <tbody>
95
+ %%%SUCURI.ApiProtocol.AffectedUrls%%%
96
+ </tbody>
97
+ </table>
98
+
99
+ <div class="sucuriscan-recipient-form">
100
+ <button type="submit" name="sucuriscan_debug_api_calls"
101
+ value="1" class="button-primary">Test API Calls</button>
102
+ </div>
103
+ </form>
104
+ </div>
105
+ </div>
inc/tpl/settings-apiservice-protocol.snippet.tpl ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+
2
+ <tr class="%%SUCURI.ApiProtocol.CssClass%%">
3
+ <td class="check-column">
4
+ <input type="checkbox" name="sucuriscan_api_ids[]" value="%%SUCURI.ApiProtocol.ID%%" />
5
+ </td>
6
+ <td><span class="sucuriscan-monospace">%%SUCURI.ApiProtocol.URL%%</span></td>
7
+ <td><div id="sucuriscan-api-%%SUCURI.ApiProtocol.ID%%">&nbsp;</div></td>
8
+ </tr>
inc/tpl/settings-apiservice.html.tpl CHANGED
@@ -1,5 +1,5 @@
1
 
2
- <div id="poststuff" class="sucuriscan-general-apiservice">
3
  %%%SUCURI.SettingsSection.ApiStatus%%%
4
 
5
  %%%SUCURI.SettingsSection.ApiProxy%%%
@@ -7,4 +7,6 @@
7
  %%%SUCURI.SettingsSection.ApiSSL%%%
8
 
9
  %%%SUCURI.SettingsSection.ApiTimeout%%%
 
 
10
  </div>
1
 
2
+ <div class="sucuriscan-panelstuff sucuriscan-general-apiservice">
3
  %%%SUCURI.SettingsSection.ApiStatus%%%
4
 
5
  %%%SUCURI.SettingsSection.ApiProxy%%%
7
  %%%SUCURI.SettingsSection.ApiSSL%%%
8
 
9
  %%%SUCURI.SettingsSection.ApiTimeout%%%
10
+
11
+ %%%SUCURI.SettingsSection.ApiProtocol%%%
12
  </div>
inc/tpl/settings-corefiles-cache.html.tpl ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <div class="postbox">
3
+ <h3>Core Integrity Checks - Marked As Fixed</h3>
4
+
5
+ <div class="inside">
6
+ <p>
7
+ The scanner is prone to inconsistencies due to the diversity of configurations
8
+ that a hosting provider may have in their servers, many of them add files in the
9
+ document root of the websites with information associated to 3rd-party services
10
+ that they offer or programs that they are running in their system. These files
11
+ will be flagged by the plugin as <em>"added"</em> because they are not part of
12
+ the official WordPress packages, but it is clear that they are false/positives.
13
+ Some of these files are being ignored by the plugin to reduce the noise in the
14
+ integrity checks, but there are many others that are not, you will have to
15
+ select them and mark them as fixed if you believe they are harmless, this action
16
+ will force the plugin to ignore them in future scans.
17
+ </p>
18
+
19
+ <div class="sucuriscan-hstatus sucuriscan-hstatus-2">
20
+ <span>Core Files Marked As Fixed: %%SUCURI.CoreFiles.CacheSize%% of data</span>
21
+ <form action="%%SUCURI.URL.Settings%%#scanner" method="post">
22
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
23
+ <input type="hidden" name="sucuriscan_corefiles_cache" value="1" />
24
+ <button type="submit" class="button-primary">Reset Cache</button>
25
+ </form>
26
+ </div>
27
+
28
+ <table class="wp-list-table widefat sucuriscan-table sucuriscan-%%SUCURI.CoreFiles.TableVisibility%%">
29
+ <thead>
30
+ <tr>
31
+ <th>Reason</th>
32
+ <th>Ignored At</th>
33
+ <th>Line</th>
34
+ </tr>
35
+ </thead>
36
+
37
+ <tbody>
38
+ %%%SUCURI.CoreFiles.IgnoredFiles%%%
39
+ </tbody>
40
+ </table>
41
+ </div>
42
+ </div>
inc/tpl/settings-corefiles-cache.snippet.tpl ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+
2
+ <tr class="%%SUCURI.IgnoredFile.CssClass%% sucuriscan-corefiles-%%SUCURI.IgnoredFile.UniqueId%%">
3
+ <td><span class="sucuriscan-label sucuriscan-label-%%SUCURI.IgnoredFile.StatusType%%">%%SUCURI.IgnoredFile.StatusType%%</span></td>
4
+ <td>%%SUCURI.IgnoredFile.IgnoredAt%%</td>
5
+ <td><span class="sucuriscan-monospace sucuriscan-wraptext">%%SUCURI.IgnoredFile.FilePath%%</span></td>
6
+ </tr>
inc/tpl/settings-corefiles-language.html.tpl ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <div class="postbox">
3
+ <h3>Core Integrity Checks - Language</h3>
4
+
5
+ <div class="inside">
6
+ <p>
7
+ The information necessary to check the integrity of the core files is obtained
8
+ from the official <a href="http://codex.wordpress.org/WordPress.org_API"
9
+ target="_blank">WordPress API</a> using an endpoint that returns the checksums
10
+ of all the files associated to a version number. By default the API returns the
11
+ checksums for the English installation, and there is an optional parameter named
12
+ locale that accepts a valid abbreviation for a supported language. If your website
13
+ was not installed using the English package please choose the appropriate language
14
+ below.
15
+ </p>
16
+
17
+ <p>
18
+ <strong>Note:</strong> Not all the international language codes are supported by
19
+ WordPress's API, you must expect incompatibilities with the results of the core
20
+ integrity checks, if you see files that are being flagged as added even when they
21
+ are part of the official releases, files that are being flagged as deleted even
22
+ when they are part of the official releases, and/or files that are being flagged
23
+ as modified even when their content has not been modified please consider to
24
+ select the English locale, if the false positives are persistent then fill a
25
+ ticket reporting the issue.
26
+ </p>
27
+
28
+ <form action="%%SUCURI.URL.Settings%%#scanner" method="post">
29
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
30
+ <span class="sucuriscan-input-group">
31
+ <label>WordPress Locale:</label>
32
+ <select name="sucuriscan_set_language">
33
+ %%%SUCURI.Integrity.LanguageDropdown%%%
34
+ </select>
35
+ </span>
36
+ <button type="submit" class="button-primary">Proceed</button>
37
+ <em>(WordPress Locale %%SUCURI.Integrity.WordPressLocale%%)</em>
38
+ </form>
39
+ </div>
40
+ </div>
inc/tpl/settings-corefiles-status.html.tpl ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <div class="postbox">
3
+ <h3>Core Integrity Checks</h3>
4
+
5
+ <div class="inside">
6
+ <p>
7
+ This tool allows you to scan the core directories searching for added, modified,
8
+ and deleted files, there is no need to touch any of these core files so any
9
+ inconsistency notified after the scan must be considered as a high severity
10
+ warning as it may be a sign that a malicious person got access to the website
11
+ and was able to add malicious code, modify files to inject malware, and/or delete
12
+ important parts of the project.
13
+ </p>
14
+
15
+ <div class="sucuriscan-inline-alert-info">
16
+ <p>
17
+ Note that this tool does not checks for malicious code, for that you have to
18
+ use the <a href="%%SUCURI.URL.Scanner%%">Malware Scanner</a> instead.
19
+ </p>
20
+ </div>
21
+
22
+ <p>
23
+ This tool detects changes in the project core files using a list of checksums
24
+ that WordPress provides via their official API service, if a file in the website
25
+ has a different checksum then the plugin displays a warning saying that the file
26
+ was modified. If the file is listed in the data provided by WordPress but does
27
+ not exists in the website then the plugin displays a warning saying that the
28
+ file was deleted. If the plugin finds a file in one of the core directories that
29
+ is not listed in the checksums then it displays a warning saying that the file
30
+ was added.
31
+ </p>
32
+
33
+ <div class="sucuriscan-hstatus sucuriscan-hstatus-%%SUCURI.Integrity.StatusNum%%">
34
+ <span>Core Integrity Checks are %%SUCURI.Integrity.Status%%</span>
35
+ <form action="%%SUCURI.URL.Settings%%#scanner" method="post">
36
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
37
+ <input type="hidden" name="sucuriscan_scan_checksums" value="%%SUCURI.Integrity.SwitchValue%%" />
38
+ <button type="submit" class="button-primary %%SUCURI.Integrity.SwitchCssClass%%">%%SUCURI.Integrity.SwitchText%%</button>
39
+ </form>
40
+ </div>
41
+ </div>
42
+ </div>
inc/tpl/settings-general-apikey.html.tpl CHANGED
@@ -40,12 +40,22 @@
40
  </p>
41
  </div>
42
 
43
- <div class="sucuriscan-hstatus sucuriscan-hstatus-0 sucuriscan-%%SUCURI.APIKey.RecoverVisibility%%">
44
- <div class="sucuriscan-monospace">Plugin API Key: %%SUCURI.APIKey%%</div>
45
- <form action="%%SUCURI.URL.Settings%%" method="post">
46
- <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
47
- <button type="submit" name="sucuriscan_recover_key" class="button-primary">Recover</button>
48
- </form>
 
 
 
 
 
 
 
 
 
 
49
  </div>
50
 
51
  <div class="sucuriscan-hstatus sucuriscan-hstatus-1 sucuriscan-%%SUCURI.APIKey.RemoveVisibility%%">
40
  </p>
41
  </div>
42
 
43
+ <div class="sucuriscan-%%SUCURI.APIKey.RecoverVisibility%%">
44
+ <div class="sucuriscan-hstatus sucuriscan-hstatus-0">
45
+ <div class="sucuriscan-monospace">Plugin API Key: %%SUCURI.APIKey%%</div>
46
+ <form action="%%SUCURI.URL.Settings%%" method="post">
47
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
48
+ <button type="submit" name="sucuriscan_recover_key" class="button-primary">Recover Via E-mail</button>
49
+ </form>
50
+ </div>
51
+
52
+ <p>
53
+ If you don't have access to the e-mail address used to generate the
54
+ API key, but have a copy of the key at hand you can <a target="_self"
55
+ href="%%SUCURI.URL.Settings%%&recover">click this link</a> to activate
56
+ the plugin manually. Be aware that if the key is invalid the plugin will
57
+ delete it afterwards.
58
+ </p>
59
  </div>
60
 
61
  <div class="sucuriscan-hstatus sucuriscan-hstatus-1 sucuriscan-%%SUCURI.APIKey.RemoveVisibility%%">
inc/tpl/settings-general-datastorage.html.tpl CHANGED
@@ -32,6 +32,14 @@
32
  </p>
33
  </div>
34
 
 
 
 
 
 
 
 
 
35
  <div class="sucuriscan-hstatus sucuriscan-hstatus-2">
36
  <span class="sucuriscan-monospace">%%SUCURI.DatastorePath%%</span>
37
  </div>
32
  </p>
33
  </div>
34
 
35
+ <div class="sucuriscan-inline-alert-info">
36
+ <p>
37
+ An alternative to this setting you can opt to set the directory path from the
38
+ WordPress configuration file using a constant named <em>"SUCURI_DATA_STORAGE"</em>
39
+ it must contain a valid and existing absolute directory path.
40
+ </p>
41
+ </div>
42
+
43
  <div class="sucuriscan-hstatus sucuriscan-hstatus-2">
44
  <span class="sucuriscan-monospace">%%SUCURI.DatastorePath%%</span>
45
  </div>
inc/tpl/settings-general.html.tpl CHANGED
@@ -1,5 +1,5 @@
1
 
2
- <div id="poststuff" class="sucuriscan-general-settings">
3
  %%%SUCURI.SettingsSection.ApiKey%%%
4
 
5
  %%%SUCURI.SettingsSection.DataStorage%%%
1
 
2
+ <div class="sucuriscan-panelstuff sucuriscan-general-settings">
3
  %%%SUCURI.SettingsSection.ApiKey%%%
4
 
5
  %%%SUCURI.SettingsSection.DataStorage%%%
inc/tpl/settings-heartbeat.html.tpl CHANGED
@@ -1,5 +1,5 @@
1
 
2
- <div id="poststuff">
3
  <div class="postbox sucuriscan-border sucuriscan-table-description">
4
  <h3>Heartbeat</h3>
5
 
1
 
2
+ <div class="sucuriscan-panelstuff">
3
  <div class="postbox sucuriscan-border sucuriscan-table-description">
4
  <h3>Heartbeat</h3>
5
 
inc/tpl/settings-ignorerules.html.tpl CHANGED
@@ -1,5 +1,5 @@
1
 
2
- <div id="poststuff">
3
  <div class="postbox sucuriscan-border sucuriscan-border-bad sucuriscan-%%SUCURI.IgnoreRules.MessageVisibility%%">
4
  <h3>Ignore Alerts</h3>
5
 
@@ -15,7 +15,7 @@
15
  </div>
16
  </div>
17
 
18
- <div id="poststuff">
19
  <div class="postbox sucuriscan-border sucuriscan-table-description sucuriscan-%%SUCURI.IgnoreRules.TableVisibility%%">
20
  <h3>Ignore Alerts</h3>
21
 
1
 
2
+ <div class="sucuriscan-panelstuff">
3
  <div class="postbox sucuriscan-border sucuriscan-border-bad sucuriscan-%%SUCURI.IgnoreRules.MessageVisibility%%">
4
  <h3>Ignore Alerts</h3>
5
 
15
  </div>
16
  </div>
17
 
18
+ <div class="sucuriscan-panelstuff">
19
  <div class="postbox sucuriscan-border sucuriscan-table-description sucuriscan-%%SUCURI.IgnoreRules.TableVisibility%%">
20
  <h3>Ignore Alerts</h3>
21
 
inc/tpl/settings-ignorescan-files.html.tpl ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <div class="postbox">
3
+ <h3>Ignore Scanning for Files</h3>
4
+
5
+ <div class="inside">
6
+ <p>
7
+ By default the file system scanner ignore the directories listed here. You can
8
+ use this panel to insert individual files or symbolic links in the list using
9
+ their absolute path. By aware that the form only accepts valid file paths,
10
+ wildcards are not allowed to prevent the misuse of this tool.
11
+ </p>
12
+
13
+ <form action="%%SUCURI.URL.Settings%%#ignorescanning" method="post">
14
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
15
+ <input type="hidden" name="sucuriscan_ignorescanning_action" value="ignore" />
16
+ <input type="text" name="sucuriscan_ignorescanning_file" placeholder="e.g. /private/cert.crt" />
17
+ <button type="submit" class="button button-primary">Proceed</button>
18
+ </form>
19
+ </div>
20
+ </div>
inc/tpl/settings-ignorescan-folders.html.tpl ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <div class="postbox">
3
+ <h3>Ignore Scanning for Folders</h3>
4
+
5
+ <div class="inside">
6
+ <p>
7
+ Selecting one or more directories from the list will force the plugin to ignore
8
+ the monitoring of the sub-folders and files inside these directories during the
9
+ execution of any of the file system scanners. This will applies to all the scanners
10
+ <em>(general scanner, modified files, integrity checks, error logs)</em>.
11
+ </p>
12
+
13
+ <script type="text/javascript">
14
+ jQuery(function($){
15
+ $('.sucuriscan-ignorescanning tbody').html(
16
+ '<tr><td colspan="3"><span>Loading <em>(may take '
17
+ + 'several seconds)</em>...</span></td></tr>'
18
+ );
19
+ $.post('%%SUCURI.AjaxURL.Settings%%', {
20
+ action: 'sucuriscan_settings_ajax',
21
+ sucuriscan_page_nonce: '%%SUCURI.PageNonce%%',
22
+ form_action: 'get_ignored_files',
23
+ }, function(data){
24
+ $('.sucuriscan-ignorescanning tbody').html(data);
25
+ });
26
+ });
27
+ </script>
28
+
29
+ <form action="%%SUCURI.URL.Settings%%#ignorescanning" method="post">
30
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
31
+
32
+ <table class="wp-list-table widefat sucuriscan-table sucuriscan-ignorescanning">
33
+ <thead>
34
+ <th class="manage-column column-cb check-column">
35
+ <label class="screen-reader-text" for="cb-select-all-1">Select All</label>
36
+ <input id="cb-select-all-1" type="checkbox">
37
+ </th>
38
+ <th class="manage-column">Directory or File Path</th>
39
+ <th class="manage-column">Status</th>
40
+ </thead>
41
+
42
+ <tbody>
43
+ </tbody>
44
+ </table>
45
+
46
+ <div class="sucuriscan-recipient-form">
47
+ <label>
48
+ <select name="sucuriscan_ignorescanning_action">
49
+ <option value="">Choose action</option>
50
+ <option value="ignore">Ignore items</option>
51
+ <option value="unignore">Un-ignore items</option>
52
+ </select>
53
+ </label>
54
+
55
+ <button type="submit" class="button button-primary">Proceed</button>
56
+ </div>
57
+ </form>
58
+ </div>
59
+ </div>
inc/tpl/settings-ignorescan-status.html.tpl ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <div class="postbox">
3
+ <h3>Ignore Scanning</h3>
4
+
5
+ <div class="inside">
6
+ <p>
7
+ If your project has too many directories and/or files it may cause the file
8
+ system scanners to fail, you may want to increase the maximum execution time of
9
+ the PHP scripts and the memory limit to allow the functions executed during the
10
+ file system scans to finish successfully. If you do not want or do not have
11
+ sufficient privileges to increase these values then you may want to skip some
12
+ directories, this will force the plugin to ignore the files inside these
13
+ folders.
14
+ </p>
15
+
16
+ <div class="sucuriscan-hstatus sucuriscan-hstatus-2">
17
+ <span>Ignore Scanning is %%SUCURI.IgnoreScan.Status%%</span>
18
+ <form action="%%SUCURI.URL.Settings%%#ignorescanning" method="post">
19
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
20
+ <input type="hidden" name="sucuriscan_ignore_scanning" value="%%SUCURI.IgnoreScan.SwitchValue%%" />
21
+ <button type="submit" class="button-primary %%SUCURI.IgnoreScan.SwitchCssClass%%">%%SUCURI.IgnoreScan.SwitchText%%</button>
22
+ </form>
23
+ </div>
24
+ </div>
25
+ </div>
inc/tpl/settings-ignorescan.html.tpl ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+
2
+ <div class="sucuriscan-panelstuff sucuriscan-general-scanner">
3
+ %%%SUCURI.SettingsSection.IgnoreScanStatus%%%
4
+
5
+ %%%SUCURI.SettingsSection.IgnoreScanFiles%%%
6
+
7
+ %%%SUCURI.SettingsSection.IgnoreScanFolders%%%
8
+ </div>
inc/tpl/settings-ignorescan.snippet.tpl ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+
2
+ <tr class="%%SUCURI.IgnoreScan.CssClass%%">
3
+ <td class="check-column">
4
+ <input type="checkbox" name="sucuriscan_ignorescanning_dirs[]" value="%%SUCURI.IgnoreScan.DirectoryPath%%" />
5
+ </td>
6
+ <td><span class="sucuriscan-monospace sucuriscan-wraptext">%%SUCURI.IgnoreScan.DirectoryPath%%</span></td>
7
+ <td><span class="sucuriscan-label-%%SUCURI.IgnoreScan.IgnoredCssClass%%">%%SUCURI.IgnoreScan.IgnoredAtText%%</span></td>
8
+ </tr>
inc/tpl/settings-ignorescanning.html.tpl DELETED
@@ -1,95 +0,0 @@
1
-
2
- <div id="poststuff">
3
- <div class="postbox sucuriscan-border sucuriscan-table-description">
4
- <h3>Ignore Scanning</h3>
5
-
6
- <div class="inside">
7
- <p>
8
- If your project has too many directories and/or files it may cause the file
9
- system scanners to fail, you may want to increase the maximum execution time of
10
- the PHP scripts and the memory limit to allow the functions executed during the
11
- file system scans to finish successfully. If you do not want or do not have
12
- sufficient privileges to increase these values then you may want to skip some
13
- directories, this will force the plugin to ignore the files inside these
14
- folders.
15
- </p>
16
-
17
- <div class="sucuriscan-inline-alert-warning sucuriscan-%%SUCURI.IgnoreScanning.DisabledVisibility%%">
18
- <p>
19
- The feature to ignore directories during the file system scans is disabled, go
20
- to the <em>Scanner Settings</em> panel to enable it.
21
- </p>
22
- </div>
23
-
24
- <div class="sucuriscan-inline-alert-info sucuriscan-ignore-file">
25
- <p>
26
- You can also force the plugin to ignore specific files during the file system
27
- scans using this form, add the absolute path of the file or symbolic link that
28
- you want to skip. <strong>Note.</strong> You can not use wildcards to select
29
- multiple files following a pattern in their names, this is intentional to
30
- prevent the misuse of this tool.
31
- </p>
32
-
33
- <form action="%%SUCURI.URL.Settings%%#ignorescanning" method="post">
34
- <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
35
- <input type="hidden" name="sucuriscan_ignorescanning_action" value="ignore" />
36
- <input type="text" name="sucuriscan_ignorescanning_file"
37
- placeholder="e.g. /public_html/private/ssl_certificate.crt"
38
- class="sucuriscan-ignore-file-input" />
39
- <button type="submit" class="button button-primary
40
- sucuriscan-ignore-file-button">Proceed</button>
41
- </form>
42
- </div>
43
- </div>
44
- </div>
45
- </div>
46
-
47
- <form action="%%SUCURI.URL.Settings%%#ignorescanning" method="post">
48
- <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
49
-
50
- <table class="wp-list-table widefat sucuriscan-table sucuriscan-settings-ignorescanning">
51
- <thead>
52
- <th class="manage-column column-cb check-column">
53
- <label class="screen-reader-text" for="cb-select-all-1">Select All</label>
54
- <input id="cb-select-all-1" type="checkbox">
55
- </th>
56
- <th class="manage-column">&nbsp;</th>
57
- <th class="manage-column">Directory</th>
58
- <th class="manage-column" width="200">Ignored At</th>
59
- </thead>
60
-
61
- <tbody>
62
- %%%SUCURI.IgnoreScanning.ResourceList%%%
63
-
64
- <tr class="sucuriscan-%%SUCURI.IgnoreScanning.NoItemsVisibility%%">
65
- <td colspan="4">
66
- <em>List is empty.</em>
67
- </td>
68
- </tr>
69
- </tbody>
70
-
71
- <tfoot>
72
- <tr>
73
- <td colspan="4">
74
- <p>
75
- Selecting one or more directories from the list will force the plugin to ignore
76
- the monitoring of the sub-folders and files inside these directories during the
77
- execution of any of the file system scanners. This will applies to all the
78
- scanners <em>(general scanner, modified files, integrity checks, error
79
- logs)</em>.
80
- </p>
81
-
82
- <label>
83
- <select name="sucuriscan_ignorescanning_action">
84
- <option value="">Choose action</option>
85
- <option value="ignore">Ignore items</option>
86
- <option value="unignore">Un-ignore items</option>
87
- </select>
88
- </label>
89
-
90
- <button type="submit" class="button button-primary">Send action</button>
91
- </td>
92
- </tr>
93
- </tfoot>
94
- </table>
95
- </form>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
inc/tpl/settings-ignorescanning.snippet.tpl DELETED
@@ -1,9 +0,0 @@
1
-
2
- <tr class="%%SUCURI.IgnoreScanning.CssClass%%">
3
- <td class="check-column">
4
- <input type="checkbox" name="sucuriscan_ignorescanning_dirs[]" value="%%SUCURI.IgnoreScanning.DirectoryPath%%" />
5
- </td>
6
- <td><span class="sucuriscan-label-%%SUCURI.IgnoreScanning.IgnoredCssClass%%">%%SUCURI.IgnoreScanning.IgnoredAtText%%</span></td>
7
- <td><span class="sucuriscan-monospace sucuriscan-wraptext">%%SUCURI.IgnoreScanning.DirectoryPath%%</span></td>
8
- <td>%%SUCURI.IgnoreScanning.IgnoredAt%%</td>
9
- </tr>
 
 
 
 
 
 
 
 
 
inc/tpl/settings-scanner.html.tpl CHANGED
@@ -1,5 +1,5 @@
1
 
2
- <div id="poststuff">
3
  <div class="postbox sucuriscan-border sucuriscan-table-description">
4
  <h3>Scanner Settings</h3>
5
 
@@ -91,30 +91,6 @@
91
  </td>
92
  </tr>
93
 
94
- <tr class="alternate">
95
- <td>FS Scanner, Core integrity checks</td>
96
- <td>%%SUCURI.ScanChecksumsStatus%%</td>
97
- <td class="td-with-button">
98
- <form action="%%SUCURI.URL.Settings%%#scanner" method="post">
99
- <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
100
- <input type="hidden" name="sucuriscan_scan_checksums" value="%%SUCURI.ScanChecksumsSwitchValue%%" />
101
- <button type="submit" class="button-primary %%SUCURI.ScanChecksumsSwitchCssClass%%">%%SUCURI.ScanChecksumsSwitchText%%</button>
102
- </form>
103
- </td>
104
- </tr>
105
-
106
- <tr>
107
- <td>FS Scanner, Ignore scanning</td>
108
- <td>%%SUCURI.IgnoreScanningStatus%%</td>
109
- <td class="td-with-button">
110
- <form action="%%SUCURI.URL.Settings%%#scanner" method="post">
111
- <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
112
- <input type="hidden" name="sucuriscan_ignore_scanning" value="%%SUCURI.IgnoreScanningSwitchValue%%" />
113
- <button type="submit" class="button-primary %%SUCURI.IgnoreScanningSwitchCssClass%%">%%SUCURI.IgnoreScanningSwitchText%%</button>
114
- </form>
115
- </td>
116
- </tr>
117
-
118
  <tr class="alternate">
119
  <td>FS Scanner, Error log files</td>
120
  <td>%%SUCURI.ScanErrorlogsStatus%%</td>
@@ -127,66 +103,6 @@
127
  </td>
128
  </tr>
129
 
130
- <tr>
131
- <td>SiteCheck scanner</td>
132
- <td>%%SUCURI.SiteCheckScannerStatus%%</td>
133
- <td class="td-with-button">
134
- <form action="%%SUCURI.URL.Settings%%#scanner" method="post">
135
- <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
136
- <input type="hidden" name="sucuriscan_sitecheck_scanner" value="%%SUCURI.SiteCheckScannerSwitchValue%%" />
137
- <button type="submit" class="button-primary %%SUCURI.SiteCheckScannerSwitchCssClass%%">%%SUCURI.SiteCheckScannerSwitchText%%</button>
138
- </form>
139
- </td>
140
- </tr>
141
-
142
- <tr class="alternate">
143
- <td>SiteCheck counter</td>
144
- <td>%%SUCURI.SiteCheckCounter%% scans so far</td>
145
- <td class="td-with-button">
146
- <form action="%%SUCURI.URL.Scanner%%" method="post">
147
- <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
148
- <input type="hidden" name="sucuriscan_malware_scan" value="1" />
149
- <button type="submit" class="button-primary">Force scan</button>
150
- </form>
151
- </td>
152
- </tr>
153
-
154
- <tr>
155
- <td>Analyze error logs</td>
156
- <td>%%SUCURI.ParseErrorLogsStatus%%</td>
157
- <td class="td-with-button">
158
- <form action="%%SUCURI.URL.Settings%%#scanner" method="post">
159
- <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
160
- <input type="hidden" name="sucuriscan_parse_errorlogs" value="%%SUCURI.ParseErrorLogsSwitchValue%%" />
161
- <button type="submit" class="button-primary %%SUCURI.ParseErrorLogsSwitchCssClass%%">%%SUCURI.ParseErrorLogsSwitchText%%</button>
162
- </form>
163
- </td>
164
- </tr>
165
-
166
- <tr class="alternate">
167
- <td>Error logs limit</td>
168
- <td>Analyze last %%SUCURI.ErrorLogsLimit%% logs</td>
169
- <td class="td-with-button">
170
- <form action="%%SUCURI.URL.Settings%%#scanner" method="post">
171
- <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
172
- <input type="text" name="sucuriscan_errorlogs_limit" placeholder="Number of lines to analyze" class="input-text" />
173
- <button type="submit" class="button-primary">Change</button>
174
- </form>
175
- </td>
176
- </tr>
177
-
178
- <tr>
179
- <td>Reset core integrity logs</td>
180
- <td><span class="sucuriscan-monospace">%%SUCURI.IntegrityLogLife%% of data</span></td>
181
- <td class="td-with-button">
182
- <form action="%%SUCURI.URL.Settings%%#scanner" method="post">
183
- <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
184
- <input type="hidden" name="sucuriscan_reset_logfile" value="integrity" />
185
- <button type="submit" class="button-primary">Reset logs</button>
186
- </form>
187
- </td>
188
- </tr>
189
-
190
  <tr class="alternate">
191
  <td>Reset last login logs</td>
192
  <td><span class="sucuriscan-monospace">%%SUCURI.LastLoginLogLife%% of data</span></td>
@@ -211,17 +127,19 @@
211
  </td>
212
  </tr>
213
 
214
- <tr class="alternate">
215
- <td>Reset sitecheck logs</td>
216
- <td><span class="sucuriscan-monospace">%%SUCURI.SiteCheckLogLife%% of data</span></td>
217
- <td class="td-with-button">
218
- <form action="%%SUCURI.URL.Settings%%#scanner" method="post">
219
- <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
220
- <input type="hidden" name="sucuriscan_reset_logfile" value="sitecheck" />
221
- <button type="submit" class="button-primary">Reset logs</button>
222
- </form>
223
- </td>
224
- </tr>
225
-
226
  </tbody>
227
  </table>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
 
2
+ <div class="sucuriscan-panelstuff">
3
  <div class="postbox sucuriscan-border sucuriscan-table-description">
4
  <h3>Scanner Settings</h3>
5
 
91
  </td>
92
  </tr>
93
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  <tr class="alternate">
95
  <td>FS Scanner, Error log files</td>
96
  <td>%%SUCURI.ScanErrorlogsStatus%%</td>
103
  </td>
104
  </tr>
105
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  <tr class="alternate">
107
  <td>Reset last login logs</td>
108
  <td><span class="sucuriscan-monospace">%%SUCURI.LastLoginLogLife%% of data</span></td>
127
  </td>
128
  </tr>
129
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  </tbody>
131
  </table>
132
+
133
+ <div class="sucuriscan-panelstuff sucuriscan-general-scanner">
134
+ %%%SUCURI.Settings.CoreFilesStatus%%%
135
+
136
+ %%%SUCURI.Settings.CoreFilesLanguage%%%
137
+
138
+ %%%SUCURI.Settings.CoreFilesCache%%%
139
+
140
+ %%%SUCURI.Settings.SiteCheckStatus%%%
141
+
142
+ %%%SUCURI.Settings.SiteCheckCache%%%
143
+
144
+ %%%SUCURI.Settings.SiteCheckTimeout%%%
145
+ </div>
inc/tpl/settings-selfhosting.html.tpl CHANGED
@@ -1,4 +1,4 @@
1
 
2
- <div id="poststuff">
3
  %%%SUCURI.SelfHosting.Monitor%%%
4
  </div>
1
 
2
+ <div class="sucuriscan-panelstuff">
3
  %%%SUCURI.SelfHosting.Monitor%%%
4
  </div>
inc/tpl/settings-sitecheck-cache.html.tpl ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <div class="postbox">
3
+ <h3>Malware Scanner Cache</h3>
4
+
5
+ <div class="inside">
6
+ <p>
7
+ SiteCheck caches by default the results of every scan to reduce the bandwidth
8
+ consumption and to make the subsequent scans faster, if you make modifications
9
+ to your website and want to execute a fresh scan you will have to wait
10
+ <strong>%%SUCURI.SiteCheck.CacheLifeTime%% seconds</strong>. Alternatively, you
11
+ can reset the cache and request a fresh scan immediately.
12
+ </p>
13
+
14
+ <div class="sucuriscan-hstatus sucuriscan-hstatus-2">
15
+ <span>Malware Scanner Cache: %%SUCURI.SiteCheck.CacheSize%% of data</span>
16
+ <form action="%%SUCURI.URL.Settings%%#scanner" method="post">
17
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
18
+ <input type="hidden" name="sucuriscan_sitecheck_cache" value="1" />
19
+ <button type="submit" class="button-primary">Reset Cache</button>
20
+ </form>
21
+ </div>
22
+ </div>
23
+ </div>
inc/tpl/settings-sitecheck-status.html.tpl ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <div class="postbox">
3
+ <h3>Malware Scanner</h3>
4
+
5
+ <div class="inside">
6
+ <p>
7
+ The malware scanner is a free tool powered by <a href="https://sitecheck.sucuri.net/"
8
+ target="_blank">Sucuri SiteCheck</a>, it will check your website for
9
+ known malware, blacklisting status, website errors, and out-of-date
10
+ software. Although we do our best to provide the best results, 100%
11
+ accuracy is not realistic, and not guaranteed. The remote website
12
+ scanner tries to identify if the provided site is infected with any
13
+ type of malware including SPAM or if it has been blacklisted or defaced.
14
+ Sounds simple, but being able to identify these issues remotely <em>
15
+ (without server access)</em> is a very complicated task, and that is
16
+ why we do not guarantee 100% accuracy. If you see a positive result
17
+ in the scan results, it just means that when we scanned we could not
18
+ see anything malicious.
19
+ </p>
20
+
21
+ <div class="sucuriscan-inline-alert-info">
22
+ <p>
23
+ More information at <a href="https://blog.sucuri.net/2012/10/ask-sucuri-how-does-sitecheck-work.html"
24
+ target="_blank">Ask Sucuri: How does SiteCheck works?</a>
25
+ </p>
26
+ </div>
27
+
28
+ <div class="sucuriscan-%%SUCURI.SiteCheck.IfEnabled%%">
29
+ <div class="sucuriscan-hstatus sucuriscan-hstatus-2">
30
+ <span>Malware Scanner is Enabled; used %%SUCURI.SiteCheck.Counter%% times</span>
31
+
32
+ <form action="%%SUCURI.URL.Scanner%%" method="post">
33
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
34
+ <input type="hidden" name="sucuriscan_malware_scan" value="1" />
35
+ <button type="submit" class="button-primary">Scan Now</button>
36
+ </form>
37
+ </div>
38
+
39
+ <p>
40
+ You can disable this scanner adding this constant in your configuration
41
+ file: <code>define('SUCURISCAN_NO_SITECHECK', true);</code>
42
+ </p>
43
+ </div>
44
+
45
+ <div class="sucuriscan-%%SUCURI.SiteCheck.IfDisabled%%">
46
+ <div class="sucuriscan-hstatus sucuriscan-hstatus-0">
47
+ <span>Malware Scanner is Disabled</span>
48
+ </div>
49
+
50
+ <p>
51
+ Enable this scanner by removing the constant <em>"SUCURISCAN_NO_SITECHECK"
52
+ </em> from the configuration file.
53
+ </p>
54
+ </div>
55
+ </div>
56
+ </div>
inc/tpl/settings-sitecheck-timeout.html.tpl ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <div class="postbox">
3
+ <h3>Malware Scanner Timeout</h3>
4
+
5
+ <div class="inside">
6
+ <p>
7
+ <a href="https://sitecheck.sucuri.net/" target="_blank">SiteCheck</a> is a web
8
+ application scanner that reads the source code of a website to determine if it
9
+ is serving malicious code, it scans the home page and linked sub-pages, then
10
+ compares the results with a list of signatures as well as a list of blacklist
11
+ services to see if other malware scanners have flagged the website before. This
12
+ operation may take a couple of seconds, around twenty seconds in most cases; be
13
+ sure to set enough timeout for the operation to finish, otherwise the scanner
14
+ will return innacurate information.
15
+ </p>
16
+
17
+ <div class="sucuriscan-inline-alert-info">
18
+ <p>
19
+ You can set up to %%SUCURI.MaxRequestTimeout%% seconds for the timeout, more than that is not allowed.
20
+ </p>
21
+ </div>
22
+
23
+ <div class="sucuriscan-hstatus sucuriscan-hstatus-2">
24
+ <span>Wait <b>%%SUCURI.RequestTimeout%%</b> before timeout</span>
25
+ </div>
26
+
27
+ <p>
28
+ If you start experiencing issues related with the timeout of the requests
29
+ you may consider to increase the number of seconds to wait for the response.
30
+ You may also want to check with your hosting provider to see if there is
31
+ something in the server blocking the connection.
32
+ </p>
33
+
34
+ <form action="%%SUCURI.URL.Settings%%#scanner" method="post">
35
+ <input type="hidden" name="sucuriscan_page_nonce" value="%%SUCURI.PageNonce%%" />
36
+ <span class="sucuriscan-input-group">
37
+ <label>HTTP Request Timeout (in secs)</label>
38
+ <input type="text" name="sucuriscan_sitecheck_timeout" class="input-text" />
39
+ </span>
40
+ <button type="submit" class="button-primary">Proceed</button>
41
+ </form>
42
+ </div>
43
+ </div>
inc/tpl/settings-trustip.html.tpl CHANGED
@@ -1,5 +1,5 @@
1
 
2
- <div id="poststuff">
3
  <div class="postbox sucuriscan-border sucuriscan-table-description sucuriscan-trustip-form">
4
  <h3>Trust IP Address</h3>
5
 
1
 
2
+ <div class="sucuriscan-panelstuff">
3
  <div class="postbox sucuriscan-border sucuriscan-table-description sucuriscan-trustip-form">
4
  <h3>Trust IP Address</h3>
5
 
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: dd@sucuri.net
3
  Donate Link: https://sucuri.net/
4
  Tags: malware, security, firewall, scan, spam, virus, sucuri, protection,WordPress Security, Login Security,Security Auditing,File Integrity,htaccess,phishing,backdoors,SQL Injection, RFI, LFI, XSS, CSRF, website firewall, Website Security, Performance Optimization, Zero Day, Software Vulnerability, Exploits, Hacks, Attackers, Bad Actors, Reverse Proxy, Two Factor Security, Two Factor Authentication, Security Logs, HeatBleed Vulnerability, Website Protection, Bash Vulnerability, RevSlider Vulnerability, MailPoet Vulnerability, Malware Prevention, Website Firewall, Website AntiVirus, Security Response, Security Detection, Security Prevention
5
  Requires at least:3.2
6
- Stable tag: 1.7.17
7
- Tested up to: 4.4.1
8
 
9
  The Sucuri WordPress Security plugin is a security toolset for security integrity monitoring, malware detection and security hardening.
10
 
@@ -354,6 +354,26 @@ service from the WordPress dashboard.
354
 
355
  == Changelog ==
356
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
357
  = 1.7.17 =
358
  * Added API service failback mechanism
359
  * Added core integrity email on force scan
3
  Donate Link: https://sucuri.net/
4
  Tags: malware, security, firewall, scan, spam, virus, sucuri, protection,WordPress Security, Login Security,Security Auditing,File Integrity,htaccess,phishing,backdoors,SQL Injection, RFI, LFI, XSS, CSRF, website firewall, Website Security, Performance Optimization, Zero Day, Software Vulnerability, Exploits, Hacks, Attackers, Bad Actors, Reverse Proxy, Two Factor Security, Two Factor Authentication, Security Logs, HeatBleed Vulnerability, Website Protection, Bash Vulnerability, RevSlider Vulnerability, MailPoet Vulnerability, Malware Prevention, Website Firewall, Website AntiVirus, Security Response, Security Detection, Security Prevention
5
  Requires at least:3.2
6
+ Stable tag: 1.7.18
7
+ Tested up to: 4.5.3
8
 
9
  The Sucuri WordPress Security plugin is a security toolset for security integrity monitoring, malware detection and security hardening.
10
 
354
 
355
  == Changelog ==
356
 
357
+ = 1.7.18 =
358
+ * Added options library using external file instead of the database
359
+ * Modified API calls using custom HTTP request using Curl
360
+ * Fixed core files marked as broken in a Windows server
361
+ * Fixed pagination links in last and failed logins page
362
+ * Fixed password with ampersands in email notification
363
+ * Fixed whitelist hardening using the authz_core module
364
+ * Removed unnecessary emails to reduce spam
365
+ * Added constant to stop execution of admin init hooks
366
+ * Added explanation for invalid emails and no MX records
367
+ * Added link to open the form to insert the API key manually
368
+ * Added more options in the IP discoverer setting
369
+ * Added option to configure malware scanner timeout
370
+ * Added option to configure the API communication protocol
371
+ * Added option to reset the malware scanner cache
372
+ * Added scheduled task and email alert for available updates
373
+ * Added tool to block user accounts from attempting a login
374
+ * Added tool to debug HTTP requests to the API services
375
+ * Various minor adjustments and fixes
376
+
377
  = 1.7.17 =
378
  * Added API service failback mechanism
379
  * Added core integrity email on force scan
sucuri.php CHANGED
@@ -4,7 +4,7 @@ Plugin Name: Sucuri Security - Auditing, Malware Scanner and Hardening
4
  Plugin URI: https://wordpress.sucuri.net/
5
  Description: The <a href="https://sucuri.net/" target="_blank">Sucuri</a> plugin provides the website owner the best Activity Auditing, SiteCheck Remote Malware Scanning, Effective Security Hardening and Post-Hack features. SiteCheck will check for malware, spam, blacklisting and other security issues like .htaccess redirects, hidden eval code, etc. The best thing about it is it's completely free.
6
  Author: Sucuri, INC
7
- Version: 1.7.17
8
  Author URI: https://sucuri.net
9
  */
10
 
@@ -13,7 +13,6 @@ Author URI: https://sucuri.net
13
  * Main file to control the plugin.
14
  *
15
  * @package Sucuri Security
16
- * @author Yorman Arias <yorman.arias@sucuri.net>
17
  * @author Daniel Cid <dcid@sucuri.net>
18
  * @copyright Since 2010-2015 Sucuri Inc.
19
  * @license Released under the GPL - see LICENSE file for details.
@@ -66,7 +65,7 @@ define('SUCURISCAN', 'sucuriscan');
66
  /**
67
  * Current version of the plugin's code.
68
  */
69
- define('SUCURISCAN_VERSION', '1.7.17');
70
 
71
  /**
72
  * The name of the Sucuri plugin main file.
@@ -76,7 +75,7 @@ define('SUCURISCAN_PLUGIN_FILE', 'sucuri.php');
76
  /**
77
  * The name of the folder where the plugin's files will be located.
78
  */
79
- define('SUCURISCAN_PLUGIN_FOLDER', 'sucuri-scanner');
80
 
81
  /**
82
  * The fullpath where the plugin's files will be located.
@@ -101,7 +100,7 @@ define('SUCURISCAN_PLUGIN_CHECKSUM', @md5_file(SUCURISCAN_PLUGIN_FILEPATH));
101
  /**
102
  * Remote URL where the public Sucuri API service is running.
103
  */
104
- define('SUCURISCAN_API', 'https://wordpress.sucuri.net/api/');
105
 
106
  /**
107
  * Latest version of the public Sucuri API.
@@ -111,7 +110,7 @@ define('SUCURISCAN_API_VERSION', 'v1');
111
  /**
112
  * Remote URL where the CloudProxy API service is running.
113
  */
114
- define('SUCURISCAN_CLOUDPROXY_API', 'https://waf.sucuri.net/api');
115
 
116
  /**
117
  * Latest version of the CloudProxy API.
@@ -153,6 +152,11 @@ define('SUCURISCAN_GET_PLUGINS_LIFETIME', 1800);
153
  */
154
  define('SUCURISCAN_MAX_REQUEST_TIMEOUT', 15);
155
 
 
 
 
 
 
156
  /**
157
  * Plugin's global variables.
158
  *
@@ -207,6 +211,7 @@ if (defined('SUCURISCAN')) {
207
  'sucuriscan_use_wpmail' => 'Use WordPress functions to send mails <em>(uncheck to use native PHP functions)</em>',
208
  'sucuriscan_lastlogin_redirection' => 'Allow redirection after login to report the last-login information',
209
  'sucuriscan_notify_scan_checksums' => 'Receive email alerts for core integrity checks',
 
210
  'sucuriscan_notify_user_registration' => 'user:Receive email alerts for new user registration',
211
  'sucuriscan_notify_success_login' => 'user:Receive email alerts for successful login attempts',
212
  'sucuriscan_notify_failed_login' => 'user:Receive email alerts for failed login attempts <em>(you may receive tons of emails)</em>',
@@ -277,6 +282,9 @@ if (defined('SUCURISCAN')) {
277
  'Sucuri Alert, :event',
278
  );
279
 
 
 
 
280
  /**
281
  * Remove the WordPress generator meta-tag from the source code.
282
  */
@@ -297,9 +305,14 @@ if (defined('SUCURISCAN')) {
297
  * execute the bootstrap function of the plugin.
298
  */
299
  add_action('init', 'SucuriScanInterface::initialize', 1);
300
- add_action('admin_init', 'SucuriScanInterface::create_datastore_folder');
301
- add_action('admin_init', 'SucuriScanInterface::handle_old_plugins');
302
- add_action('admin_enqueue_scripts', 'SucuriScanInterface::enqueue_scripts', 1);
 
 
 
 
 
303
 
304
  /**
305
  * Display extension menu and submenu items in the correct interface. For single
@@ -307,7 +320,7 @@ if (defined('SUCURISCAN')) {
307
  * multisite installations the menu items must be available only in the network
308
  * panel and hidden in the administration panel of the subsites.
309
  */
310
- add_action($sucuriscan_action_prefix . 'admin_menu', 'SucuriScanInterface::add_interface_menu');
311
 
312
  /**
313
  * Attach Ajax requests to a custom page handler.
@@ -361,7 +374,10 @@ if (defined('SUCURISCAN')) {
361
  add_action($hook_name, $hook_func, 50, 5);
362
  }
363
 
364
- add_action('admin_init', 'SucuriScanHook::hook_undefined_actions');
 
 
 
365
  add_action('login_form', 'SucuriScanHook::hook_undefined_actions');
366
  } else {
367
  SucuriScanInterface::error('Function call interceptors are not working properly.');
@@ -529,6 +545,47 @@ class SucuriScan
529
  return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$sz[ $factor ];
530
  }
531
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
532
  /**
533
  * Returns the system filepath to the relevant user uploads directory for this
534
  * site. This is a multisite capable function.
@@ -539,7 +596,16 @@ class SucuriScan
539
  public static function datastore_folder_path($path = '')
540
  {
541
  $default_dir = 'sucuri';
542
- $datastore = SucuriScanOption::get_option(':datastore_path');
 
 
 
 
 
 
 
 
 
543
 
544
  // Use the uploads folder by default.
545
  if (empty($datastore)) {
@@ -550,23 +616,28 @@ class SucuriScan
550
  $upload_dir = wp_upload_dir();
551
 
552
  if (isset($upload_dir['basedir'])) {
553
- $uploads_path = rtrim($upload_dir['basedir'], '/');
554
  }
555
  }
556
 
557
  if ($uploads_path === false) {
558
  if (defined('WP_CONTENT_DIR')) {
559
- $uploads_path = WP_CONTENT_DIR . '/uploads';
560
  } else {
561
- $uploads_path = ABSPATH . '/wp-content/uploads';
562
  }
563
  }
564
 
565
- $datastore = $uploads_path . '/' . $default_dir;
 
566
  SucuriScanOption::update_option(':datastore_path', $datastore);
567
  }
568
 
569
- return $datastore . '/' . $path;
 
 
 
 
570
  }
571
 
572
  /**
@@ -685,6 +756,7 @@ class SucuriScan
685
  {
686
  SucuriScanEvent::filesystem_scan();
687
  sucuriscan_core_files_data(true);
 
688
  }
689
 
690
  /**
@@ -704,7 +776,14 @@ class SucuriScan
704
  public static function allowedHttpHeaders($with_keys = false)
705
  {
706
  $allowed = array(
 
707
  'HTTP_X_SUCURI_CLIENTIP',
 
 
 
 
 
 
708
  'HTTP_X_REAL_IP',
709
  'HTTP_CLIENT_IP',
710
  'HTTP_X_FORWARDED_FOR',
@@ -1024,9 +1103,9 @@ class SucuriScan
1024
  */
1025
  public static function datetime($timestamp = null)
1026
  {
1027
- $date_format = get_option('date_format');
1028
- $time_format = get_option('time_format');
1029
- $tz_format = sprintf('%s %s', $date_format, $time_format);
1030
 
1031
  if (is_numeric($timestamp) && $timestamp > 0) {
1032
  return date_i18n($tz_format, $timestamp);
@@ -1298,30 +1377,6 @@ class SucuriScan
1298
  }
1299
  }
1300
 
1301
- /**
1302
- * Determine if the plugin notices can be displayed in the current page.
1303
- *
1304
- * @param string $current_page Identifier of the current page.
1305
- * @return boolean TRUE if the current page must not have noticies.
1306
- */
1307
- public static function no_notices_here($current_page = false)
1308
- {
1309
- global $sucuriscan_no_notices_in;
1310
-
1311
- if ($current_page === false) {
1312
- $current_page = SucuriScanRequest::get('page');
1313
- }
1314
-
1315
- if (isset($sucuriscan_no_notices_in)
1316
- && is_array($sucuriscan_no_notices_in)
1317
- && !empty($sucuriscan_no_notices_in)
1318
- ) {
1319
- return (bool) in_array($current_page, $sucuriscan_no_notices_in);
1320
- }
1321
-
1322
- return false;
1323
- }
1324
-
1325
  /**
1326
  * Check whether the site is running over the Nginx web server.
1327
  *
@@ -1341,6 +1396,170 @@ class SucuriScan
1341
  {
1342
  return (bool) preg_match('/Microsoft-IIS/i', @$_SERVER['SERVER_SOFTWARE']);
1343
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1344
  }
1345
 
1346
  /**
@@ -1540,7 +1759,7 @@ class SucuriScanFileInfo extends SucuriScan
1540
  public function get_directory_tree_md5($directory = '', $as_array = false)
1541
  {
1542
  $project_signatures = '';
1543
- $abs_path = rtrim(ABSPATH, DIRECTORY_SEPARATOR);
1544
  $files = $this->get_directory_tree($directory);
1545
 
1546
  if ($as_array) {
@@ -1555,7 +1774,7 @@ class SucuriScanFileInfo extends SucuriScan
1555
  $filesize = @filesize($filepath);
1556
 
1557
  if ($as_array) {
1558
- $basename = str_replace($abs_path . DIRECTORY_SEPARATOR, '', $filepath);
1559
  $project_signatures[ $basename ] = array(
1560
  'filepath' => $filepath,
1561
  'checksum' => $file_checksum,
@@ -1564,7 +1783,7 @@ class SucuriScanFileInfo extends SucuriScan
1564
  'modified_at' => @filemtime($filepath),
1565
  );
1566
  } else {
1567
- $filepath = str_replace($abs_path, $abs_path . DIRECTORY_SEPARATOR, $filepath);
1568
  $project_signatures .= sprintf(
1569
  "%s%s%s%s\n",
1570
  $file_checksum,
@@ -1622,7 +1841,9 @@ class SucuriScanFileInfo extends SucuriScan
1622
  break;
1623
  }
1624
 
1625
- return $tree;
 
 
1626
  }
1627
 
1628
  return false;
@@ -2059,6 +2280,26 @@ class SucuriScanFileInfo extends SucuriScan
2059
  return false;
2060
  }
2061
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2062
  /**
2063
  * Return the lines of a file as an array, it will automatically remove the new
2064
  * line characters from the end of each line, and skip empty lines from the
@@ -2295,7 +2536,7 @@ class SucuriScanCache extends SucuriScan
2295
  {
2296
  if (!is_null($this->datastore)) {
2297
  $folder_path = $this->datastore_folder_path();
2298
- $file_path = $folder_path . 'sucuri-' . $this->datastore . '.php';
2299
 
2300
  // Create the datastore parent directory.
2301
  if (!file_exists($folder_path)) {
@@ -2652,8 +2893,8 @@ class SucuriScanOption extends SucuriScanRequest
2652
  $defaults = array(
2653
  'sucuriscan_account' => '',
2654
  'sucuriscan_addr_header' => 'HTTP_X_SUCURI_CLIENTIP',
2655
- 'sucuriscan_ads_visibility' => 'enabled',
2656
  'sucuriscan_api_key' => false,
 
2657
  'sucuriscan_api_service' => 'enabled',
2658
  'sucuriscan_audit_report' => 'disabled',
2659
  'sucuriscan_cloudproxy_apikey' => '',
@@ -2673,10 +2914,12 @@ class SucuriScanOption extends SucuriScanRequest
2673
  'sucuriscan_heartbeat_pulse' => 15,
2674
  'sucuriscan_ignore_scanning' => 'disabled',
2675
  'sucuriscan_ignored_events' => '',
 
2676
  'sucuriscan_last_email_at' => time(),
2677
  'sucuriscan_lastlogin_redirection' => 'enabled',
2678
  'sucuriscan_logs4report' => 500,
2679
  'sucuriscan_maximum_failed_logins' => 30,
 
2680
  'sucuriscan_notify_bruteforce_attack' => 'disabled',
2681
  'sucuriscan_notify_failed_login' => 'enabled',
2682
  'sucuriscan_notify_plugin_activated' => 'disabled',
@@ -2686,7 +2929,7 @@ class SucuriScanOption extends SucuriScanRequest
2686
  'sucuriscan_notify_plugin_installed' => 'disabled',
2687
  'sucuriscan_notify_plugin_updated' => 'disabled',
2688
  'sucuriscan_notify_post_publication' => 'enabled',
2689
- 'sucuriscan_notify_scan_checksums' => 'disabled',
2690
  'sucuriscan_notify_settings_updated' => 'disabled',
2691
  'sucuriscan_notify_success_login' => 'enabled',
2692
  'sucuriscan_notify_theme_activated' => 'disabled',
@@ -2700,6 +2943,7 @@ class SucuriScanOption extends SucuriScanRequest
2700
  'sucuriscan_notify_widget_added' => 'disabled',
2701
  'sucuriscan_notify_widget_deleted' => 'disabled',
2702
  'sucuriscan_parse_errorlogs' => 'enabled',
 
2703
  'sucuriscan_prettify_mails' => 'disabled',
2704
  'sucuriscan_request_timeout' => 5,
2705
  'sucuriscan_revproxy' => 'disabled',
@@ -2712,7 +2956,7 @@ class SucuriScanOption extends SucuriScanRequest
2712
  'sucuriscan_selfhosting_monitor' => 'disabled',
2713
  'sucuriscan_site_version' => '0.0',
2714
  'sucuriscan_sitecheck_counter' => 0,
2715
- 'sucuriscan_sitecheck_scanner' => 'enabled',
2716
  'sucuriscan_use_wpmail' => 'enabled',
2717
  'sucuriscan_verify_ssl_cert' => 'false',
2718
  'sucuriscan_xhr_monitor' => 'disabled',
@@ -2737,15 +2981,14 @@ class SucuriScanOption extends SucuriScanRequest
2737
  /**
2738
  * Check whether an option is used in the plugin or not.
2739
  *
2740
- * @param string $option_name Name of the option that will be checked.
2741
- * @return boolean True if the option is part of the plugin, False otherwise.
2742
  */
2743
- public static function is_valid_plugin_option($option_name = '')
2744
  {
2745
- $valid_options = self::get_default_option_names();
2746
- $is_valid_option = (bool) array_key_exists($option_name, $valid_options);
2747
 
2748
- return $is_valid_option;
2749
  }
2750
 
2751
  /**
@@ -2786,33 +3029,133 @@ class SucuriScanOption extends SucuriScanRequest
2786
  }
2787
 
2788
  /**
2789
- * Alias function for the method Common::SucuriScan_Get_Options()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2790
  *
2791
- * This function search the specified option in the database, not only the options
2792
- * set by the plugin but all the options set for the site. If the value retrieved
2793
- * is FALSE the method tries to search for a default value.
 
 
 
 
 
 
 
 
 
 
 
2794
  *
2795
  * To facilitate the development, you can prefix the name of the key in the
2796
  * request (when accessing it) with a single colon, this function will
2797
  * automatically replace that character with the unique identifier of the
2798
  * plugin.
2799
  *
2800
- * @see https://codex.wordpress.org/Function_Reference/get_option
 
 
 
 
 
2801
  *
2802
- * @param string $option_name Optional parameter that you can use to filter the results to one option.
2803
- * @return string The value (or default value) of the option specified.
2804
  */
2805
- public static function get_option($option_name = '')
2806
  {
2807
- if (function_exists('update_option')) {
2808
- $option_name = self::variable_prefix($option_name);
2809
- $option_value = get_option($option_name);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2810
 
2811
- if ($option_value === false && preg_match('/^sucuriscan_/', $option_name)) {
2812
- $option_value = self::get_default_options($option_name);
 
 
 
 
 
2813
  }
 
2814
 
2815
- return $option_value;
 
2816
  }
2817
 
2818
  return false;
@@ -2828,16 +3171,22 @@ class SucuriScanOption extends SucuriScanRequest
2828
  *
2829
  * @see https://codex.wordpress.org/Function_Reference/update_option
2830
  *
2831
- * @param string $option_name Name of the option to update which must not exceed 64 characters.
2832
- * @param string $option_value The new value for the option, can be an integer, string, array, or object.
2833
- * @return boolean True if option value has changed, false if not or if update failed.
2834
  */
2835
- public static function update_option($option_name = '', $option_value = '')
2836
  {
2837
- if (function_exists('update_option')) {
2838
- $option_name = self::variable_prefix($option_name);
 
 
2839
 
2840
- return update_option($option_name, $option_value);
 
 
 
 
2841
  }
2842
 
2843
  return false;
@@ -2850,15 +3199,25 @@ class SucuriScanOption extends SucuriScanRequest
2850
  *
2851
  * @see https://codex.wordpress.org/Function_Reference/delete_option
2852
  *
2853
- * @param string $option_name Name of the option to be deleted.
2854
- * @return boolean True, if option is successfully deleted. False on failure, or option does not exist.
2855
  */
2856
- public static function delete_option($option_name = '')
2857
  {
2858
- if (function_exists('delete_option')) {
2859
- $option_name = self::variable_prefix($option_name);
 
 
 
 
 
 
 
 
 
2860
 
2861
- return delete_option($option_name);
 
2862
  }
2863
 
2864
  return false;
@@ -2902,7 +3261,16 @@ class SucuriScanOption extends SucuriScanRequest
2902
  );
2903
 
2904
  foreach ($options as $option) {
2905
- self::delete_option($option->option_name);
 
 
 
 
 
 
 
 
 
2906
  }
2907
  }
2908
 
@@ -2928,6 +3296,12 @@ class SucuriScanOption extends SucuriScanRequest
2928
  $settings[ $row->option_name ] = $row->option_value;
2929
  }
2930
 
 
 
 
 
 
 
2931
  return $settings;
2932
  }
2933
 
@@ -3015,15 +3389,7 @@ class SucuriScanOption extends SucuriScanRequest
3015
  $post_types = self::get_option(':ignored_events');
3016
  $post_types_arr = false;
3017
 
3018
- // Encode (old) serialized data into JSON.
3019
- if (self::is_serialized($post_types)) {
3020
- $post_types_arr = @unserialize($post_types);
3021
- $post_types_fix = json_encode($post_types_arr);
3022
- self::update_option(':ignored_events', $post_types_fix);
3023
-
3024
- return $post_types_arr;
3025
- } // Decode JSON-encoded data as an array.
3026
- elseif (preg_match('/^\{.+\}$/', $post_types)) {
3027
  $post_types_arr = @json_decode($post_types, true);
3028
  }
3029
 
@@ -3065,18 +3431,20 @@ class SucuriScanOption extends SucuriScanRequest
3065
  /**
3066
  * Remove a post type from the list of ignored events to send notifications.
3067
  *
3068
- * @param string $event_name Unique post-type name.
3069
- * @return boolean Whether the event was removed from the list or not.
3070
  */
3071
- public static function remove_ignored_event($event_name = '')
3072
  {
3073
- $ignored_events = self::get_ignored_events();
3074
 
3075
- if (array_key_exists($event_name, $ignored_events)) {
3076
- unset($ignored_events[ $event_name ]);
3077
- $saved = self::update_option(':ignored_events', json_encode($ignored_events));
3078
 
3079
- return $saved;
 
 
 
3080
  }
3081
 
3082
  return false;
@@ -3085,19 +3453,15 @@ class SucuriScanOption extends SucuriScanRequest
3085
  /**
3086
  * Check whether an event is being ignored to send notifications or not.
3087
  *
3088
- * @param string $event_name Unique post-type name.
3089
- * @return boolean Whether an event is being ignored or not.
3090
  */
3091
- public static function is_ignored_event($event_name = '')
3092
  {
3093
- $event_name = strtolower($event_name);
3094
- $ignored_events = self::get_ignored_events();
3095
-
3096
- if (array_key_exists($event_name, $ignored_events)) {
3097
- return true;
3098
- }
3099
 
3100
- return false;
3101
  }
3102
 
3103
  /**
@@ -3155,6 +3519,10 @@ class SucuriScanOption extends SucuriScanRequest
3155
  */
3156
  public static function setRevProxy($action = 'disable')
3157
  {
 
 
 
 
3158
  $action_d = $action . 'd';
3159
  $message = 'Reverse proxy support was <code>' . $action_d . '</code>';
3160
 
@@ -3211,7 +3579,7 @@ class SucuriScanEvent extends SucuriScan
3211
  *
3212
  * @return void
3213
  */
3214
- public static function schedule_task()
3215
  {
3216
  $task_name = 'sucuriscan_scheduled_scan';
3217
 
@@ -3219,7 +3587,10 @@ class SucuriScanEvent extends SucuriScan
3219
  wp_schedule_event(time() + 10, 'twicedaily', $task_name);
3220
  }
3221
 
3222
- wp_schedule_single_event(time() + 300, $task_name);
 
 
 
3223
  }
3224
 
3225
  /**
@@ -3321,16 +3692,14 @@ class SucuriScanEvent extends SucuriScan
3321
  * Generates an audit event log (to be sent later).
3322
  *
3323
  * @param integer $severity Importance of the event that will be reported, values from one to five.
3324
- * @param string $location In which part of the system was the event triggered.
3325
  * @param string $message The explanation of the event.
3326
  * @param boolean $internal Whether the event will be publicly visible or not.
3327
  * @return boolean TRUE if the event was logged in the monitoring service, FALSE otherwise.
3328
  */
3329
- private static function report_event($severity = 0, $location = '', $message = '', $internal = false)
3330
  {
3331
  $user = wp_get_current_user();
3332
  $username = false;
3333
- $current_time = date('Y-m-d H:i:s');
3334
  $remote_ip = self::get_remote_addr();
3335
 
3336
  // Identify current user in session.
@@ -3442,7 +3811,7 @@ class SucuriScanEvent extends SucuriScan
3442
  */
3443
  public static function report_debug_event($message = '', $internal = false)
3444
  {
3445
- return self::report_event(0, 'core', $message, $internal);
3446
  }
3447
 
3448
  /**
@@ -3454,7 +3823,7 @@ class SucuriScanEvent extends SucuriScan
3454
  */
3455
  public static function report_notice_event($message = '', $internal = false)
3456
  {
3457
- return self::report_event(1, 'core', $message, $internal);
3458
  }
3459
 
3460
  /**
@@ -3466,7 +3835,7 @@ class SucuriScanEvent extends SucuriScan
3466
  */
3467
  public static function report_info_event($message = '', $internal = false)
3468
  {
3469
- return self::report_event(2, 'core', $message, $internal);
3470
  }
3471
 
3472
  /**
@@ -3478,7 +3847,7 @@ class SucuriScanEvent extends SucuriScan
3478
  */
3479
  public static function report_warning_event($message = '', $internal = false)
3480
  {
3481
- return self::report_event(3, 'core', $message, $internal);
3482
  }
3483
 
3484
  /**
@@ -3490,7 +3859,7 @@ class SucuriScanEvent extends SucuriScan
3490
  */
3491
  public static function report_error_event($message = '', $internal = false)
3492
  {
3493
- return self::report_event(4, 'core', $message, $internal);
3494
  }
3495
 
3496
  /**
@@ -3502,7 +3871,7 @@ class SucuriScanEvent extends SucuriScan
3502
  */
3503
  public static function report_critical_event($message = '', $internal = false)
3504
  {
3505
- return self::report_event(5, 'core', $message, $internal);
3506
  }
3507
 
3508
  /**
@@ -3615,6 +3984,10 @@ class SucuriScanEvent extends SucuriScan
3615
  } elseif ($event == 'scan_checksums') {
3616
  $event = 'core_integrity_checks';
3617
  $email_params['Force'] = true;
 
 
 
 
3618
  }
3619
 
3620
  $title = str_replace('_', "\x20", $event);
@@ -4675,65 +5048,262 @@ class SucuriScanAPI extends SucuriScanOption
4675
  }
4676
 
4677
  /**
4678
- * Retrieves a URL using a changeable HTTP method, returning results in an
4679
- * array. Results include HTTP headers and content.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4680
  *
4681
- * @see https://codex.wordpress.org/Function_Reference/wp_remote_post
4682
- * @see https://codex.wordpress.org/Function_Reference/wp_remote_get
 
 
 
 
 
 
 
 
 
 
 
 
4683
  *
4684
  * @param string $url The target URL where the request will be sent.
4685
  * @param string $method HTTP method that will be used to send the request.
4686
- * @param array $params Parameters for the request defined in an associative array of key-value.
4687
- * @param array $args Request arguments like the timeout, redirections, headers, cookies, etc.
4688
  * @return array Response object after the HTTP request is executed.
4689
  */
4690
  private static function apiCall($url = '', $method = 'GET', $params = array(), $args = array())
4691
  {
4692
- if (!$url) {
4693
- return false;
4694
- }
 
 
 
 
4695
 
4696
- $req_args = array(
4697
- 'method' => $method,
4698
- 'timeout' => self::requestTimeout(),
4699
- 'redirection' => 2,
4700
- 'httpversion' => '1.0',
4701
- 'user-agent' => self::userAgent(),
4702
- 'blocking' => true,
4703
- 'headers' => array(),
4704
- 'cookies' => array(),
4705
- 'compress' => false,
4706
- 'decompress' => false,
4707
- 'sslverify' => self::verifySslCert(),
4708
- );
4709
 
4710
- // Update the request arguments with the values passed tot he function.
4711
- foreach ($args as $arg_name => $arg_value) {
4712
- if (array_key_exists($arg_name, $req_args)) {
4713
- $req_args[$arg_name] = $arg_value;
4714
  }
4715
- }
4716
 
4717
- // Add random request parameter to avoid request reset.
4718
- if (!empty($params) && !array_key_exists('time', $params)) {
4719
- $params['time'] = time();
4720
- }
 
 
4721
 
4722
- if ($method == 'GET') {
4723
- if (!empty($params)) {
4724
- $url = sprintf('%s?%s', $url, http_build_query($params));
 
 
 
 
 
 
 
 
 
4725
  }
4726
 
4727
- $response = wp_remote_get($url, $req_args);
4728
- } elseif ($method == 'POST') {
4729
- $req_args['body'] = $params;
4730
- $response = wp_remote_post($url, $req_args);
4731
- } else {
4732
- $response = false;
4733
- SucuriScanInterface::error('HTTP method not allowed: ' . $method);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4734
  }
4735
 
4736
- return self::processResponse($response, $params, $args);
4737
  }
4738
 
4739
  /**
@@ -4802,16 +5372,6 @@ class SucuriScanAPI extends SucuriScanOption
4802
  $option_name = ':cloudproxy_apikey';
4803
  $api_key = self::get_option($option_name);
4804
 
4805
- // Check if the cloudproxy-waf plugin was previously installed.
4806
- if (!$api_key) {
4807
- $api_key = self::get_option('sucuriwaf_apikey');
4808
-
4809
- if ($api_key) {
4810
- self::update_option($option_name, $api_key);
4811
- self::delete_option('sucuriwaf_apikey');
4812
- }
4813
- }
4814
-
4815
  // Check the validity of the API key.
4816
  $match = self::isValidCloudproxyKey($api_key, true);
4817
 
@@ -4911,139 +5471,30 @@ class SucuriScanAPI extends SucuriScanOption
4911
  }
4912
 
4913
  /**
4914
- * Execute some actions according to the response message.
 
 
4915
  *
4916
- * @param array $response Response object after the HTTP request is executed.
4917
- * @param array $params Parameters for the request defined in an associative array of key-value.
4918
- * @param array $args Request arguments like the timeout, redirections, headers, cookies, etc.
4919
- * @return array Response object with some modifications.
4920
  */
4921
- private static function processResponse($response = array(), $params = array(), $args = array())
4922
  {
4923
- /**
4924
- * Convert the error message generated by the code base functions after the HTTP
4925
- * request is executed to a valid response object that will allow this code
4926
- * process the data according to the specified standards.
4927
- */
4928
- if (is_wp_error($response)) {
4929
- // Extract information from the error object.
4930
- $error_message = $response->get_error_message();
4931
- $request_action = isset($params['a']) ? $params['a'] : 'unknown';
4932
-
4933
- // Build a fake request response with custom data.
4934
- $data_set = array(
4935
- 'status' => 0,
4936
- 'action' => $request_action,
4937
- 'messages' => array( $error_message ),
4938
- 'request_time' => SucuriScan::local_time(),
4939
- 'output' => new stdClass(),
4940
- 'verbose' => 0,
4941
- );
4942
 
4943
- // Build the response object and encode data.
4944
- $response = array();
4945
- $response['body'] = json_encode($data_set);
4946
- $response['headers']['date'] = date('r');
4947
- $response['headers']['connection'] = 'close';
4948
- $response['headers']['content-type'] = 'application/json';
4949
- $response['headers']['content-length'] = strlen($response['body']);
4950
- $response['response']['code'] = 500;
4951
- $response['response']['message'] = 'ERROR';
4952
- }
4953
-
4954
- /**
4955
- * Process the response object.
4956
- *
4957
- * Some response messages and even errors require extra steps of processing to,
4958
- * for example, try to fix automatically issues related with disconnections,
4959
- * timeouts, SSL certificate verifications, etc. Some of these actions can not
4960
- * be fixed if the server where the website is being hosted has a special
4961
- * configuration, which then requires the human interaction of the admin user,
4962
- * they will see extra information explaining the response and how to proceed
4963
- * with it.
4964
- */
4965
- if (is_array($response)
4966
- && array_key_exists('body', $response)
4967
- && array_key_exists('headers', $response)
4968
- && array_key_exists('response', $response)
4969
- ) {
4970
- // Keep a copy of the raw HTTP response.
4971
- $response['body_raw'] = $response['body'];
4972
-
4973
- // Append the non-private HTTP request parameters.
4974
- $response['params'] = $params;
4975
- unset($response['params']['k']);
4976
-
4977
- /**
4978
- * Check and decode the API response.
4979
- *
4980
- * Note that serialized data is going to be ignored, the old API service used to
4981
- * respond to all endpoints with serialized data and considering the risk that
4982
- * it poses to unserialize in PHP it was decided to drop that option and stick
4983
- * to JSON which is a bit safer.
4984
- */
4985
- if (isset($response['headers']['content-type'])
4986
- && $response['headers']['content-type'] == 'application/json'
4987
- ) {
4988
- $assoc = (isset($args['assoc']) && $args['assoc'] === true) ? true : false;
4989
- $response['body'] = @json_decode($response['body_raw'], $assoc);
4990
- $response['body_arr'] = @json_decode($response['body_raw'], true);
4991
- } elseif (self::is_serialized($response['body'])) {
4992
- $response['body_raw'] = null;
4993
- $response['body'] = 'ERROR:Serialized data is not supported.';
4994
- }
4995
-
4996
- return $response;
4997
- }
4998
-
4999
- return false;
5000
- }
5001
-
5002
- /**
5003
- * Determine whether an API response was successful or not checking the expected
5004
- * generic variables and types, in case of an error a notification will appears
5005
- * in the administrator panel explaining the result of the operation.
5006
- *
5007
- * @param array $response HTTP response after API endpoint execution.
5008
- * @param boolean $enqueue Add the log to the local queue on a failure.
5009
- * @return boolean False if the API call failed, true otherwise.
5010
- */
5011
- private static function handleResponse($response = array(), $enqueue = true)
5012
- {
5013
- $error_msg = '';
5014
-
5015
- if ($response) {
5016
- if ($response['body'] instanceof stdClass) {
5017
- if (isset($response['body']->status)) {
5018
- if ($response['body']->status == 1) {
5019
- return true;
5020
- } else {
5021
- return self::handleErrorResponse($response, $enqueue);
5022
- }
5023
- } else {
5024
- $error_msg = 'Could not determine the status of an API call.';
5025
- }
5026
- } else {
5027
- $message = 'non JSON-encoded response.';
5028
-
5029
- if (isset($response['response'])
5030
- && isset($response['response']['message'])
5031
- && isset($response['response']['code'])
5032
- && $response['response']['code'] !== 200
5033
- ) {
5034
- $message = sprintf(
5035
- '(%s) %s',
5036
- $response['response']['code'],
5037
- $response['response']['message']
5038
- );
5039
- }
5040
-
5041
- $error_msg = 'Malformed API response: ' . $message;
5042
- }
5043
- }
5044
-
5045
- if (!empty($error_msg) && $enqueue) {
5046
- SucuriScanInterface::error($error_msg);
5047
  }
5048
 
5049
  return false;
@@ -5082,76 +5533,66 @@ class SucuriScanAPI extends SucuriScanOption
5082
  */
5083
  private static function handleErrorResponse($response = array(), $enqueue = true)
5084
  {
5085
- $action_message = 'Unknown error, there is no more information.';
5086
 
5087
- // Check whether the message list is empty or not.
5088
- if (isset($response['body']->messages[0])) {
5089
- $action_message = $response['body']->messages[0] . '.';
5090
- }
5091
-
5092
- // Keep a copy of the original API response message.
5093
- $raw_message = $action_message;
5094
 
5095
- // Special response for invalid API keys.
5096
- if (stripos($raw_message, 'log file not found') !== false) {
5097
- SucuriScanOption::delete_option(':api_key');
 
 
 
 
 
5098
 
5099
- $action_message .= ' This generally happens when you add an invalid API key, the'
5100
- . ' key will be deleted automatically to hide these warnings, if you want to'
5101
- . ' recover it go to the settings page and use the recover button to send the'
5102
- . ' key to your email address.';
5103
- }
5104
 
5105
- // Special response for invalid CloudProxy API keys.
5106
- if (stripos($raw_message, 'wrong api key') !== false) {
5107
- SucuriScanOption::delete_option(':cloudproxy_apikey');
5108
- SucuriScanOption::setRevProxy('disable');
5109
- SucuriScanOption::setAddrHeader('REMOTE_ADDR');
5110
 
5111
- $action_message .= ' The CloudProxy API key does not seems to be valid.';
5112
- }
5113
 
5114
- // Special response for connection timeouts.
5115
- if ($enqueue && @preg_match('/time(d\s)?out/', $raw_message)) {
5116
- $action_message = ''; /* Empty the error message. */
5117
- $cache = new SucuriScanCache('auditqueue');
5118
- $cache_key = md5($response['params']['time']);
5119
- $cache_value = array(
5120
- 'created_at' => $response['params']['time'],
5121
- 'message' => $response['params']['m'],
5122
- );
5123
- $cache->add($cache_key, $cache_value);
5124
- }
5125
 
5126
- // Stop SSL peer verification on connection failures.
5127
- if (stripos($raw_message, 'no alternative certificate')
5128
- || stripos($raw_message, 'error setting certificate')
5129
- || stripos($raw_message, 'SSL connect error')
5130
- ) {
5131
- SucuriScanOption::update_option(':verify_ssl_cert', 'false');
5132
 
5133
- $action_message .= 'There were some issues with the SSL certificate either in this'
5134
- . ' server or with the remote API service. The automatic verification of the'
5135
- . ' certificates has been deactivated to reduce the noise during the execution'
5136
- . ' of the HTTP requests.';
5137
- }
 
5138
 
5139
- if (!empty($action_message)) {
5140
- if ($enqueue) {
5141
- SucuriScanInterface::error(
5142
- sprintf(
5143
- '(%d) %s: %s',
5144
- SucuriScan::local_time(),
5145
- ucwords($response['body']->action),
5146
- $action_message
5147
- )
5148
- );
5149
  }
 
5150
 
5151
- return false;
 
5152
  }
5153
 
5154
- return true;
5155
  }
5156
 
5157
  /**
@@ -5173,7 +5614,8 @@ class SucuriScanAPI extends SucuriScanOption
5173
  ), false);
5174
 
5175
  if (self::handleResponse($response)) {
5176
- self::setPluginKey($response['body']->output->api_key);
 
5177
  SucuriScanEvent::schedule_task();
5178
  SucuriScanEvent::notify_event('plugin_change', 'Site registered and API key generated');
5179
  SucuriScanInterface::info('The API key for your site was successfully generated and saved.');
@@ -5201,7 +5643,7 @@ class SucuriScanAPI extends SucuriScanOption
5201
 
5202
  if (self::handleResponse($response)) {
5203
  SucuriScanEvent::notify_event('plugin_change', 'API key recovered for domain: ' . $clean_domain);
5204
- SucuriScanInterface::info($response['body']->output->message);
5205
 
5206
  return true;
5207
  }
@@ -5297,7 +5739,7 @@ class SucuriScanAPI extends SucuriScanOption
5297
 
5298
  // If success continue with the retrieval of the logs data.
5299
  if (self::handleResponse($response)) {
5300
- return self::getLogs($response['body']->total_entries);
5301
  }
5302
 
5303
  return false;
@@ -5317,13 +5759,13 @@ class SucuriScanAPI extends SucuriScanOption
5317
  ));
5318
 
5319
  if (self::handleResponse($response)) {
5320
- $response['body']->output_data = array();
5321
  $log_pattern = '/^([0-9\-]+) ([0-9:]+) (\S+) : (.+)/';
5322
  $extra_pattern = '/(.+ \(multiple entries\):) (.+)/';
5323
  $generic_pattern = '/^@?([A-Z][a-z]{3,7}): ([^;]+; )?(.+)/';
5324
  $auth_pattern = '/^User authentication (succeeded|failed): ([^<;]+)/';
5325
 
5326
- foreach ($response['body']->output as $log) {
5327
  if (@preg_match($log_pattern, $log, $log_match)) {
5328
  $log_data = array(
5329
  'event' => 'notice',
@@ -5392,11 +5834,11 @@ class SucuriScanAPI extends SucuriScanOption
5392
  $log_data['file_list_count'] = count($log_data['file_list']);
5393
  }
5394
 
5395
- $response['body']->output_data[] = $log_data;
5396
  }
5397
  }
5398
 
5399
- return $response['body'];
5400
  }
5401
 
5402
  return false;
@@ -5447,10 +5889,10 @@ class SucuriScanAPI extends SucuriScanOption
5447
  {
5448
  $audit_logs = self::getLogs($lines);
5449
 
5450
- if ($audit_logs instanceof stdClass
5451
- && property_exists($audit_logs, 'total_entries')
5452
- && property_exists($audit_logs, 'output_data')
5453
- && !empty($audit_logs->output_data)
5454
  ) {
5455
  // Data structure that will be returned.
5456
  $report = array(
@@ -5475,7 +5917,7 @@ class SucuriScanAPI extends SucuriScanOption
5475
  }
5476
 
5477
  // Collect information for each report chart.
5478
- foreach ($audit_logs->output_data as $event) {
5479
  $report['total_events'] += 1;
5480
 
5481
  // Increment the number of events for this event type.
@@ -5657,30 +6099,35 @@ class SucuriScanAPI extends SucuriScanOption
5657
  *
5658
  * [1] https://sitecheck.sucuri.net/
5659
  *
5660
- * @param string $domain The clean version of the website's domain.
5661
- * @return object Serialized data of the scanning results for the site specified.
 
5662
  */
5663
- public static function getSitecheckResults($domain = '')
5664
  {
5665
  if (!empty($domain)) {
5666
- $url = 'https://sitecheck.sucuri.net/';
 
 
 
 
 
 
 
 
 
 
5667
  $response = self::apiCall(
5668
- $url,
5669
  'GET',
5670
- array(
5671
- 'scan' => $domain,
5672
- 'fromwp' => 2,
5673
- 'clear' => 1,
5674
- 'json' => 1,
5675
- ),
5676
  array(
5677
  'assoc' => true,
 
5678
  )
5679
  );
5680
 
5681
- if ($response) {
5682
- return $response['body'];
5683
- }
5684
  }
5685
 
5686
  return false;
@@ -5720,12 +6167,7 @@ class SucuriScanAPI extends SucuriScanOption
5720
  $data_set['malware_docs'] = $match[2];
5721
  }
5722
 
5723
- $payload = trim($malware_parts[1]);
5724
- $payload = html_entity_decode($payload);
5725
-
5726
- if (@preg_match('/<div id=\'HiddenDiv\'>(.+)<\/div>/', $payload, $match)) {
5727
- $data_set['malware_payload'] = trim($match[1]);
5728
- }
5729
  }
5730
 
5731
  return $data_set;
@@ -5743,9 +6185,9 @@ class SucuriScanAPI extends SucuriScanOption
5743
  public static function getNewSecretKeys()
5744
  {
5745
  $pattern = self::secret_key_pattern();
5746
- $response = self::apiCall('https://api.wordpress.org/secret-key/1.1/salt/', 'GET');
5747
 
5748
- if ($response && @preg_match_all($pattern, $response['body'], $match)) {
5749
  $new_keys = array();
5750
 
5751
  foreach ($match[1] as $i => $value) {
@@ -5768,34 +6210,26 @@ class SucuriScanAPI extends SucuriScanOption
5768
  */
5769
  public static function getOfficialChecksums($version = 0)
5770
  {
5771
- $url = 'https://api.wordpress.org/core/checksums/1.0/';
5772
- $language = 'en_US'; /* WPLANG does not works. */
5773
- $response = self::apiCall($url, 'GET', array(
5774
- 'version' => $version,
5775
- 'locale' => $language,
5776
- ));
 
 
 
5777
 
5778
  if ($response) {
5779
- if ($response['body'] instanceof stdClass) {
5780
- $json_data = $response['body'];
5781
- } else {
5782
- $json_data = @json_decode($response['body']);
5783
- }
5784
-
5785
- if (isset($json_data->checksums)
5786
- && !empty($json_data->checksums)
5787
  ) {
5788
- if (count((array) $json_data->checksums) <= 1
5789
- && property_exists($json_data->checksums, $version)
5790
  ) {
5791
- $checksums = $json_data->checksums->{$version};
5792
  } else {
5793
- $checksums = $json_data->checksums;
5794
- }
5795
-
5796
- // Check whether the list of file is an object.
5797
- if ($checksums instanceof stdClass) {
5798
- return (array) $checksums;
5799
  }
5800
  }
5801
  }
@@ -5828,7 +6262,7 @@ class SucuriScanAPI extends SucuriScanOption
5828
  // Get the plugin's basic information from WordPress transient data.
5829
  $plugins = get_plugins();
5830
  $pattern = '/^http(s)?:\/\/wordpress\.org\/plugins\/(.*)\/$/';
5831
- $wp_market = 'https://wordpress.org/plugins/%s/';
5832
 
5833
  // Loop through each plugin data and complement its information with more attributes.
5834
  foreach ($plugins as $plugin_path => $plugin_data) {
@@ -5859,6 +6293,7 @@ class SucuriScanAPI extends SucuriScanOption
5859
 
5860
  if (isset($plugin_path_parts[0])) {
5861
  $possible_repository = sprintf($wp_market, $plugin_path_parts[0]);
 
5862
  $resp = wp_remote_head($possible_repository);
5863
 
5864
  if (!is_wp_error($resp)
@@ -5917,13 +6352,11 @@ class SucuriScanAPI extends SucuriScanOption
5917
  public static function getRemotePluginData($plugin = '')
5918
  {
5919
  if (!empty($plugin)) {
5920
- $url = sprintf('https://api.wordpress.org/plugins/info/1.0/%s.json', $plugin);
5921
  $response = self::apiCall($url, 'GET');
5922
 
5923
  if ($response) {
5924
- if ($response['body'] instanceof stdClass) {
5925
- return $response['body'];
5926
- }
5927
  }
5928
  }
5929
 
@@ -5950,16 +6383,11 @@ class SucuriScanAPI extends SucuriScanOption
5950
  $version = self::site_version();
5951
  }
5952
 
5953
- $url = sprintf('https://core.svn.wordpress.org/tags/%s/%s', $version, $filepath);
5954
  $response = self::apiCall($url, 'GET');
5955
 
5956
  if ($response) {
5957
- if (isset($response['headers']['content-length'])
5958
- && $response['headers']['content-length'] > 0
5959
- && is_string($response['body'])
5960
- ) {
5961
- return $response['body'];
5962
- }
5963
  }
5964
  }
5965
 
@@ -6021,9 +6449,10 @@ class SucuriScanMail extends SucuriScanOption
6021
  }
6022
 
6023
  // Check whether the email notifications will be sent in HTML or Plain/Text.
6024
- if (self::prettify_mails()) {
6025
  $headers = array( 'content-type: text/html' );
6026
  $data_set['PrettifyType'] = 'pretty';
 
6027
  } else {
6028
  $message = strip_tags($message);
6029
  }
@@ -6259,13 +6688,27 @@ class SucuriScanTemplate extends SucuriScanRequest
6259
  return false;
6260
  }
6261
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6262
  /**
6263
  * Gather and generate the information required globally by all the template files.
6264
  *
6265
- * @param array $params Key-value array with pseudo-variables shared with the template.
6266
- * @return array A complementary list of pseudo-variables for the template files.
 
6267
  */
6268
- private static function sharedParams($params = array())
6269
  {
6270
  $params = is_array($params) ? $params : array();
6271
 
@@ -6277,16 +6720,17 @@ class SucuriScanTemplate extends SucuriScanRequest
6277
  $params['PageNonce'] = wp_create_nonce('sucuriscan_page_nonce');
6278
  $params['PageStyleClass'] = isset($params['PageStyleClass']) ? $params['PageStyleClass'] : 'base';
6279
  $params['CleanDomain'] = self::get_domain();
6280
- $params['AdminEmails'] = '';
6281
 
6282
  // Get a list of admin users for the API key generation.
6283
- if (SucuriScanAPI::getPluginKey() === false) {
 
 
6284
  $admin_users = SucuriScan::get_users_for_api_key();
6285
  $params['AdminEmails'] = self::selectOptions($admin_users);
6286
  }
6287
 
6288
  // Hide the advertisements from the layout.
6289
- if (SucuriScanOption::is_disabled(':ads_visibility')) {
6290
  $params['LayoutType'] = 'onecolumn';
6291
  $params['AdsVisibility'] = 'hidden';
6292
  $params['ReviewNavbarButton'] = 'visible';
@@ -6329,6 +6773,14 @@ class SucuriScanTemplate extends SucuriScanRequest
6329
  $url_path .= '_' . strtolower($page);
6330
  }
6331
 
 
 
 
 
 
 
 
 
6332
  return $url_path;
6333
  }
6334
 
@@ -6367,8 +6819,8 @@ class SucuriScanTemplate extends SucuriScanRequest
6367
  }
6368
 
6369
  foreach ($sub_pages as $sub_page_func => $sub_page_title) {
6370
- if ($sub_page_func == 'sucuriscan_scanner'
6371
- && SucuriScanOption::is_disabled(':sitecheck_scanner')
6372
  ) {
6373
  continue;
6374
  }
@@ -6419,7 +6871,7 @@ class SucuriScanTemplate extends SucuriScanRequest
6419
  {
6420
  $params = is_array($params) ? $params : array();
6421
 
6422
- $params = self::sharedParams($params);
6423
  $params['PageContent'] = $html;
6424
 
6425
  return self::getTemplate('base', $params);
@@ -6497,7 +6949,7 @@ class SucuriScanTemplate extends SucuriScanRequest
6497
  */
6498
  public static function getSection($template = '', $params = array())
6499
  {
6500
- $params = self::sharedParams($params);
6501
 
6502
  return self::getTemplate($template, $params, 'section');
6503
  }
@@ -6538,7 +6990,7 @@ class SucuriScanTemplate extends SucuriScanRequest
6538
 
6539
  $params['Visibility'] = 'sucuriscan-' . $params['Visibility'];
6540
  $params['Identifier'] = 'sucuriscan-' . $template . '-modal';
6541
- $params = self::sharedParams($params);
6542
 
6543
  return self::getTemplate('modalwindow', $params, 'section');
6544
  }
@@ -6623,11 +7075,12 @@ class SucuriScanTemplate extends SucuriScanRequest
6623
  }
6624
 
6625
  $html_links .= sprintf(
6626
- '<li><a href="%s&paged=%d%s" class="%s">%s</a></li>',
6627
  $base_url,
6628
  $j,
6629
  $extra_url,
6630
  $link_class,
 
6631
  $j
6632
  );
6633
  }
@@ -7073,6 +7526,8 @@ class SucuriScanInterface
7073
  $_SERVER['SUCURIREAL_REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
7074
  $_SERVER['REMOTE_ADDR'] = SucuriScan::get_remote_addr();
7075
  }
 
 
7076
  }
7077
 
7078
  /**
@@ -7081,7 +7536,7 @@ class SucuriScanInterface
7081
  *
7082
  * @return void
7083
  */
7084
- public static function enqueue_scripts()
7085
  {
7086
  $asset_version = '';
7087
 
@@ -7107,7 +7562,7 @@ class SucuriScanInterface
7107
  *
7108
  * @return void
7109
  */
7110
- public static function add_interface_menu()
7111
  {
7112
  global $sucuriscan_pages;
7113
 
@@ -7128,7 +7583,7 @@ class SucuriScanInterface
7128
 
7129
  foreach ($sucuriscan_pages as $sub_page_func => $sub_page_title) {
7130
  if ($sub_page_func == 'sucuriscan_scanner'
7131
- && SucuriScanOption::is_disabled(':sitecheck_scanner')
7132
  ) {
7133
  continue;
7134
  }
@@ -7155,7 +7610,7 @@ class SucuriScanInterface
7155
  *
7156
  * @return void
7157
  */
7158
- public static function handle_old_plugins()
7159
  {
7160
  if (class_exists('SucuriScanFileInfo')) {
7161
  $file_info = new SucuriScanFileInfo();
@@ -7175,7 +7630,7 @@ class SucuriScanInterface
7175
  deactivate_plugins($plugin);
7176
  }
7177
 
7178
- $plugin_removed = $file_info->remove_directory_tree($plugin_directory);
7179
  }
7180
  }
7181
  }
@@ -7187,7 +7642,7 @@ class SucuriScanInterface
7187
  *
7188
  * @return void
7189
  */
7190
- public static function create_datastore_folder()
7191
  {
7192
  $directory = SucuriScan::datastore_folder_path();
7193
 
@@ -7228,6 +7683,43 @@ class SucuriScanInterface
7228
  }
7229
  }
7230
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7231
  /**
7232
  * Check whether a user has the permissions to see a page from the plugin.
7233
  *
@@ -7274,7 +7766,7 @@ class SucuriScanInterface
7274
  * @param string $message The message that will be printed in the alert.
7275
  * @return void
7276
  */
7277
- private static function admin_notice($type = 'updated', $message = '')
7278
  {
7279
  $display_notice = true;
7280
 
@@ -7297,6 +7789,20 @@ class SucuriScanInterface
7297
 
7298
  // Display the HTML notice to the current user.
7299
  if ($display_notice === true && !empty($message)) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7300
  echo SucuriScanTemplate::getSection(
7301
  'notification-admin',
7302
  array(
@@ -7316,7 +7822,7 @@ class SucuriScanInterface
7316
  */
7317
  public static function error($error_msg = '')
7318
  {
7319
- self::admin_notice('error', '<b>Sucuri:</b> ' . $error_msg);
7320
  }
7321
 
7322
  /**
@@ -7327,7 +7833,64 @@ class SucuriScanInterface
7327
  */
7328
  public static function info($info_msg = '')
7329
  {
7330
- self::admin_notice('updated', '<b>Sucuri:</b> ' . $info_msg);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7331
  }
7332
 
7333
  /**
@@ -7340,7 +7903,7 @@ class SucuriScanInterface
7340
  public static function setup_notice()
7341
  {
7342
  if (current_user_can('manage_options')
7343
- && SucuriScan::no_notices_here() === false
7344
  && !SucuriScanAPI::getPluginKey()
7345
  && SucuriScanRequest::post(':plugin_api_key') === false
7346
  && SucuriScanRequest::post(':recover_key') === false
@@ -8085,10 +8648,9 @@ function sucuriscan_explain_firewall_settings($settings = array())
8085
  /**
8086
  * Generate the HTML code for the firewall logs panel.
8087
  *
8088
- * @param string $api_key The CloudProxy API key.
8089
- * @return string The parsed-content of the firewall logs panel.
8090
  */
8091
- function sucuriscan_firewall_auditlogs($api_key = '')
8092
  {
8093
  $date = date('Y-m-d');
8094
  $params = array();
@@ -8469,7 +9031,7 @@ class SucuriScanHardening extends SucuriScan
8469
  }
8470
 
8471
  if ($fhandle) {
8472
- $rules_str = implode("\n", $deny_rules) . "\n";
8473
  $written = @fwrite($fhandle, $rules_str);
8474
  @fclose($fhandle);
8475
 
@@ -8576,7 +9138,17 @@ class SucuriScanHardening extends SucuriScan
8576
  $file = str_replace('<', '', $file);
8577
  $file = str_replace('>', '', $file);
8578
 
8579
- return sprintf("<Files %s>\n\x20\x20Allow from all\n</Files>\n", $file);
 
 
 
 
 
 
 
 
 
 
8580
  }
8581
 
8582
  public static function whitelist($file = '', $folder = '')
@@ -8603,7 +9175,7 @@ class SucuriScanHardening extends SucuriScan
8603
  && is_readable($htaccess)
8604
  && is_writable($htaccess)
8605
  ) {
8606
- $content = @file_get_contents($htaccess);
8607
  $rules = self::whitelist_rule($file);
8608
  $content = str_replace($rules, '', $content);
8609
  @file_put_contents($htaccess, $content);
@@ -8613,10 +9185,15 @@ class SucuriScanHardening extends SucuriScan
8613
  public static function get_whitelisted($folder = '')
8614
  {
8615
  $htaccess = self::htaccess($folder);
8616
- $content = @file_get_contents($htaccess);
8617
 
8618
- if (@preg_match_all('/<Files (\S+)>/', $content, $matches)) {
8619
- return $matches[1];
 
 
 
 
 
 
8620
  }
8621
 
8622
  return false;
@@ -8694,6 +9271,7 @@ function sucuriscan_hardening_whitelist()
8694
  'wp-content/uploads',
8695
  );
8696
 
 
8697
  // Add a new file to the hardening whitelist.
8698
  if ($fwhite = SucuriScanRequest::post(':hardening_whitelist')) {
8699
  $folder = SucuriScanRequest::post(':hardening_folder');
@@ -8720,6 +9298,7 @@ function sucuriscan_hardening_whitelist()
8720
 
8721
  SucuriScanInterface::info('Selected files were processed successfully');
8722
  }
 
8723
 
8724
  // Read the access control file and retrieve the whitelisted files.
8725
  $counter = 0;
@@ -8770,6 +9349,7 @@ function sucuriscan_harden_status($title = '', $status = 0, $type = '', $message
8770
  'Hardening.Title' => $title,
8771
  'Hardening.Description' => '',
8772
  'Hardening.Status' => 'unknown',
 
8773
  'Hardening.FieldName' => '',
8774
  'Hardening.FieldValue' => '',
8775
  'Hardening.FieldAttributes' => '',
@@ -8807,6 +9387,10 @@ function sucuriscan_harden_status($title = '', $status = 0, $type = '', $message
8807
  $template_variables['Hardening.UpdateMessage'] = '<p>' . $updatemsg . '</p>';
8808
  }
8809
 
 
 
 
 
8810
  return SucuriScanTemplate::getSnippet('hardening', $template_variables);
8811
  }
8812
 
@@ -8890,6 +9474,20 @@ function sucuriscan_harden_nginx_phpfpm()
8890
  $description .= "\x20\x20deny all;\n";
8891
  $description .= '}</pre>';
8892
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8893
  $description .= '<p class="sucuriscan-hidden">';
8894
 
8895
  return sucuriscan_harden_status(
@@ -9226,8 +9824,6 @@ function sucuriscan_harden_readme()
9226
  */
9227
  function sucuriscan_harden_adminuser()
9228
  {
9229
- global $wpdb;
9230
-
9231
  $upmsg = null;
9232
  $user_query = new WP_User_Query(array(
9233
  'search' => 'admin',
@@ -9462,6 +10058,7 @@ function sucuriscan_ajax()
9462
 
9463
  if (SucuriScanInterface::check_nonce()) {
9464
  sucuriscan_core_files_ajax();
 
9465
  }
9466
 
9467
  wp_die();
@@ -9475,94 +10072,113 @@ function sucuriscan_ajax()
9475
  */
9476
  function sucuriscan_auditlogs()
9477
  {
9478
- // Initialize the values for the pagination.
9479
- $max_per_page = SUCURISCAN_AUDITLOGS_PER_PAGE;
9480
- $page_number = SucuriScanTemplate::pageNumber();
9481
- $logs_limit = $page_number * $max_per_page;
9482
- $audit_logs = SucuriScanAPI::getLogs($logs_limit);
9483
-
9484
- $params = array(
9485
- 'PageTitle' => 'Audit Logs',
9486
- 'AuditLogs.List' => '',
9487
- 'AuditLogs.Count' => 0,
9488
- 'AuditLogs.MaxPerPage' => $max_per_page,
9489
- 'AuditLogs.NoItemsVisibility' => 'visible',
9490
- 'AuditLogs.PaginationVisibility' => 'hidden',
9491
- 'AuditLogs.PaginationLinks' => '',
9492
- 'AuditLogs.EnableAuditReportVisibility' => 'hidden',
9493
- );
9494
 
9495
- if ($audit_logs) {
9496
- $counter_i = 0;
9497
- $total_items = count($audit_logs->output_data);
9498
- $iterator_start = ($page_number - 1) * $max_per_page;
9499
- $iterator_end = $total_items;
9500
 
9501
- if ($audit_logs->total_entries >= $max_per_page
9502
- && SucuriScanOption::is_disabled(':audit_report')
9503
- ) {
9504
- $params['AuditLogs.EnableAuditReportVisibility'] = 'visible';
9505
- }
9506
 
9507
- for ($i = $iterator_start; $i < $total_items; $i++) {
9508
- if ($counter_i > $max_per_page) {
9509
- break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9510
  }
9511
 
9512
- if (isset($audit_logs->output_data[ $i ])) {
9513
- $audit_log = $audit_logs->output_data[ $i ];
9514
-
9515
- $css_class = ( $counter_i % 2 == 0 ) ? '' : 'alternate';
9516
- $snippet_data = array(
9517
- 'AuditLog.CssClass' => $css_class,
9518
- 'AuditLog.Event' => $audit_log['event'],
9519
- 'AuditLog.EventTitle' => ucfirst($audit_log['event']),
9520
- 'AuditLog.Timestamp' => $audit_log['timestamp'],
9521
- 'AuditLog.DateTime' => SucuriScan::datetime($audit_log['timestamp']),
9522
- 'AuditLog.Account' => $audit_log['account'],
9523
- 'AuditLog.Username' => $audit_log['username'],
9524
- 'AuditLog.RemoteAddress' => $audit_log['remote_addr'],
9525
- 'AuditLog.Message' => $audit_log['message'],
9526
- 'AuditLog.Extra' => '',
9527
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9528
 
9529
- // Print every file_list information item in a separate table.
9530
- if ($audit_log['file_list']) {
9531
- $css_scrollable = $audit_log['file_list_count'] > 10 ? 'sucuriscan-list-as-table-scrollable' : '';
9532
- $snippet_data['AuditLog.Extra'] .= '<ul class="sucuriscan-list-as-table ' . $css_scrollable . '">';
9533
- foreach ($audit_log['file_list'] as $log_extra) {
9534
- $snippet_data['AuditLog.Extra'] .= '<li>' . SucuriScan::escape($log_extra) . '</li>';
9535
  }
9536
- $snippet_data['AuditLog.Extra'] .= '</ul>';
9537
- }
9538
 
9539
- $params['AuditLogs.List'] .= SucuriScanTemplate::getSnippet('integrity-auditlogs', $snippet_data);
9540
- $counter_i += 1;
 
9541
  }
9542
- }
9543
 
9544
- $params['AuditLogs.Count'] = $counter_i;
9545
- $params['AuditLogs.NoItemsVisibility'] = 'hidden';
9546
 
9547
- if ($total_items > 1) {
9548
- $max_pages = ceil($audit_logs->total_entries / $max_per_page);
9549
 
9550
- if ($max_pages > SUCURISCAN_MAX_PAGINATION_BUTTONS) {
9551
- $max_pages = SUCURISCAN_MAX_PAGINATION_BUTTONS;
9552
- }
9553
 
9554
- if ($max_pages > 1) {
9555
- $params['AuditLogs.PaginationVisibility'] = 'visible';
9556
- $params['AuditLogs.PaginationLinks'] = SucuriScanTemplate::pagination(
9557
- '%%SUCURI.URL.Home%%',
9558
- $max_per_page * $max_pages,
9559
- $max_per_page
9560
- );
9561
  }
9562
  }
9563
- }
9564
 
9565
- return SucuriScanTemplate::getSection('integrity-auditlogs', $params);
 
 
 
9566
  }
9567
 
9568
  /**
@@ -9708,6 +10324,7 @@ function sucuriscan_core_files_data($send_email = false)
9708
  {
9709
  $affected_files = 0;
9710
  $site_version = SucuriScan::site_version();
 
9711
 
9712
  $params = array(
9713
  'CoreFiles.List' => '',
@@ -9717,14 +10334,21 @@ function sucuriscan_core_files_data($send_email = false)
9717
  'CoreFiles.GoodVisibility' => 'visible',
9718
  'CoreFiles.FailureVisibility' => 'hidden',
9719
  'CoreFiles.NotFixableVisibility' => 'hidden',
 
9720
  );
9721
 
9722
- if ($site_version && SucuriScanOption::is_enabled(':scan_checksums')) {
 
 
 
 
 
9723
  // Check if there are added, removed, or modified files.
9724
  $latest_hashes = sucuriscan_check_core_integrity($site_version);
 
9725
  $params['CoreFiles.RemoteChecksumsURL'] =
9726
  'https://api.wordpress.org/core/checksums/1.0/'
9727
- . '?version=' . $site_version . '&locale=en_US';
9728
 
9729
  if ($latest_hashes) {
9730
  $cache = new SucuriScanCache('integrity');
@@ -9823,6 +10447,7 @@ function sucuriscan_integrity_form_submissions()
9823
  SucuriScanEvent::notify_event('plugin_change', 'Filesystem scan forced at: ' . date('r'));
9824
  SucuriScanEvent::filesystem_scan(true);
9825
  sucuriscan_core_files_data(true);
 
9826
  }
9827
 
9828
  // Restore, Remove, Mark as fixed the core files.
@@ -9864,9 +10489,15 @@ function sucuriscan_integrity_form_submissions()
9864
  case 'restore':
9865
  $file_content = SucuriScanAPI::getOriginalCoreFile($file_path);
9866
  if ($file_content) {
9867
- $restored = @file_put_contents($full_path, $file_content);
9868
- $files_processed += ($restored ? 1 : 0);
9869
- $files_affected[] = $full_path;
 
 
 
 
 
 
9870
  }
9871
  break;
9872
  case 'fixed':
@@ -9943,8 +10574,6 @@ function sucuriscan_integrity_form_submissions()
9943
  */
9944
  function sucuriscan_get_integrity_tree($dir = './', $recursive = false)
9945
  {
9946
- $abs_path = rtrim(ABSPATH, '/');
9947
-
9948
  $file_info = new SucuriScanFileInfo();
9949
  $file_info->ignore_files = false;
9950
  $file_info->ignore_directories = false;
@@ -10139,12 +10768,11 @@ function sucuriscan_posthack_page()
10139
  $process_form = sucuriscan_posthack_process_form();
10140
 
10141
  // Page pseudo-variables initialization.
10142
- $params = array(
10143
- 'PageTitle' => 'Post-Hack',
10144
- 'UpdateSecretKeys' => sucuriscan_update_secret_keys($process_form),
10145
- 'ResetPassword' => sucuriscan_posthack_users($process_form),
10146
- 'ResetPlugins' => sucuriscan_posthack_plugins($process_form),
10147
- );
10148
 
10149
  echo SucuriScanTemplate::getTemplate('posthack', $params);
10150
  }
@@ -10160,6 +10788,7 @@ function sucuriscan_posthack_ajax()
10160
 
10161
  if (SucuriScanInterface::check_nonce()) {
10162
  sucuriscan_posthack_plugins_ajax();
 
10163
  }
10164
 
10165
  wp_die();
@@ -10437,6 +11066,7 @@ function sucuriscan_posthack_plugins_ajax()
10437
  'ResetPlugin.CssClass' => $css_class,
10438
  'ResetPlugin.Disabled' => $input_disabled,
10439
  'ResetPlugin.PluginPath' => $plugin_path,
 
10440
  'ResetPlugin.Plugin' => SucuriScan::excerpt($plugin_data['Name'], 35),
10441
  'ResetPlugin.Version' => $plugin_data['Version'],
10442
  'ResetPlugin.Type' => $plugin_data['PluginType'],
@@ -10454,49 +11084,164 @@ function sucuriscan_posthack_plugins_ajax()
10454
  }
10455
 
10456
  /**
10457
- * Process the request that will start the execution of the plugin
10458
- * reinstallation, it will check if the plugins submitted are (in fact)
10459
- * installed in the system, then check if they are free download from the
10460
- * WordPress market place, and finally download and install them.
10461
  *
10462
- * @param boolean $process_form Whether a form was submitted or not.
10463
  * @return void
10464
  */
10465
- function sucuriscan_posthack_reinstall_plugins($process_form = false)
10466
  {
10467
- if ($process_form && isset($_POST['sucuriscan_reset_plugins'])) {
10468
- include_once(ABSPATH . 'wp-admin/includes/class-wp-upgrader.php');
10469
- include_once(ABSPATH . 'wp-admin/includes/plugin-install.php'); // For plugins_api.
10470
-
10471
- if ($plugin_list = SucuriScanRequest::post('plugin_path', '_array')) {
10472
- // Create an instance of the FileInfo interface.
10473
- $file_info = new SucuriScanFileInfo();
10474
- $file_info->ignore_files = false;
10475
- $file_info->ignore_directories = false;
10476
- $file_info->skip_directories = false;
10477
 
10478
- // Get (possible) cached information from the installed plugins.
10479
- $all_plugins = SucuriScanAPI::getPlugins();
10480
 
10481
- // Loop through all the installed plugins.
10482
- foreach ($_POST['plugin_path'] as $plugin_path) {
10483
- if (array_key_exists($plugin_path, $all_plugins)) {
10484
- $plugin_data = $all_plugins[ $plugin_path ];
 
 
 
 
 
 
 
 
 
 
10485
 
10486
- // Check if the plugin can be downloaded from the free market.
10487
- if ($plugin_data['IsFreePlugin'] === true) {
10488
- $plugin_info = SucuriScanAPI::getRemotePluginData($plugin_data['RepositoryName']);
10489
 
10490
- if ($plugin_info) {
10491
- // First, remove all files/sub-folders from the plugin's directory.
10492
- if (substr_count($plugin_path, '/') >= 1) {
10493
- $plugin_directory = dirname(WP_PLUGIN_DIR . '/' . $plugin_path);
10494
- $file_info->remove_directory_tree($plugin_directory);
10495
- }
10496
 
10497
- // Install a fresh copy of the plugin's files.
10498
- $upgrader_skin = new Plugin_Installer_Skin();
10499
- $upgrader = new Plugin_Upgrader($upgrader_skin);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10500
  $upgrader->install($plugin_info->download_link);
10501
  SucuriScanEvent::report_notice_event('Plugin re-installed: ' . $plugin_path);
10502
  } else {
@@ -10511,6 +11256,10 @@ function sucuriscan_posthack_reinstall_plugins($process_form = false)
10511
  }
10512
  }
10513
 
 
 
 
 
10514
  /**
10515
  * Generate and print the HTML code for the Last Logins page.
10516
  *
@@ -10528,7 +11277,7 @@ function sucuriscan_lastlogins_page()
10528
  ) {
10529
  $file_path = sucuriscan_lastlogins_datastore_filepath();
10530
 
10531
- if (unlink($file_path)) {
10532
  sucuriscan_lastlogins_datastore_exists();
10533
  SucuriScanInterface::info('Last-Logins logs were reset successfully.');
10534
  } else {
@@ -10543,6 +11292,7 @@ function sucuriscan_lastlogins_page()
10543
  'LastLogins.AllUsers' => sucuriscan_lastlogins_all(),
10544
  'LoggedInUsers' => sucuriscan_loggedin_users_panel(),
10545
  'FailedLogins' => sucuriscan_failed_logins_panel(),
 
10546
  );
10547
 
10548
  echo SucuriScanTemplate::getTemplate('lastlogins', $params);
@@ -11182,6 +11932,15 @@ function sucuriscan_failed_logins_panel()
11182
  'FailedLogins.PaginationVisibility' => 'hidden',
11183
  );
11184
 
 
 
 
 
 
 
 
 
 
11185
  // Define variables for the pagination.
11186
  $page_number = SucuriScanTemplate::pageNumber();
11187
  $max_per_page = SUCURISCAN_MAX_PAGINATION_BUTTONS;
@@ -11190,17 +11949,8 @@ function sucuriscan_failed_logins_panel()
11190
 
11191
  $max_failed_logins = SucuriScanOption::get_option(':maximum_failed_logins');
11192
  $notify_bruteforce_attack = SucuriScanOption::get_option(':notify_bruteforce_attack');
11193
- $failed_logins = sucuriscan_get_failed_logins();
11194
- $old_failed_logins = sucuriscan_get_failed_logins(true);
11195
-
11196
- // Merge the new and old failed logins.
11197
- if (is_array($old_failed_logins) && !empty($old_failed_logins)) {
11198
- if (is_array($failed_logins) && !empty($failed_logins)) {
11199
- $failed_logins = array_merge($failed_logins, $old_failed_logins);
11200
- } else {
11201
- $failed_logins = $old_failed_logins;
11202
- }
11203
- }
11204
 
11205
  if ($failed_logins) {
11206
  $counter = 0;
@@ -11212,7 +11962,7 @@ function sucuriscan_failed_logins_panel()
11212
  $wrong_user_password = 'hidden';
11213
  $wrong_user_password_color = 'default';
11214
 
11215
- if (sucuriscan_collect_wrong_passwords() === true) {
11216
  if (isset($login_data['user_password']) && !empty($login_data['user_password'])) {
11217
  $wrong_user_password = $login_data['user_password'];
11218
  $wrong_user_password_color = 'none';
@@ -11260,7 +12010,7 @@ function sucuriscan_failed_logins_panel()
11260
  $template_variables['FailedLogins.WarningVisibility'] = 'hidden';
11261
  }
11262
 
11263
- if (sucuriscan_collect_wrong_passwords() !== true) {
11264
  $template_variables['FailedLogins.CollectPasswordsVisibility'] = 'hidden';
11265
  }
11266
 
@@ -11315,9 +12065,38 @@ function sucuriscan_failed_logins_datastore_path($get_old_logs = false, $reset =
11315
  */
11316
  function sucuriscan_failed_logins_default_content()
11317
  {
11318
- $default_content = "<?php exit(0); ?>\n";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11319
 
11320
- return $default_content;
 
 
 
 
 
 
 
 
 
 
 
 
 
11321
  }
11322
 
11323
  /**
@@ -11334,8 +12113,6 @@ function sucuriscan_failed_logins_default_content()
11334
  function sucuriscan_get_failed_logins($get_old_logs = false)
11335
  {
11336
  $datastore_path = sucuriscan_failed_logins_datastore_path($get_old_logs);
11337
- $default_content = sucuriscan_failed_logins_default_content();
11338
- $default_content_n = substr_count($default_content, "\n");
11339
 
11340
  if ($datastore_path) {
11341
  $lines = SucuriScanFileInfo::file_lines($datastore_path);
@@ -11388,7 +12165,6 @@ function sucuriscan_get_failed_logins($get_old_logs = false)
11388
  return false;
11389
  }
11390
 
11391
-
11392
  /**
11393
  * Add a new entry in the datastore file where the failed logins are being kept,
11394
  * this entry will contain the username, timestamp of the login attempt, remote
@@ -11535,6 +12311,155 @@ function sucuriscan_reset_failed_logins()
11535
  return (bool) sucuriscan_failed_logins_datastore_path(false, true);
11536
  }
11537
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11538
  /**
11539
  * Process the requests sent by the form submissions originated in the settings
11540
  * page, all forms must have a nonce field that will be checked against the one
@@ -11546,9 +12471,7 @@ function sucuriscan_reset_failed_logins()
11546
  function sucuriscan_settings_form_submissions($page_nonce = null)
11547
  {
11548
  global $sucuriscan_schedule_allowed,
11549
- $sucuriscan_interface_allowed,
11550
- $sucuriscan_notify_options,
11551
- $sucuriscan_email_subjects;
11552
 
11553
  // Use this conditional to avoid double checking.
11554
  if (is_null($page_nonce)) {
@@ -11582,28 +12505,6 @@ function sucuriscan_settings_form_submissions($page_nonce = null)
11582
  SucuriScanInterface::info($message);
11583
  }
11584
 
11585
- // Enable or disable the filesystem scanner for file integrity.
11586
- if ($scan_checksums = SucuriScanRequest::post(':scan_checksums', '(en|dis)able')) {
11587
- $action_d = $scan_checksums . 'd';
11588
- $message = 'File system scanner for file integrity was <code>' . $action_d . '</code>';
11589
-
11590
- SucuriScanOption::update_option(':scan_checksums', $action_d);
11591
- SucuriScanEvent::report_auto_event($message);
11592
- SucuriScanEvent::notify_event('plugin_change', $message);
11593
- SucuriScanInterface::info($message);
11594
- }
11595
-
11596
- // Enable or disable the filesystem scanner for error logs.
11597
- if ($ignore_scanning = SucuriScanRequest::post(':ignore_scanning', '(en|dis)able')) {
11598
- $action_d = $ignore_scanning . 'd';
11599
- $message = 'File system scanner rules to ignore directories was <code>' . $action_d . '</code>';
11600
-
11601
- SucuriScanOption::update_option(':ignore_scanning', $action_d);
11602
- SucuriScanEvent::report_auto_event($message);
11603
- SucuriScanEvent::notify_event('plugin_change', $message);
11604
- SucuriScanInterface::info($message);
11605
- }
11606
-
11607
  // Enable or disable the filesystem scanner for error logs.
11608
  if ($scan_errorlogs = SucuriScanRequest::post(':scan_errorlogs', '(en|dis)able')) {
11609
  $action_d = $scan_errorlogs . 'd';
@@ -11615,28 +12516,6 @@ function sucuriscan_settings_form_submissions($page_nonce = null)
11615
  SucuriScanInterface::info($message);
11616
  }
11617
 
11618
- // Enable or disable the error logs parsing.
11619
- if ($parse_errorlogs = SucuriScanRequest::post(':parse_errorlogs', '(en|dis)able')) {
11620
- $action_d = $parse_errorlogs . 'd';
11621
- $message = 'Analysis of main error log file was <code>' . $action_d . '</code>';
11622
-
11623
- SucuriScanOption::update_option(':parse_errorlogs', $action_d);
11624
- SucuriScanEvent::report_auto_event($message);
11625
- SucuriScanEvent::notify_event('plugin_change', $message);
11626
- SucuriScanInterface::info($message);
11627
- }
11628
-
11629
- // Enable or disable the SiteCheck scanner and the malware scan page.
11630
- if ($sitecheck_scanner = SucuriScanRequest::post(':sitecheck_scanner', '(en|dis)able')) {
11631
- $action_d = $sitecheck_scanner . 'd';
11632
- $message = 'SiteCheck malware and blacklist scanner was <code>' . $action_d . '</code>';
11633
-
11634
- SucuriScanOption::update_option(':sitecheck_scanner', $action_d);
11635
- SucuriScanEvent::report_auto_event($message);
11636
- SucuriScanEvent::notify_event('plugin_change', $message);
11637
- SucuriScanInterface::info($message);
11638
- }
11639
-
11640
  // Modify the schedule of the filesystem scanner.
11641
  if ($frequency = SucuriScanRequest::post(':scan_frequency')) {
11642
  if (array_key_exists($frequency, $sucuriscan_schedule_allowed)) {
@@ -11670,22 +12549,8 @@ function sucuriscan_settings_form_submissions($page_nonce = null)
11670
  }
11671
  }
11672
 
11673
- // Update the limit of error log lines to parse.
11674
- if ($errorlogs_limit = SucuriScanRequest::post(':errorlogs_limit', '[0-9]+')) {
11675
- if ($errorlogs_limit > 1000) {
11676
- SucuriScanInterface::error('Analyze more than 1,000 lines will take too much time.');
11677
- } else {
11678
- SucuriScanOption::update_option(':errorlogs_limit', $errorlogs_limit);
11679
- SucuriScanInterface::info('Analyze last <code>' . $errorlogs_limit . '</code> entries encountered in the error logs.');
11680
-
11681
- if ($errorlogs_limit == 0) {
11682
- SucuriScanOption::update_option(':parse_errorlogs', 'disabled');
11683
- }
11684
- }
11685
- }
11686
-
11687
  // Reset the plugin security logs.
11688
- $allowed_log_files = '(integrity|lastlogins|failedlogins|sitecheck)';
11689
  if ($reset_logfile = SucuriScanRequest::post(':reset_logfile', $allowed_log_files)) {
11690
  $files_to_delete = array(
11691
  'sucuri-' . $reset_logfile . '.php',
@@ -11723,76 +12588,32 @@ function sucuriscan_settings_form_submissions($page_nonce = null)
11723
  }
11724
  }
11725
 
11726
- // Ignore a new directory path for the file system scans.
11727
- if ($action = SucuriScanRequest::post(':ignorescanning_action', '(ignore|unignore)')) {
11728
- $ignore_directories = SucuriScanRequest::post(':ignorescanning_dirs', '_array');
11729
- $ignore_file = SucuriScanRequest::post(':ignorescanning_file');
 
 
 
 
 
11730
 
11731
- if ($action == 'ignore') {
11732
- // Target a single file path to be ignored.
11733
- if ($ignore_file !== false) {
11734
- $ignore_directories = array( $ignore_file );
 
 
 
 
 
11735
  }
 
 
11736
 
11737
- // Target a list of directories to be ignored.
11738
- if (!empty($ignore_directories)) {
11739
- $were_ignored = array();
11740
-
11741
- foreach ($ignore_directories as $resource_path) {
11742
- if (file_exists($resource_path)
11743
- && SucuriScanFSScanner::ignore_directory($resource_path)
11744
- ) {
11745
- $were_ignored[] = $resource_path;
11746
- }
11747
- }
11748
-
11749
- if (!empty($were_ignored)) {
11750
- SucuriScanInterface::info('Items selected will be ignored in future scans.');
11751
- SucuriScanEvent::report_warning_event(sprintf(
11752
- 'Resources will not be scanned: (multiple entries): %s',
11753
- @implode(',', $ignore_directories)
11754
- ));
11755
- }
11756
- }
11757
- } elseif ($action == 'unignore') {
11758
- foreach ($ignore_directories as $directory_path) {
11759
- SucuriScanFSScanner::unignore_directory($directory_path);
11760
- }
11761
-
11762
- SucuriScanInterface::info('Items selected will not be ignored anymore.');
11763
- SucuriScanEvent::report_notice_event(sprintf(
11764
- 'Resources will be scanned: (multiple entries): %s',
11765
- @implode(',', $ignore_directories)
11766
- ));
11767
- }
11768
- }
11769
-
11770
- // Trust and IP address to ignore notifications for a subnet.
11771
- if ($trust_ip = SucuriScanRequest::post(':trust_ip')) {
11772
- if (SucuriScan::is_valid_ip($trust_ip)
11773
- || SucuriScan::is_valid_cidr($trust_ip)
11774
- ) {
11775
- $cache = new SucuriScanCache('trustip');
11776
- $ip_info = SucuriScan::get_ip_info($trust_ip);
11777
- $ip_info['added_at'] = SucuriScan::local_time();
11778
- $cache_key = md5($ip_info['remote_addr']);
11779
-
11780
- if ($cache->exists($cache_key)) {
11781
- SucuriScanInterface::error('The IP address specified was already trusted.');
11782
- } elseif ($cache->add($cache_key, $ip_info)) {
11783
- $message = 'Changes from <code>' . $trust_ip . '</code> will be ignored';
11784
-
11785
- SucuriScanEvent::report_warning_event($message);
11786
- SucuriScanInterface::info($message);
11787
- } else {
11788
- SucuriScanInterface::error('The new entry was not saved in the datastore file.');
11789
- }
11790
- }
11791
- }
11792
-
11793
- // Trust and IP address to ignore notifications for a subnet.
11794
- if ($del_trust_ip = SucuriScanRequest::post(':del_trust_ip', '_array')) {
11795
- $cache = new SucuriScanCache('trustip');
11796
 
11797
  foreach ($del_trust_ip as $cache_key) {
11798
  $cache->delete($cache_key);
@@ -11884,8 +12705,6 @@ function sucuriscan_settings_general($nonce)
11884
  $params['SettingsSection.AuditLogStats'] = sucuriscan_settings_general_auditlogstats($nonce);
11885
  $params['SettingsSection.Datetime'] = sucuriscan_settings_general_datetime($nonce);
11886
 
11887
- sucuriscan_settings_general_adsvisibility($nonce);
11888
-
11889
  return SucuriScanTemplate::getSection('settings-general', $params);
11890
  }
11891
 
@@ -11916,6 +12735,7 @@ function sucuriscan_settings_general_resetoptions($nonce)
11916
  @unlink(SucuriScan::datastore_folder_path('sucuri-oldfailedlogins.php'));
11917
  @unlink(SucuriScan::datastore_folder_path('sucuri-plugindata.php'));
11918
  @unlink(SucuriScan::datastore_folder_path('sucuri-sitecheck.php'));
 
11919
  @unlink(SucuriScan::datastore_folder_path('sucuri-trustip.php'));
11920
  @rmdir(SucuriScan::datastore_folder_path());
11921
 
@@ -11968,20 +12788,24 @@ function sucuriscan_settings_general_apikey($nonce)
11968
 
11969
  // Recover API key through the email registered previously.
11970
  if (SucuriScanRequest::post(':recover_key') !== false) {
 
11971
  SucuriScanAPI::recoverKey();
11972
  SucuriScanEvent::report_info_event('Recovery of the Sucuri API key was requested.');
11973
- $api_recovery_modal = SucuriScanTemplate::getModal(
11974
- 'settings-apirecovery',
11975
- array(
11976
- 'Title' => 'Plugin API Key Recovery',
11977
- 'CssClass' => 'sucuriscan-apirecovery',
11978
- )
11979
- );
11980
  }
11981
  }
11982
 
11983
  $api_key = SucuriScanAPI::getPluginKey();
11984
 
 
 
 
 
 
 
 
 
 
 
11985
  // Check whether the domain name is valid or not.
11986
  if (!$api_key) {
11987
  $clean_domain = SucuriScan::get_top_level_domain();
@@ -12336,29 +13160,12 @@ function sucuriscan_settings_general_datetime($nonce)
12336
  return SucuriScanTemplate::getSection('settings-general-datetime', $params);
12337
  }
12338
 
12339
- function sucuriscan_settings_general_adsvisibility($nonce)
12340
- {
12341
- // Update the advertisement visibility settings.
12342
- if ($nonce) {
12343
- $ads_visibility = SucuriScanRequest::post(':ads_visibility');
12344
-
12345
- if ($ads_visibility === 'disable') {
12346
- $option_value = $ads_visibility . 'd';
12347
- $message = sprintf('Plugin advertisement set to <code>%s</code>', $option_value);
12348
-
12349
- SucuriScanOption::update_option(':ads_visibility', $option_value);
12350
- SucuriScanEvent::report_info_event($message);
12351
- SucuriScanInterface::info($message);
12352
- }
12353
- }
12354
- }
12355
-
12356
  /**
12357
  * Read and parse the content of the scanner settings template.
12358
  *
12359
  * @return string Parsed HTML code for the scanner settings panel.
12360
  */
12361
- function sucuriscan_settings_scanner()
12362
  {
12363
  global $sucuriscan_schedule_allowed,
12364
  $sucuriscan_interface_allowed;
@@ -12367,20 +13174,14 @@ function sucuriscan_settings_scanner()
12367
  $fs_scanner = SucuriScanOption::get_option(':fs_scanner');
12368
  $scan_freq = SucuriScanOption::get_option(':scan_frequency');
12369
  $scan_interface = SucuriScanOption::get_option(':scan_interface');
12370
- $scan_checksums = SucuriScanOption::get_option(':scan_checksums');
12371
  $scan_errorlogs = SucuriScanOption::get_option(':scan_errorlogs');
12372
- $parse_errorlogs = SucuriScanOption::get_option(':parse_errorlogs');
12373
- $errorlogs_limit = SucuriScanOption::get_option(':errorlogs_limit');
12374
- $ignore_scanning = SucuriScanOption::get_option(':ignore_scanning');
12375
- $sitecheck_scanner = SucuriScanOption::get_option(':sitecheck_scanner');
12376
- $sitecheck_counter = SucuriScanOption::get_option(':sitecheck_counter');
12377
  $runtime_scan_human = SucuriScanFSScanner::get_filesystem_runtime(true);
12378
 
12379
  // Get the file path of the security logs.
12380
- $integrity_log_path = SucuriScan::datastore_folder_path('sucuri-integrity.php');
12381
- $lastlogins_log_path = SucuriScan::datastore_folder_path('sucuri-lastlogins.php');
12382
- $failedlogins_log_path = SucuriScan::datastore_folder_path('sucuri-failedlogins.php');
12383
- $sitecheck_log_path = SucuriScan::datastore_folder_path('sucuri-sitecheck.php');
12384
 
12385
  // Generate the HTML code for the option list in the form select fields.
12386
  $scan_freq_options = SucuriScanTemplate::selectOptions($sucuriscan_schedule_allowed, $scan_freq);
@@ -12392,31 +13193,11 @@ function sucuriscan_settings_scanner()
12392
  'FsScannerSwitchText' => 'Disable',
12393
  'FsScannerSwitchValue' => 'disable',
12394
  'FsScannerSwitchCssClass' => 'button-danger',
12395
- /* Scan files checksum. */
12396
- 'ScanChecksumsStatus' => 'Enabled',
12397
- 'ScanChecksumsSwitchText' => 'Disable',
12398
- 'ScanChecksumsSwitchValue' => 'disable',
12399
- 'ScanChecksumsSwitchCssClass' => 'button-danger',
12400
- /* Ignore scanning. */
12401
- 'IgnoreScanningStatus' => 'Enabled',
12402
- 'IgnoreScanningSwitchText' => 'Disable',
12403
- 'IgnoreScanningSwitchValue' => 'disable',
12404
- 'IgnoreScanningSwitchCssClass' => 'button-danger',
12405
  /* Scan error logs. */
12406
  'ScanErrorlogsStatus' => 'Enabled',
12407
  'ScanErrorlogsSwitchText' => 'Disable',
12408
  'ScanErrorlogsSwitchValue' => 'disable',
12409
  'ScanErrorlogsSwitchCssClass' => 'button-danger',
12410
- /* Parse error logs. */
12411
- 'ParseErrorLogsStatus' => 'Enabled',
12412
- 'ParseErrorLogsSwitchText' => 'Disable',
12413
- 'ParseErrorLogsSwitchValue' => 'disable',
12414
- 'ParseErrorLogsSwitchCssClass' => 'button-danger',
12415
- /* SiteCheck scanner. */
12416
- 'SiteCheckScannerStatus' => 'Enabled',
12417
- 'SiteCheckScannerSwitchText' => 'Disable',
12418
- 'SiteCheckScannerSwitchValue' => 'disable',
12419
- 'SiteCheckScannerSwitchCssClass' => 'button-danger',
12420
  /* Filsystem scanning frequency. */
12421
  'ScanningFrequency' => 'Undefined',
12422
  'ScanningFrequencyOptions' => $scan_freq_options,
@@ -12424,12 +13205,9 @@ function sucuriscan_settings_scanner()
12424
  'ScanningInterfaceOptions' => $scan_interface_options,
12425
  /* Filesystem scanning runtime. */
12426
  'ScanningRuntimeHuman' => $runtime_scan_human,
12427
- 'SiteCheckCounter' => $sitecheck_counter,
12428
- 'ErrorLogsLimit' => $errorlogs_limit,
12429
  'IntegrityLogLife' => '0B',
12430
  'LastLoginLogLife' => '0B',
12431
  'FailedLoginLogLife' => '0B',
12432
- 'SiteCheckLogLife' => '0B',
12433
  );
12434
 
12435
  if ($fs_scanner == 'disabled') {
@@ -12439,20 +13217,6 @@ function sucuriscan_settings_scanner()
12439
  $params['FsScannerSwitchCssClass'] = 'button-success';
12440
  }
12441
 
12442
- if ($scan_checksums == 'disabled') {
12443
- $params['ScanChecksumsStatus'] = 'Disabled';
12444
- $params['ScanChecksumsSwitchText'] = 'Enable';
12445
- $params['ScanChecksumsSwitchValue'] = 'enable';
12446
- $params['ScanChecksumsSwitchCssClass'] = 'button-success';
12447
- }
12448
-
12449
- if ($ignore_scanning == 'disabled') {
12450
- $params['IgnoreScanningStatus'] = 'Disabled';
12451
- $params['IgnoreScanningSwitchText'] = 'Enable';
12452
- $params['IgnoreScanningSwitchValue'] = 'enable';
12453
- $params['IgnoreScanningSwitchCssClass'] = 'button-success';
12454
- }
12455
-
12456
  if ($scan_errorlogs == 'disabled') {
12457
  $params['ScanErrorlogsStatus'] = 'Disabled';
12458
  $params['ScanErrorlogsSwitchText'] = 'Enable';
@@ -12460,20 +13224,6 @@ function sucuriscan_settings_scanner()
12460
  $params['ScanErrorlogsSwitchCssClass'] = 'button-success';
12461
  }
12462
 
12463
- if ($parse_errorlogs == 'disabled') {
12464
- $params['ParseErrorLogsStatus'] = 'Disabled';
12465
- $params['ParseErrorLogsSwitchText'] = 'Enable';
12466
- $params['ParseErrorLogsSwitchValue'] = 'enable';
12467
- $params['ParseErrorLogsSwitchCssClass'] = 'button-success';
12468
- }
12469
-
12470
- if ($sitecheck_scanner == 'disabled') {
12471
- $params['SiteCheckScannerStatus'] = 'Disabled';
12472
- $params['SiteCheckScannerSwitchText'] = 'Enable';
12473
- $params['SiteCheckScannerSwitchValue'] = 'enable';
12474
- $params['SiteCheckScannerSwitchCssClass'] = 'button-success';
12475
- }
12476
-
12477
  if (array_key_exists($scan_freq, $sucuriscan_schedule_allowed)) {
12478
  $params['ScanningFrequency'] = $sucuriscan_schedule_allowed[ $scan_freq ];
12479
  }
@@ -12482,75 +13232,383 @@ function sucuriscan_settings_scanner()
12482
  $params['IntegrityLogLife'] = SucuriScan::human_filesize(@filesize($integrity_log_path));
12483
  $params['LastLoginLogLife'] = SucuriScan::human_filesize(@filesize($lastlogins_log_path));
12484
  $params['FailedLoginLogLife'] = SucuriScan::human_filesize(@filesize($failedlogins_log_path));
12485
- $params['SiteCheckLogLife'] = SucuriScan::human_filesize(@filesize($sitecheck_log_path));
 
 
 
 
 
 
12486
 
12487
  return SucuriScanTemplate::getSection('settings-scanner', $params);
12488
  }
12489
 
12490
- function sucuriscan_settings_ignorescanning()
12491
  {
12492
- $params = array(
12493
- 'IgnoreScanning.ResourceList' => '',
12494
- 'IgnoreScanning.DisabledVisibility' => 'visible',
12495
- 'IgnoreScanning.NoItemsVisibility' => 'visible',
12496
- );
 
 
 
 
 
 
 
12497
 
12498
- $ignore_scanning = SucuriScanFSScanner::will_ignore_scanning();
 
 
 
 
 
12499
 
12500
- // Allow disable of this option temporarily.
12501
- if (SucuriScanRequest::get('no_scan') == 1) {
12502
- $ignore_scanning = false;
 
 
 
12503
  }
12504
 
12505
- // Scan the project and get the ignored paths.
12506
- if ($ignore_scanning === true) {
12507
- $counter = 0;
12508
- $params['IgnoreScanning.DisabledVisibility'] = 'hidden';
12509
- $dir_list_list = SucuriScanFSScanner::get_ignored_directories_live();
12510
-
12511
- foreach ($dir_list_list as $group => $dir_list) {
12512
- foreach ($dir_list as $dir_data) {
12513
- $valid_entry = false;
12514
- $snippet_data = array(
12515
- 'IgnoreScanning.CssClass' => '',
12516
- 'IgnoreScanning.Directory' => '',
12517
- 'IgnoreScanning.DirectoryPath' => '',
12518
- 'IgnoreScanning.IgnoredAt' => '',
12519
- 'IgnoreScanning.IgnoredAtText' => 'ok',
12520
- 'IgnoreScanning.IgnoredCssClass' => 'success',
12521
- );
12522
 
12523
- if ($group == 'is_ignored') {
12524
- $valid_entry = true;
12525
- $snippet_data['IgnoreScanning.Directory'] = urlencode($dir_data['directory_path']);
12526
- $snippet_data['IgnoreScanning.DirectoryPath'] = $dir_data['directory_path'];
12527
- $snippet_data['IgnoreScanning.IgnoredAt'] = SucuriScan::datetime($dir_data['ignored_at']);
12528
- $snippet_data['IgnoreScanning.IgnoredAtText'] = 'ignored';
12529
- $snippet_data['IgnoreScanning.IgnoredCssClass'] = 'warning';
12530
- } elseif ($group == 'is_not_ignored') {
12531
- $valid_entry = true;
12532
- $snippet_data['IgnoreScanning.Directory'] = urlencode($dir_data);
12533
- $snippet_data['IgnoreScanning.DirectoryPath'] = $dir_data;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12534
  }
 
 
 
 
 
12535
 
12536
- if ($valid_entry) {
12537
- $css_class = ( $counter % 2 == 0 ) ? '' : 'alternate';
12538
- $snippet_data['IgnoreScanning.CssClass'] = $css_class;
12539
- $params['IgnoreScanning.ResourceList'] .= SucuriScanTemplate::getSnippet(
12540
- 'settings-ignorescanning',
12541
- $snippet_data
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12542
  );
12543
- $counter++;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12544
  }
12545
  }
 
 
12546
  }
12547
 
12548
- if ($counter > 0) {
12549
- $params['IgnoreScanning.NoItemsVisibility'] = 'hidden';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12550
  }
12551
  }
12552
 
12553
- return SucuriScanTemplate::getSection('settings-ignorescanning', $params);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12554
  }
12555
 
12556
  /**
@@ -12819,10 +13877,6 @@ function sucuriscan_settings_alert_events($nonce)
12819
  if (SucuriScanRequest::post(':save_alert_events') !== false) {
12820
  $ucounter = 0;
12821
 
12822
- if (SucuriScanRequest::post(':notify_scan_checksums') == 1) {
12823
- $_POST['sucuriscan_prettify_mails'] = '1';
12824
- }
12825
-
12826
  foreach ($sucuriscan_notify_options as $alert_type => $alert_label) {
12827
  $option_value = SucuriScanRequest::post($alert_type, '(1|0)');
12828
 
@@ -12966,6 +14020,7 @@ function sucuriscan_settings_apiservice($nonce)
12966
  $params['SettingsSection.ApiProxy'] = sucuriscan_settings_apiservice_proxy($nonce);
12967
  $params['SettingsSection.ApiSSL'] = sucuriscan_settings_apiservice_ssl($nonce);
12968
  $params['SettingsSection.ApiTimeout'] = sucuriscan_settings_apiservice_timeout($nonce);
 
12969
 
12970
  return SucuriScanTemplate::getSection('settings-apiservice', $params);
12971
  }
@@ -13115,6 +14170,75 @@ function sucuriscan_settings_apiservice_timeout($nonce)
13115
  return SucuriScanTemplate::getSection('settings-apiservice-timeout', $params);
13116
  }
13117
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13118
  /**
13119
  * Read and parse the content of the self-hosting settings template.
13120
  *
@@ -13172,11 +14296,12 @@ function sucuriscan_settings_selfhosting_monitor($nonce)
13172
  SucuriScanInterface::info($message);
13173
  } elseif (strpos($monitor_fpath, $_SERVER['DOCUMENT_ROOT']) !== false) {
13174
  SucuriScanInterface::error('File should not be publicly accessible.');
13175
- } elseif (!file_exists($monitor_fpath)) {
13176
- SucuriScanInterface::error('File path does not exists.');
13177
- } elseif (!is_writable($monitor_fpath)) {
13178
- SucuriScanInterface::error('File path is not writable.');
13179
  } else {
 
13180
  $message = 'Log exporter file path was set correctly.';
13181
 
13182
  SucuriScanEvent::report_info_event($message);
@@ -13314,6 +14439,10 @@ function sucuriscan_settings_heartbeat()
13314
  return SucuriScanTemplate::getSection('settings-heartbeat', $params);
13315
  }
13316
 
 
 
 
 
13317
  /**
13318
  * Print a HTML code with the settings of the plugin.
13319
  *
@@ -13328,11 +14457,11 @@ function sucuriscan_settings_page()
13328
 
13329
  $params['PageTitle'] = 'Settings';
13330
  $params['Settings.General'] = sucuriscan_settings_general($nonce);
13331
- $params['Settings.Scanner'] = sucuriscan_settings_scanner();
13332
  $params['Settings.Alerts'] = sucuriscan_settings_alert($nonce);
13333
  $params['Settings.ApiService'] = sucuriscan_settings_apiservice($nonce);
13334
  $params['Settings.SelfHosting'] = sucuriscan_settings_selfhosting($nonce);
13335
- $params['Settings.IgnoreScanning'] = sucuriscan_settings_ignorescanning();
13336
  $params['Settings.IgnoreRules'] = sucuriscan_settings_ignore_rules();
13337
  $params['Settings.TrustIP'] = sucuriscan_settings_trust_ip();
13338
  $params['Settings.Heartbeat'] = sucuriscan_settings_heartbeat();
@@ -13340,6 +14469,23 @@ function sucuriscan_settings_page()
13340
  echo SucuriScanTemplate::getTemplate('settings', $params);
13341
  }
13342
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13343
  /**
13344
  * Generate and print the HTML code for the InfoSys page.
13345
  *
@@ -13369,6 +14515,22 @@ function sucuriscan_infosys_page()
13369
  echo SucuriScanTemplate::getTemplate('infosys', $params);
13370
  }
13371
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13372
  /**
13373
  * Find the main htaccess file for the site and check whether the rules of the
13374
  * main htaccess file of the site are the default rules generated by WordPress.
@@ -13561,7 +14723,6 @@ function sucuriscan_show_cronjobs()
13561
  );
13562
 
13563
  $cronjobs = _get_cron_array();
13564
- $schedules = wp_get_schedules();
13565
  $counter = 0;
13566
 
13567
  foreach ($cronjobs as $timestamp => $cronhooks) {
@@ -13645,7 +14806,6 @@ function sucuriscan_infosys_form_submissions()
13645
  ));
13646
 
13647
  foreach ($cronjobs as $task_name) {
13648
- wp_clear_scheduled_hook($task_name);
13649
  $next_due = wp_next_scheduled($task_name);
13650
  wp_schedule_event($next_due, $cronjob_action, $task_name);
13651
  }
@@ -13664,67 +14824,123 @@ function sucuriscan_infosys_form_submissions()
13664
  */
13665
  function sucuriscan_infosys_errorlogs()
13666
  {
13667
- $params = array(
13668
- 'ErrorLog.Path' => '',
13669
- 'ErrorLog.Exists' => 'No',
13670
- 'ErrorLog.NoItemsVisibility' => 'hidden',
13671
- 'ErrorLog.DisabledVisibility' => 'hidden',
13672
- 'ErrorLog.InvalidFormatVisibility' => 'hidden',
13673
- 'ErrorLog.LogsLimit' => '0',
13674
- 'ErrorLog.FileSize' => '0B',
13675
- 'ErrorLog.List' => '',
13676
- );
13677
 
13678
- $error_log_path = false;
13679
- $log_filename = SucuriScan::ini_get('error_log');
13680
- $errorlogs_limit = SucuriScanOption::get_option(':errorlogs_limit');
13681
- $params['ErrorLog.LogsLimit'] = $errorlogs_limit;
13682
- $counter = 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13683
 
13684
- if ($log_filename) {
13685
- $error_log_path = @realpath(ABSPATH . '/' . $log_filename);
 
 
 
13686
  }
13687
 
13688
- if (SucuriScanOption::is_disabled(':parse_errorlogs')) {
13689
- $params['ErrorLog.DisabledVisibility'] = 'visible';
 
 
 
13690
  }
13691
 
13692
- if ($error_log_path) {
13693
- $params['ErrorLog.Exists'] = 'Yes';
13694
- $params['ErrorLog.Path'] = $error_log_path;
13695
- $params['ErrorLog.FileSize'] = SucuriScan::human_filesize(filesize($error_log_path));
13696
 
13697
- $last_lines = SucuriScanFileInfo::tail_file($error_log_path, $errorlogs_limit);
13698
- $error_logs = SucuriScanFSScanner::parse_error_logs($last_lines);
13699
- $error_logs = array_reverse($error_logs);
13700
- $counter = 0;
13701
 
13702
- foreach ($error_logs as $error_log) {
13703
- $css_class = ( $counter % 2 === 0 ) ? '' : 'alternate';
13704
- $params['ErrorLog.List'] .= SucuriScanTemplate::getSnippet(
13705
- 'infosys-errorlogs',
13706
- array(
13707
- 'ErrorLog.CssClass' => $css_class,
13708
- 'ErrorLog.DateTime' => SucuriScan::datetime($error_log->timestamp),
13709
- 'ErrorLog.ErrorType' => $error_log->error_type,
13710
- 'ErrorLog.ErrorCode' => $error_log->error_code,
13711
- 'ErrorLog.ErrorAbbr' => strtoupper(substr($error_log->error_code, 0, 1)),
13712
- 'ErrorLog.ErrorMessage' => $error_log->error_message,
13713
- 'ErrorLog.FilePath' => $error_log->file_path,
13714
- 'ErrorLog.LineNumber' => $error_log->line_number,
13715
- )
13716
- );
13717
- $counter += 1;
13718
- }
13719
 
13720
- if ($counter <= 0) {
13721
- $params['ErrorLog.InvalidFormatVisibility'] = 'visible';
 
 
13722
  }
13723
- } else {
13724
- $params['ErrorLog.NoItemsVisibility'] = 'visible';
13725
  }
13726
 
13727
- return SucuriScanTemplate::getSection('infosys-errorlogs', $params);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13728
  }
13729
 
13730
  /**
@@ -13757,7 +14973,7 @@ function sucuriscan_server_info()
13757
  $info_vars['Datetime_and_Timezone'] = sprintf(
13758
  '%s (GMT %s)',
13759
  SucuriScan::current_datetime(),
13760
- get_option('gmt_offset')
13761
  );
13762
 
13763
  if (defined('WP_DEBUG') && WP_DEBUG) {
4
  Plugin URI: https://wordpress.sucuri.net/
5
  Description: The <a href="https://sucuri.net/" target="_blank">Sucuri</a> plugin provides the website owner the best Activity Auditing, SiteCheck Remote Malware Scanning, Effective Security Hardening and Post-Hack features. SiteCheck will check for malware, spam, blacklisting and other security issues like .htaccess redirects, hidden eval code, etc. The best thing about it is it's completely free.
6
  Author: Sucuri, INC
7
+ Version: 1.7.18
8
  Author URI: https://sucuri.net
9
  */
10
 
13
  * Main file to control the plugin.
14
  *
15
  * @package Sucuri Security
 
16
  * @author Daniel Cid <dcid@sucuri.net>
17
  * @copyright Since 2010-2015 Sucuri Inc.
18
  * @license Released under the GPL - see LICENSE file for details.
65
  /**
66
  * Current version of the plugin's code.
67
  */
68
+ define('SUCURISCAN_VERSION', '1.7.18');
69
 
70
  /**
71
  * The name of the Sucuri plugin main file.
75
  /**
76
  * The name of the folder where the plugin's files will be located.
77
  */
78
+ define('SUCURISCAN_PLUGIN_FOLDER', basename(__DIR__));
79
 
80
  /**
81
  * The fullpath where the plugin's files will be located.
100
  /**
101
  * Remote URL where the public Sucuri API service is running.
102
  */
103
+ define('SUCURISCAN_API', 'sucuri://wordpress.sucuri.net/api/');
104
 
105
  /**
106
  * Latest version of the public Sucuri API.
110
  /**
111
  * Remote URL where the CloudProxy API service is running.
112
  */
113
+ define('SUCURISCAN_CLOUDPROXY_API', 'sucuri://waf.sucuri.net/api');
114
 
115
  /**
116
  * Latest version of the CloudProxy API.
152
  */
153
  define('SUCURISCAN_MAX_REQUEST_TIMEOUT', 15);
154
 
155
+ /**
156
+ * The maximum execution time for SiteCheck requests before timeout.
157
+ */
158
+ define('SUCURISCAN_MAX_SITECHECK_TIMEOUT', 60);
159
+
160
  /**
161
  * Plugin's global variables.
162
  *
211
  'sucuriscan_use_wpmail' => 'Use WordPress functions to send mails <em>(uncheck to use native PHP functions)</em>',
212
  'sucuriscan_lastlogin_redirection' => 'Allow redirection after login to report the last-login information',
213
  'sucuriscan_notify_scan_checksums' => 'Receive email alerts for core integrity checks',
214
+ 'sucuriscan_notify_available_updates' => 'Receive email alerts for available updates',
215
  'sucuriscan_notify_user_registration' => 'user:Receive email alerts for new user registration',
216
  'sucuriscan_notify_success_login' => 'user:Receive email alerts for successful login attempts',
217
  'sucuriscan_notify_failed_login' => 'user:Receive email alerts for failed login attempts <em>(you may receive tons of emails)</em>',
282
  'Sucuri Alert, :event',
283
  );
284
 
285
+ $sucuriscan_date_format = get_option('date_format');
286
+ $sucuriscan_time_format = get_option('time_format');
287
+
288
  /**
289
  * Remove the WordPress generator meta-tag from the source code.
290
  */
305
  * execute the bootstrap function of the plugin.
306
  */
307
  add_action('init', 'SucuriScanInterface::initialize', 1);
308
+ add_action('init', 'SucuriScanBlockedUsers::blockUserLogin', 1);
309
+ add_action('admin_enqueue_scripts', 'SucuriScanInterface::enqueueScripts', 1);
310
+
311
+ if (SucuriScan::runAdminInit()) {
312
+ add_action('admin_init', 'SucuriScanInterface::handleOldPlugins');
313
+ add_action('admin_init', 'SucuriScanInterface::createStorageFolder');
314
+ add_action('admin_init', 'SucuriScanInterface::noticeAfterUpdate');
315
+ }
316
 
317
  /**
318
  * Display extension menu and submenu items in the correct interface. For single
320
  * multisite installations the menu items must be available only in the network
321
  * panel and hidden in the administration panel of the subsites.
322
  */
323
+ add_action($sucuriscan_action_prefix . 'admin_menu', 'SucuriScanInterface::addInterfaceMenu');
324
 
325
  /**
326
  * Attach Ajax requests to a custom page handler.
374
  add_action($hook_name, $hook_func, 50, 5);
375
  }
376
 
377
+ if (SucuriScan::runAdminInit()) {
378
+ add_action('admin_init', 'SucuriScanHook::hook_undefined_actions');
379
+ }
380
+
381
  add_action('login_form', 'SucuriScanHook::hook_undefined_actions');
382
  } else {
383
  SucuriScanInterface::error('Function call interceptors are not working properly.');
545
  return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$sz[ $factor ];
546
  }
547
 
548
+ /**
549
+ * Check if the admin init hook must not be intercepted.
550
+ *
551
+ * @return boolean True if the admin init hook must not be intercepted.
552
+ */
553
+ public static function noAdminInit()
554
+ {
555
+ return (bool) (
556
+ defined('SUCURISCAN_ADMIN_INIT')
557
+ && SUCURISCAN_ADMIN_INIT === false
558
+ );
559
+ }
560
+
561
+ /**
562
+ * Check if the admin init hook must be intercepted.
563
+ *
564
+ * @return boolean True if the admin init hook must be intercepted.
565
+ */
566
+ public static function runAdminInit()
567
+ {
568
+ return (bool) (self::noAdminInit() === false);
569
+ }
570
+
571
+ /**
572
+ * Fix the deliminar of a resource path.
573
+ *
574
+ * In Windows based system the directory separator is a back slash which
575
+ * differs from what other file systems use. To keep consistency during the
576
+ * unit-tests we have decided to replace any non forward slash with it.
577
+ *
578
+ * @return string Fixed file path.
579
+ */
580
+ public static function fixPath($path = '')
581
+ {
582
+ $delimiter = '/' /* Forward slash */;
583
+ $path = str_replace(DIRECTORY_SEPARATOR, $delimiter, $path);
584
+ $path = rtrim($path, $delimiter);
585
+
586
+ return $path;
587
+ }
588
+
589
  /**
590
  * Returns the system filepath to the relevant user uploads directory for this
591
  * site. This is a multisite capable function.
596
  public static function datastore_folder_path($path = '')
597
  {
598
  $default_dir = 'sucuri';
599
+ $abspath = self::fixPath(ABSPATH);
600
+
601
+ if (defined('SUCURI_DATA_STORAGE')
602
+ && file_exists(SUCURI_DATA_STORAGE)
603
+ && is_dir(SUCURI_DATA_STORAGE)
604
+ ) {
605
+ $datastore = SUCURI_DATA_STORAGE;
606
+ } else {
607
+ $datastore = SucuriScanOption::get_option(':datastore_path');
608
+ }
609
 
610
  // Use the uploads folder by default.
611
  if (empty($datastore)) {
616
  $upload_dir = wp_upload_dir();
617
 
618
  if (isset($upload_dir['basedir'])) {
619
+ $uploads_path = rtrim($upload_dir['basedir'], DIRECTORY_SEPARATOR);
620
  }
621
  }
622
 
623
  if ($uploads_path === false) {
624
  if (defined('WP_CONTENT_DIR')) {
625
+ $uploads_path = implode(DIRECTORY_SEPARATOR, array(WP_CONTENT_DIR, 'uploads'));
626
  } else {
627
+ $uploads_path = implode(DIRECTORY_SEPARATOR, array($abspath, 'wp-content', 'uploads'));
628
  }
629
  }
630
 
631
+ $datastore = $uploads_path . DIRECTORY_SEPARATOR . $default_dir;
632
+ $datastore = self::fixPath($datastore);
633
  SucuriScanOption::update_option(':datastore_path', $datastore);
634
  }
635
 
636
+ // Keep consistency with the directory separator.
637
+ $final = $datastore . DIRECTORY_SEPARATOR . $path;
638
+ $final = self::fixPath($final);
639
+
640
+ return $final;
641
  }
642
 
643
  /**
756
  {
757
  SucuriScanEvent::filesystem_scan();
758
  sucuriscan_core_files_data(true);
759
+ sucuriscan_posthack_updates_content(true);
760
  }
761
 
762
  /**
776
  public static function allowedHttpHeaders($with_keys = false)
777
  {
778
  $allowed = array(
779
+ /* CloudProxy custom HTTP headers */
780
  'HTTP_X_SUCURI_CLIENTIP',
781
+ /* CloudFlare custom HTTP headers */
782
+ 'HTTP_CF_CONNECTING_IP', /* Real visitor IP. */
783
+ 'HTTP_CF_IPCOUNTRY', /* Country of visitor. */
784
+ 'HTTP_CF_RAY', /* https://support.cloudflare.com/entries/23046742-w. */
785
+ 'HTTP_CF_VISITOR', /* Determine if HTTP or HTTPS. */
786
+ /* Possible HTTP headers */
787
  'HTTP_X_REAL_IP',
788
  'HTTP_CLIENT_IP',
789
  'HTTP_X_FORWARDED_FOR',
1103
  */
1104
  public static function datetime($timestamp = null)
1105
  {
1106
+ global $sucuriscan_date_format, $sucuriscan_time_format;
1107
+
1108
+ $tz_format = $sucuriscan_date_format . "\x20" . $sucuriscan_time_format;
1109
 
1110
  if (is_numeric($timestamp) && $timestamp > 0) {
1111
  return date_i18n($tz_format, $timestamp);
1377
  }
1378
  }
1379
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1380
  /**
1381
  * Check whether the site is running over the Nginx web server.
1382
  *
1396
  {
1397
  return (bool) preg_match('/Microsoft-IIS/i', @$_SERVER['SERVER_SOFTWARE']);
1398
  }
1399
+
1400
+ /**
1401
+ * Returns list of supported languages.
1402
+ *
1403
+ * @return array Supported languages abbreviated.
1404
+ */
1405
+ public static function languages()
1406
+ {
1407
+ return array(
1408
+ 'af' => 'af',
1409
+ 'ak' => 'ak',
1410
+ 'sq' => 'sq',
1411
+ 'arq' => 'arq',
1412
+ 'am' => 'am',
1413
+ 'ar' => 'ar',
1414
+ 'hy' => 'hy',
1415
+ 'rup_MK' => 'rup_MK',
1416
+ 'frp' => 'frp',
1417
+ 'as' => 'as',
1418
+ 'az' => 'az',
1419
+ 'az_TR' => 'az_TR',
1420
+ 'bcc' => 'bcc',
1421
+ 'ba' => 'ba',
1422
+ 'eu' => 'eu',
1423
+ 'bel' => 'bel',
1424
+ 'bn_BD' => 'bn_BD',
1425
+ 'bs_BA' => 'bs_BA',
1426
+ 'bre' => 'bre',
1427
+ 'bg_BG' => 'bg_BG',
1428
+ 'ca' => 'ca',
1429
+ 'bal' => 'bal',
1430
+ 'zh_CN' => 'zh_CN',
1431
+ 'zh_HK' => 'zh_HK',
1432
+ 'zh_TW' => 'zh_TW',
1433
+ 'co' => 'co',
1434
+ 'hr' => 'hr',
1435
+ 'cs_CZ' => 'cs_CZ',
1436
+ 'da_DK' => 'da_DK',
1437
+ 'dv' => 'dv',
1438
+ 'nl_NL' => 'nl_NL',
1439
+ 'nl_BE' => 'nl_BE',
1440
+ 'dzo' => 'dzo',
1441
+ 'en_US' => 'en_US',
1442
+ 'en_AU' => 'en_AU',
1443
+ 'en_CA' => 'en_CA',
1444
+ 'en_ZA' => 'en_ZA',
1445
+ 'en_GB' => 'en_GB',
1446
+ 'eo' => 'eo',
1447
+ 'et' => 'et',
1448
+ 'fo' => 'fo',
1449
+ 'fi' => 'fi',
1450
+ 'fr_BE' => 'fr_BE',
1451
+ 'fr_CA' => 'fr_CA',
1452
+ 'fr_FR' => 'fr_FR',
1453
+ 'fy' => 'fy',
1454
+ 'fuc' => 'fuc',
1455
+ 'gl_ES' => 'gl_ES',
1456
+ 'ka_GE' => 'ka_GE',
1457
+ 'de_DE' => 'de_DE',
1458
+ 'de_CH' => 'de_CH',
1459
+ 'el' => 'el',
1460
+ 'gn' => 'gn',
1461
+ 'gu' => 'gu',
1462
+ 'haw_US' => 'haw_US',
1463
+ 'haz' => 'haz',
1464
+ 'he_IL' => 'he_IL',
1465
+ 'hi_IN' => 'hi_IN',
1466
+ 'hu_HU' => 'hu_HU',
1467
+ 'is_IS' => 'is_IS',
1468
+ 'ido' => 'ido',
1469
+ 'id_ID' => 'id_ID',
1470
+ 'ga' => 'ga',
1471
+ 'it_IT' => 'it_IT',
1472
+ 'ja' => 'ja',
1473
+ 'jv_ID' => 'jv_ID',
1474
+ 'kab' => 'kab',
1475
+ 'kn' => 'kn',
1476
+ 'kk' => 'kk',
1477
+ 'km' => 'km',
1478
+ 'kin' => 'kin',
1479
+ 'ky_KY' => 'ky_KY',
1480
+ 'ko_KR' => 'ko_KR',
1481
+ 'ckb' => 'ckb',
1482
+ 'lo' => 'lo',
1483
+ 'lv' => 'lv',
1484
+ 'li' => 'li',
1485
+ 'lin' => 'lin',
1486
+ 'lt_LT' => 'lt_LT',
1487
+ 'lb_LU' => 'lb_LU',
1488
+ 'mk_MK' => 'mk_MK',
1489
+ 'mg_MG' => 'mg_MG',
1490
+ 'ms_MY' => 'ms_MY',
1491
+ 'ml_IN' => 'ml_IN',
1492
+ 'mri' => 'mri',
1493
+ 'mr' => 'mr',
1494
+ 'xmf' => 'xmf',
1495
+ 'mn' => 'mn',
1496
+ 'me_ME' => 'me_ME',
1497
+ 'my_MM' => 'my_MM',
1498
+ 'ne_NP' => 'ne_NP',
1499
+ 'nb_NO' => 'nb_NO',
1500
+ 'nn_NO' => 'nn_NO',
1501
+ 'oci' => 'oci',
1502
+ 'ory' => 'ory',
1503
+ 'os' => 'os',
1504
+ 'ps' => 'ps',
1505
+ 'fa_IR' => 'fa_IR',
1506
+ 'fa_AF' => 'fa_AF',
1507
+ 'pl_PL' => 'pl_PL',
1508
+ 'pt_BR' => 'pt_BR',
1509
+ 'pt_PT' => 'pt_PT',
1510
+ 'pa_IN' => 'pa_IN',
1511
+ 'rhg' => 'rhg',
1512
+ 'ro_RO' => 'ro_RO',
1513
+ 'roh' => 'roh',
1514
+ 'ru_RU' => 'ru_RU',
1515
+ 'ru_UA' => 'ru_UA',
1516
+ 'rue' => 'rue',
1517
+ 'sah' => 'sah',
1518
+ 'sa_IN' => 'sa_IN',
1519
+ 'srd' => 'srd',
1520
+ 'gd' => 'gd',
1521
+ 'sr_RS' => 'sr_RS',
1522
+ 'szl' => 'szl',
1523
+ 'sd_PK' => 'sd_PK',
1524
+ 'si_LK' => 'si_LK',
1525
+ 'sk_SK' => 'sk_SK',
1526
+ 'sl_SI' => 'sl_SI',
1527
+ 'so_SO' => 'so_SO',
1528
+ 'azb' => 'azb',
1529
+ 'es_AR' => 'es_AR',
1530
+ 'es_CL' => 'es_CL',
1531
+ 'es_CO' => 'es_CO',
1532
+ 'es_MX' => 'es_MX',
1533
+ 'es_PE' => 'es_PE',
1534
+ 'es_PR' => 'es_PR',
1535
+ 'es_ES' => 'es_ES',
1536
+ 'es_VE' => 'es_VE',
1537
+ 'su_ID' => 'su_ID',
1538
+ 'sw' => 'sw',
1539
+ 'sv_SE' => 'sv_SE',
1540
+ 'gsw' => 'gsw',
1541
+ 'tl' => 'tl',
1542
+ 'tg' => 'tg',
1543
+ 'tzm' => 'tzm',
1544
+ 'ta_IN' => 'ta_IN',
1545
+ 'ta_LK' => 'ta_LK',
1546
+ 'tt_RU' => 'tt_RU',
1547
+ 'te' => 'te',
1548
+ 'th' => 'th',
1549
+ 'bo' => 'bo',
1550
+ 'tir' => 'tir',
1551
+ 'tr_TR' => 'tr_TR',
1552
+ 'tuk' => 'tuk',
1553
+ 'ug_CN' => 'ug_CN',
1554
+ 'uk' => 'uk',
1555
+ 'ur' => 'ur',
1556
+ 'uz_UZ' => 'uz_UZ',
1557
+ 'vi' => 'vi',
1558
+ 'wa' => 'wa',
1559
+ 'cy' => 'cy',
1560
+ );
1561
+ }
1562
+
1563
  }
1564
 
1565
  /**
1759
  public function get_directory_tree_md5($directory = '', $as_array = false)
1760
  {
1761
  $project_signatures = '';
1762
+ $abspath = self::fixPath(ABSPATH);
1763
  $files = $this->get_directory_tree($directory);
1764
 
1765
  if ($as_array) {
1774
  $filesize = @filesize($filepath);
1775
 
1776
  if ($as_array) {
1777
+ $basename = str_replace($abspath . '/', '', $filepath);
1778
  $project_signatures[ $basename ] = array(
1779
  'filepath' => $filepath,
1780
  'checksum' => $file_checksum,
1783
  'modified_at' => @filemtime($filepath),
1784
  );
1785
  } else {
1786
+ $filepath = str_replace($abspath, $abspath . '/', $filepath);
1787
  $project_signatures .= sprintf(
1788
  "%s%s%s%s\n",
1789
  $file_checksum,
1841
  break;
1842
  }
1843
 
1844
+ if (is_array($tree) && !empty($tree)) {
1845
+ return array_map(array('SucuriScan', 'fixPath'), $tree);
1846
+ }
1847
  }
1848
 
1849
  return false;
2280
  return false;
2281
  }
2282
 
2283
+ /**
2284
+ * Returns the content of a file.
2285
+ *
2286
+ * If the file does not exists or is not readable the function will return
2287
+ * false. Make sure that you double check this with a condition using triple
2288
+ * equals in order to avoid ambiguous results when the file exists, is
2289
+ * readable, but is empty.
2290
+ *
2291
+ * @param string $fpath Relative or absolute path of the file.
2292
+ * @return string Content of the file, false if not accessible.
2293
+ */
2294
+ public static function fileContent($fpath = '')
2295
+ {
2296
+ if (file_exists($fpath) && is_readable($fpath)) {
2297
+ return file_get_contents($fpath);
2298
+ }
2299
+
2300
+ return false;
2301
+ }
2302
+
2303
  /**
2304
  * Return the lines of a file as an array, it will automatically remove the new
2305
  * line characters from the end of each line, and skip empty lines from the
2536
  {
2537
  if (!is_null($this->datastore)) {
2538
  $folder_path = $this->datastore_folder_path();
2539
+ $file_path = $folder_path . '/sucuri-' . $this->datastore . '.php';
2540
 
2541
  // Create the datastore parent directory.
2542
  if (!file_exists($folder_path)) {
2893
  $defaults = array(
2894
  'sucuriscan_account' => '',
2895
  'sucuriscan_addr_header' => 'HTTP_X_SUCURI_CLIENTIP',
 
2896
  'sucuriscan_api_key' => false,
2897
+ 'sucuriscan_api_protocol' => 'https',
2898
  'sucuriscan_api_service' => 'enabled',
2899
  'sucuriscan_audit_report' => 'disabled',
2900
  'sucuriscan_cloudproxy_apikey' => '',
2914
  'sucuriscan_heartbeat_pulse' => 15,
2915
  'sucuriscan_ignore_scanning' => 'disabled',
2916
  'sucuriscan_ignored_events' => '',
2917
+ 'sucuriscan_language' => 'en_US',
2918
  'sucuriscan_last_email_at' => time(),
2919
  'sucuriscan_lastlogin_redirection' => 'enabled',
2920
  'sucuriscan_logs4report' => 500,
2921
  'sucuriscan_maximum_failed_logins' => 30,
2922
+ 'sucuriscan_notify_available_updates' => 'enabled',
2923
  'sucuriscan_notify_bruteforce_attack' => 'disabled',
2924
  'sucuriscan_notify_failed_login' => 'enabled',
2925
  'sucuriscan_notify_plugin_activated' => 'disabled',
2929
  'sucuriscan_notify_plugin_installed' => 'disabled',
2930
  'sucuriscan_notify_plugin_updated' => 'disabled',
2931
  'sucuriscan_notify_post_publication' => 'enabled',
2932
+ 'sucuriscan_notify_scan_checksums' => 'enabled',
2933
  'sucuriscan_notify_settings_updated' => 'disabled',
2934
  'sucuriscan_notify_success_login' => 'enabled',
2935
  'sucuriscan_notify_theme_activated' => 'disabled',
2943
  'sucuriscan_notify_widget_added' => 'disabled',
2944
  'sucuriscan_notify_widget_deleted' => 'disabled',
2945
  'sucuriscan_parse_errorlogs' => 'enabled',
2946
+ 'sucuriscan_plugin_version' => '0.0',
2947
  'sucuriscan_prettify_mails' => 'disabled',
2948
  'sucuriscan_request_timeout' => 5,
2949
  'sucuriscan_revproxy' => 'disabled',
2956
  'sucuriscan_selfhosting_monitor' => 'disabled',
2957
  'sucuriscan_site_version' => '0.0',
2958
  'sucuriscan_sitecheck_counter' => 0,
2959
+ 'sucuriscan_sitecheck_timeout' => 30,
2960
  'sucuriscan_use_wpmail' => 'enabled',
2961
  'sucuriscan_verify_ssl_cert' => 'false',
2962
  'sucuriscan_xhr_monitor' => 'disabled',
2981
  /**
2982
  * Check whether an option is used in the plugin or not.
2983
  *
2984
+ * @param string $option Name of the option that will be checked.
2985
+ * @return boolean True if the option is part of the plugin, False otherwise.
2986
  */
2987
+ public static function is_valid_plugin_option($option = '')
2988
  {
2989
+ $options = self::get_default_option_names();
 
2990
 
2991
+ return (bool) in_array($option, $options);
2992
  }
2993
 
2994
  /**
3029
  }
3030
 
3031
  /**
3032
+ * Returns path of the options storage.
3033
+ *
3034
+ * Returns the absolute path of the file that will store the options
3035
+ * associated to the plugin. This must be a PHP file without public access,
3036
+ * for which reason it will contain a header with an exit point to prevent
3037
+ * malicious people to read the its content. The rest of the file will
3038
+ * content a JSON encoded array.
3039
+ *
3040
+ * @return string File path of the options storage.
3041
+ */
3042
+ public static function optionsFilePath()
3043
+ {
3044
+ $folder = WP_CONTENT_DIR . '/uploads/sucuri';
3045
+
3046
+ if (defined('SUCURI_DATA_STORAGE')
3047
+ && file_exists(SUCURI_DATA_STORAGE)
3048
+ && is_dir(SUCURI_DATA_STORAGE)
3049
+ ) {
3050
+ $folder = SUCURI_DATA_STORAGE;
3051
+ }
3052
+
3053
+ return $folder . '/sucuri-settings.php';
3054
+ }
3055
+
3056
+ /**
3057
+ * Returns an array with all the plugin options.
3058
+ *
3059
+ * NOTE: There is a maximum number of lines for this file, one is for the
3060
+ * exit point and the other one is for a single line JSON encoded string.
3061
+ * We will discard any other content that exceeds this limit.
3062
+ *
3063
+ * @return array Array with all the plugin options.
3064
+ */
3065
+ public static function getAllOptions()
3066
+ {
3067
+ $options = array();
3068
+ $fpath = self::optionsFilePath();
3069
+
3070
+ /* Use this over SucuriScanCache to prevent nested function calls */
3071
+ $content = SucuriScanFileInfo::fileContent($fpath);
3072
+
3073
+ if ($content !== false) {
3074
+ // Refer to self::optionsFilePath to know why the number two.
3075
+ $lines = explode("\n", $content, 2);
3076
+
3077
+ if (count($lines) >= 2) {
3078
+ $jsonData = json_decode($lines[1], true);
3079
+
3080
+ if (is_array($jsonData) && !empty($jsonData)) {
3081
+ $options = $jsonData;
3082
+ }
3083
+ }
3084
+ }
3085
+
3086
+ return $options;
3087
+ }
3088
+
3089
+ /**
3090
+ * Write new options into the external options file.
3091
  *
3092
+ * @param array $options Array with plugins options.
3093
+ * @return boolean True if the new options were saved, false otherwise.
3094
+ */
3095
+ public static function writeNewOptions($options = array())
3096
+ {
3097
+ $fpath = self::optionsFilePath();
3098
+ $content = "<?php exit(0); ?>\n";
3099
+ $content .= @json_encode($options) . "\n";
3100
+
3101
+ return (bool) @file_put_contents($fpath, $content);
3102
+ }
3103
+
3104
+ /**
3105
+ * Returns data from the settings file or the database.
3106
  *
3107
  * To facilitate the development, you can prefix the name of the key in the
3108
  * request (when accessing it) with a single colon, this function will
3109
  * automatically replace that character with the unique identifier of the
3110
  * plugin.
3111
  *
3112
+ * NOTE: The SucuriScanCache library is a better interface to read the
3113
+ * content of a configuration file following the same standard in the other
3114
+ * files associated to the plugin. However, this library makes use of this
3115
+ * function to retrieve the directory where the files are stored, if we use
3116
+ * this library for this specific task we will end up provoking a maximum
3117
+ * nesting function call warning.
3118
  *
3119
+ * @param string $option Name of the setting that will be retrieved.
3120
+ * @return string Option value, or default value if empty.
3121
  */
3122
+ public static function get_option($option = '')
3123
  {
3124
+ $options = self::getAllOptions();
3125
+ $option = self::variable_prefix($option);
3126
+
3127
+ if (array_key_exists($option, $options)) {
3128
+ return $options[$option];
3129
+ }
3130
+
3131
+ /**
3132
+ * Fallback to the default values.
3133
+ *
3134
+ * If the option is not set in the external options file then we must
3135
+ * search in the database for older data, this to provide backward
3136
+ * compatibility with older installations of the plugin. If the option
3137
+ * is found in the database we must insert it in the external file and
3138
+ * delete it from the database before the value is returned to the user.
3139
+ *
3140
+ * If the option is not in the external file nor in the database, and
3141
+ * the name starts with the same prefix used by the plugin then we must
3142
+ * return the default value defined by the author.
3143
+ */
3144
+ if (function_exists('get_option')) {
3145
+ $value = get_option($option);
3146
 
3147
+ if ($value !== false) {
3148
+ if (strpos($option, 'sucuriscan_') === 0) {
3149
+ delete_option($option);
3150
+ self::update_option($option, $value);
3151
+ }
3152
+
3153
+ return $value;
3154
  }
3155
+ }
3156
 
3157
+ if (strpos($option, 'sucuriscan_') === 0) {
3158
+ return self::get_default_options($option);
3159
  }
3160
 
3161
  return false;
3171
  *
3172
  * @see https://codex.wordpress.org/Function_Reference/update_option
3173
  *
3174
+ * @param string $option Name of the option to update, must not exceed 64 characters.
3175
+ * @param string $value New value, either an integer, string, array, or object.
3176
+ * @return boolean True if option value has changed, false otherwise.
3177
  */
3178
+ public static function update_option($option = '', $value = '')
3179
  {
3180
+ if (strpos($option, ':') === 0 || strpos($option, 'sucuriscan') === 0) {
3181
+ $options = self::getAllOptions();
3182
+ $option = self::variable_prefix($option);
3183
+ $options[$option] = $value;
3184
 
3185
+ return self::writeNewOptions($options);
3186
+ }
3187
+
3188
+ if (function_exists('update_option')) {
3189
+ return update_option($option, $value);
3190
  }
3191
 
3192
  return false;
3199
  *
3200
  * @see https://codex.wordpress.org/Function_Reference/delete_option
3201
  *
3202
+ * @param string $option Name of the option to be deleted.
3203
+ * @return boolean True, if option is successfully deleted. False on failure, or option does not exist.
3204
  */
3205
+ public static function delete_option($option = '')
3206
  {
3207
+ if (strpos($option, ':') === 0 || strpos($option, 'sucuriscan') === 0) {
3208
+ $options = self::getAllOptions();
3209
+ $option = self::variable_prefix($option);
3210
+
3211
+ // Create/Modify option's value.
3212
+ if (array_key_exists($option, $options)) {
3213
+ unset($options[$option]);
3214
+
3215
+ return self::writeNewOptions($options);
3216
+ }
3217
+ }
3218
 
3219
+ if (function_exists('delete_option')) {
3220
+ return delete_option($option);
3221
  }
3222
 
3223
  return false;
3261
  );
3262
 
3263
  foreach ($options as $option) {
3264
+ delete_option($option->option_name);
3265
+ }
3266
+
3267
+ // Merge with the default options to ensure full cleanup.
3268
+ $default = self::get_default_option_names();
3269
+
3270
+ foreach ($default as $option) {
3271
+ if (is_string($option)) {
3272
+ self::delete_option($option);
3273
+ }
3274
  }
3275
  }
3276
 
3296
  $settings[ $row->option_name ] = $row->option_value;
3297
  }
3298
 
3299
+ $external = self::getAllOptions();
3300
+
3301
+ foreach ($external as $option => $value) {
3302
+ $settings[$option] = $value;
3303
+ }
3304
+
3305
  return $settings;
3306
  }
3307
 
3389
  $post_types = self::get_option(':ignored_events');
3390
  $post_types_arr = false;
3391
 
3392
+ if (is_string($post_types)) {
 
 
 
 
 
 
 
 
3393
  $post_types_arr = @json_decode($post_types, true);
3394
  }
3395
 
3431
  /**
3432
  * Remove a post type from the list of ignored events to send notifications.
3433
  *
3434
+ * @param string $event Unique post-type name.
3435
+ * @return boolean Whether the event was removed from the list or not.
3436
  */
3437
+ public static function remove_ignored_event($event = '')
3438
  {
3439
+ $ignored = self::get_ignored_events();
3440
 
3441
+ if (array_key_exists($event, $ignored)) {
3442
+ unset($ignored[$event]);
 
3443
 
3444
+ return self::update_option(
3445
+ ':ignored_events',
3446
+ @json_encode($ignored)
3447
+ );
3448
  }
3449
 
3450
  return false;
3453
  /**
3454
  * Check whether an event is being ignored to send notifications or not.
3455
  *
3456
+ * @param string $event Unique post-type name.
3457
+ * @return boolean Whether an event is being ignored or not.
3458
  */
3459
+ public static function is_ignored_event($event = '')
3460
  {
3461
+ $event = strtolower($event);
3462
+ $ignored = self::get_ignored_events();
 
 
 
 
3463
 
3464
+ return array_key_exists($event, $ignored);
3465
  }
3466
 
3467
  /**
3519
  */
3520
  public static function setRevProxy($action = 'disable')
3521
  {
3522
+ if ($action !== 'enable' && $action !== 'disable') {
3523
+ return self::delete_option(':revproxy');
3524
+ }
3525
+
3526
  $action_d = $action . 'd';
3527
  $message = 'Reverse proxy support was <code>' . $action_d . '</code>';
3528
 
3579
  *
3580
  * @return void
3581
  */
3582
+ public static function schedule_task($run_now = true)
3583
  {
3584
  $task_name = 'sucuriscan_scheduled_scan';
3585
 
3587
  wp_schedule_event(time() + 10, 'twicedaily', $task_name);
3588
  }
3589
 
3590
+ if ($run_now === true) {
3591
+ // Execute scheduled task after five minutes.
3592
+ wp_schedule_single_event(time() + 300, $task_name);
3593
+ }
3594
  }
3595
 
3596
  /**
3692
  * Generates an audit event log (to be sent later).
3693
  *
3694
  * @param integer $severity Importance of the event that will be reported, values from one to five.
 
3695
  * @param string $message The explanation of the event.
3696
  * @param boolean $internal Whether the event will be publicly visible or not.
3697
  * @return boolean TRUE if the event was logged in the monitoring service, FALSE otherwise.
3698
  */
3699
+ private static function report_event($severity = 0, $message = '', $internal = false)
3700
  {
3701
  $user = wp_get_current_user();
3702
  $username = false;
 
3703
  $remote_ip = self::get_remote_addr();
3704
 
3705
  // Identify current user in session.
3811
  */
3812
  public static function report_debug_event($message = '', $internal = false)
3813
  {
3814
+ return self::report_event(0, $message, $internal);
3815
  }
3816
 
3817
  /**
3823
  */
3824
  public static function report_notice_event($message = '', $internal = false)
3825
  {
3826
+ return self::report_event(1, $message, $internal);
3827
  }
3828
 
3829
  /**
3835
  */
3836
  public static function report_info_event($message = '', $internal = false)
3837
  {
3838
+ return self::report_event(2, $message, $internal);
3839
  }
3840
 
3841
  /**
3847
  */
3848
  public static function report_warning_event($message = '', $internal = false)
3849
  {
3850
+ return self::report_event(3, $message, $internal);
3851
  }
3852
 
3853
  /**
3859
  */
3860
  public static function report_error_event($message = '', $internal = false)
3861
  {
3862
+ return self::report_event(4, $message, $internal);
3863
  }
3864
 
3865
  /**
3871
  */
3872
  public static function report_critical_event($message = '', $internal = false)
3873
  {
3874
+ return self::report_event(5, $message, $internal);
3875
  }
3876
 
3877
  /**
3984
  } elseif ($event == 'scan_checksums') {
3985
  $event = 'core_integrity_checks';
3986
  $email_params['Force'] = true;
3987
+ $email_params['ForceHTML'] = true;
3988
+ } elseif ($event == 'available_updates') {
3989
+ $email_params['Force'] = true;
3990
+ $email_params['ForceHTML'] = true;
3991
  }
3992
 
3993
  $title = str_replace('_', "\x20", $event);
5048
  }
5049
 
5050
  /**
5051
+ * Alternative to the built-in PHP function http_build_query.
5052
+ *
5053
+ * Some PHP installations with different encoding or with different language
5054
+ * (German for example) might produce an unwanted behavior when building an
5055
+ * URL, because of this we decided to write our own URL query builder to
5056
+ * keep control of the output.
5057
+ *
5058
+ * @param array $params May be an array or object containing properties.
5059
+ * @return string Returns a URL-encoded string.
5060
+ */
5061
+ private static function buildQuery($params = array())
5062
+ {
5063
+ $trail = '';
5064
+
5065
+ foreach ($params as $param => $value) {
5066
+ $value = urlencode($value);
5067
+ $trail .= sprintf('&%s=%s', $param, $value);
5068
+ }
5069
+
5070
+ return substr($trail, 1);
5071
+ }
5072
+
5073
+ /**
5074
+ * Assign the communication protocol.
5075
+ *
5076
+ * @see https://developer.wordpress.org/reference/functions/wp_http_supports/
5077
+ * @see https://developer.wordpress.org/reference/functions/set_url_scheme/
5078
+ *
5079
+ * @param string $url Valid URL with or without protocol
5080
+ * @param string $protocol Optional protocol, we will get it from the config.
5081
+ * @return string Full URL with the proper protocol.
5082
+ */
5083
+ public static function apiUrlProtocol($url = '', $protocol = false)
5084
+ {
5085
+ $pattern = 'sucuri://'; /* Placeholder for HTTP protocol. */
5086
+
5087
+ if (strpos($url, $pattern) === 0) {
5088
+ if (!$protocol) {
5089
+ $protocol = SucuriScanOption::get_option(':api_protocol');
5090
+ }
5091
+
5092
+ $protocol = ($protocol === 'https') ? 'https' : 'http';
5093
+ $url = str_replace($pattern, '', $url);
5094
+ $url = sprintf('%s://%s', $protocol, $url);
5095
+ }
5096
+
5097
+ return $url;
5098
+ }
5099
+
5100
+ /**
5101
+ * Affected URLs by API protocol setting.
5102
+ *
5103
+ * These URLs are the ones that will be modified when the admin decides to
5104
+ * enable or disable the API communication protocol. If this option is enabled
5105
+ * these URLs will be queried using HTTPS and HTTP otherwise. Find an updated
5106
+ * list of the affected URLs using the Grep command like this:
5107
+ *
5108
+ * Note: The string that identifies each URL is a descriptive unique string used
5109
+ * to differentiate and easily select the URLs from the list. Make sure that
5110
+ * they are different among them all.
5111
+ *
5112
+ * @see grep -n 'sucuri://' sucuri.php
5113
+ * @return array API URLs affected by the HTTP protocol setting.
5114
+ */
5115
+ public static function ambiguousApiUrls()
5116
+ {
5117
+ return array(
5118
+ 'sucuriwp' => 'sucuri://wordpress.sucuri.net/api/',
5119
+ 'cproxywp' => 'sucuri://waf.sucuri.net/api',
5120
+ 'sitechck' => 'sucuri://sitecheck.sucuri.net/',
5121
+ 'wpssalts' => 'sucuri://api.wordpress.org/secret-key/1.1/salt/',
5122
+ 'wphashes' => 'sucuri://api.wordpress.org/core/checksums/1.0/',
5123
+ 'wpplugin' => 'sucuri://wordpress.org/plugins/PLUGIN/',
5124
+ 'plugindt' => 'sucuri://api.wordpress.org/plugins/info/1.0/PLUGIN.json',
5125
+ 'wpvfpath' => 'sucuri://core.svn.wordpress.org/tags/VERSION/FILEPATH',
5126
+ );
5127
+ }
5128
+
5129
+ /**
5130
+ * Send test HTTP request to the API URLs.
5131
+ *
5132
+ * @param string $unique Unique API URL selector.
5133
+ * @return object WordPress HTTP request response.
5134
+ */
5135
+ public static function debugApiCall($unique = null)
5136
+ {
5137
+ $urls = self::ambiguousApiUrls();
5138
+
5139
+ if (array_key_exists($unique, $urls)) {
5140
+ $params = array();
5141
+ $url = self::apiUrlProtocol($urls[$unique]);
5142
+
5143
+ if ($unique === 'sitechck') {
5144
+ $response = self::getSitecheckResults('sucuri.net', false);
5145
+ } else {
5146
+ if ($unique === 'cproxywp') {
5147
+ $params['v2'] = 'true';
5148
+ $params['a'] = 'test';
5149
+ } elseif ($unique === 'wpplugin') {
5150
+ $url = str_replace('/PLUGIN/', '/sucuri-scanner/', $url);
5151
+ } elseif ($unique === 'plugindt') {
5152
+ $url = str_replace('/PLUGIN.json', '/sucuri-scanner.json', $url);
5153
+ } elseif ($unique === 'wpvfpath') {
5154
+ $fpath = sprintf('/%s/wp-load.php', SucuriScan::site_version());
5155
+ $url = str_replace('/VERSION/FILEPATH', $fpath, $url);
5156
+ }
5157
+
5158
+ $response = self::apiCall($url, 'GET', $params);
5159
+ }
5160
+
5161
+ if ($response) {
5162
+ if ($unique === 'sucuriwp'
5163
+ && array_key_exists('status', $response)
5164
+ && array_key_exists('action', $response)
5165
+ && array_key_exists('output', $response)
5166
+ && is_numeric($response['status'])
5167
+ ) {
5168
+ return array('unique' => $unique, 'output' => 'OK');
5169
+ } elseif ($unique === 'cproxywp'
5170
+ && array_key_exists('status', $response)
5171
+ && array_key_exists('action', $response)
5172
+ && array_key_exists('output', $response)
5173
+ && is_numeric($response['status'])
5174
+ ) {
5175
+ return array('unique' => $unique, 'output' => 'OK');
5176
+ } elseif ($unique === 'sitechck'
5177
+ && array_key_exists('SCAN', $response)
5178
+ && array_key_exists('SYSTEM', $response)
5179
+ && array_key_exists('BLACKLIST', $response)
5180
+ ) {
5181
+ return array('unique' => $unique, 'output' => 'OK');
5182
+ } elseif ($unique === 'wpssalts'
5183
+ && strpos($response, 'AUTH_KEY')
5184
+ && strpos($response, 'AUTH_SALT')
5185
+ && strpos($response, 'SECURE_AUTH_KEY')
5186
+ ) {
5187
+ return array('unique' => $unique, 'output' => 'OK');
5188
+ } elseif ($unique === 'wphashes'
5189
+ && array_key_exists('checksums', $response)
5190
+ && is_array($response['checksums'])
5191
+ ) {
5192
+ return array('unique' => $unique, 'output' => 'OK');
5193
+ } elseif ($unique === 'wpplugin'
5194
+ && strpos($response, '<title>Sucuri Security')
5195
+ && strpos($response, 'wordpress.org/plugin/sucuri-scanner')
5196
+ ) {
5197
+ return array('unique' => $unique, 'output' => 'OK');
5198
+ } elseif ($unique === 'plugindt'
5199
+ && array_key_exists('slug', $response)
5200
+ && $response['slug'] === 'sucuri-scanner'
5201
+ ) {
5202
+ return array('unique' => $unique, 'output' => 'OK');
5203
+ } elseif ($unique === 'wpvfpath'
5204
+ && strpos($response, 'ABSPATH')
5205
+ && strpos($response, 'wp_die')
5206
+ ) {
5207
+ return array('unique' => $unique, 'output' => 'OK');
5208
+ }
5209
+ }
5210
+ }
5211
+
5212
+ return array('unique' => $unique, 'output' => 'ERROR');
5213
+ }
5214
+
5215
+ /**
5216
+ * Communicates with a remote URL and retrieves its content.
5217
  *
5218
+ * Curl is a reflective object-oriented programming language for interactive
5219
+ * web applications whose goal is to provide a smoother transition between
5220
+ * formatting and programming. It makes it possible to embed complex objects
5221
+ * in simple documents without needing to switch between programming
5222
+ * languages or development platforms.
5223
+ *
5224
+ * Using Curl instead of the custom WordPress HTTP functions allow us to
5225
+ * control the functionality at 100% without expecting breaking changes in
5226
+ * newer versions of the code. For exampe, as of WordPress 4.6.x the result
5227
+ * of executing the functions prefixed with "wp_remote_" returns an object
5228
+ * WP_HTTP_Requests_Response that is not compatible with older implementations
5229
+ * of the plugin.
5230
+ *
5231
+ * @see https://secure.php.net/manual/en/book.curl.php
5232
  *
5233
  * @param string $url The target URL where the request will be sent.
5234
  * @param string $method HTTP method that will be used to send the request.
5235
+ * @param array $params Parameters for the request defined in an associative array.
5236
+ * @param array $args Request arguments like the timeout, headers, cookies, etc.
5237
  * @return array Response object after the HTTP request is executed.
5238
  */
5239
  private static function apiCall($url = '', $method = 'GET', $params = array(), $args = array())
5240
  {
5241
+ if ($url
5242
+ && function_exists('curl_init')
5243
+ && ($method === 'GET' || $method === 'POST')
5244
+ ) {
5245
+ $curl = curl_init();
5246
+ $url = self::apiUrlProtocol($url);
5247
+ $timeout = self::requestTimeout();
5248
 
5249
+ if (is_array($args) && isset($args['timeout'])) {
5250
+ $timeout = $args['timeout'];
5251
+ }
 
 
 
 
 
 
 
 
 
 
5252
 
5253
+ // Add random request parameter to avoid request reset.
5254
+ if (!empty($params) && !array_key_exists('time', $params)) {
5255
+ $params['time'] = time();
 
5256
  }
 
5257
 
5258
+ if ($method === 'GET'
5259
+ && is_array($params)
5260
+ && !empty($params)
5261
+ ) {
5262
+ $url .= '?' . self::buildQuery($params);
5263
+ }
5264
 
5265
+ curl_setopt($curl, CURLOPT_URL, $url);
5266
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
5267
+ curl_setopt($curl, CURLOPT_USERAGENT, self::userAgent());
5268
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
5269
+ curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, $timeout);
5270
+ curl_setopt($curl, CURLOPT_TIMEOUT, $timeout * 2);
5271
+ curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
5272
+ curl_setopt($curl, CURLOPT_MAXREDIRS, 2);
5273
+
5274
+ if ($method === 'POST') {
5275
+ curl_setopt($curl, CURLOPT_POST, true);
5276
+ curl_setopt($curl, CURLOPT_POSTFIELDS, self::buildQuery($params));
5277
  }
5278
 
5279
+ if (self::verifySslCert()) {
5280
+ curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
5281
+ curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
5282
+ } else {
5283
+ curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
5284
+ curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
5285
+ }
5286
+
5287
+ $output = curl_exec($curl);
5288
+ $headers = curl_getinfo($curl);
5289
+
5290
+ curl_close($curl);
5291
+
5292
+ if (array_key_exists('http_code', $headers)
5293
+ && $headers['http_code'] === 200
5294
+ && !empty($output)
5295
+ ) {
5296
+ $result = @json_decode($output, true);
5297
+
5298
+ if ($result) {
5299
+ return $result;
5300
+ }
5301
+
5302
+ return $output;
5303
+ }
5304
  }
5305
 
5306
+ return false;
5307
  }
5308
 
5309
  /**
5372
  $option_name = ':cloudproxy_apikey';
5373
  $api_key = self::get_option($option_name);
5374
 
 
 
 
 
 
 
 
 
 
 
5375
  // Check the validity of the API key.
5376
  $match = self::isValidCloudproxyKey($api_key, true);
5377
 
5471
  }
5472
 
5473
  /**
5474
+ * Determine whether an API response was successful or not checking the expected
5475
+ * generic variables and types, in case of an error a notification will appears
5476
+ * in the administrator panel explaining the result of the operation.
5477
  *
5478
+ * @param array $response HTTP response after API endpoint execution.
5479
+ * @param boolean $enqueue Add the log to the local queue on a failure.
5480
+ * @return boolean False if the API call failed, true otherwise.
 
5481
  */
5482
+ private static function handleResponse($response = array(), $enqueue = true)
5483
  {
5484
+ if ($response !== false) {
5485
+ if (is_array($response)
5486
+ && array_key_exists('status', $response)
5487
+ && intval($response['status']) === 1
5488
+ ) {
5489
+ return true;
5490
+ }
 
 
 
 
 
 
 
 
 
 
 
 
5491
 
5492
+ if (is_array($response)
5493
+ && array_key_exists('messages', $response)
5494
+ && !empty($response['messages'])
5495
+ ) {
5496
+ return self::handleErrorResponse($response, $enqueue);
5497
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5498
  }
5499
 
5500
  return false;
5533
  */
5534
  private static function handleErrorResponse($response = array(), $enqueue = true)
5535
  {
5536
+ $msg = 'Unknown error, there is no more information.';
5537
 
5538
+ if (is_array($response)
5539
+ && array_key_exists('messages', $response)
5540
+ && !empty($response['messages'])
5541
+ ) {
5542
+ $msg = implode(".\x20", $response['messages']);
5543
+ $raw = $msg; /* Keep a copy of the original message. */
 
5544
 
5545
+ // Special response for invalid API keys.
5546
+ if (stripos($raw, 'log file not found') !== false) {
5547
+ $key = SucuriScanOption::get_option(':api_key');
5548
+ $msg .= '; this generally happens when you add an invalid API '
5549
+ . 'key, the key will be deleted automatically to hide these w'
5550
+ . 'arnings, if you want to recover it go to the settings page'
5551
+ . ' and use the recover button to send the key to your email '
5552
+ . 'address: ' . SucuriScan::escape($key);
5553
 
5554
+ SucuriScanOption::delete_option(':api_key');
5555
+ }
 
 
 
5556
 
5557
+ // Special response for invalid CloudProxy API keys.
5558
+ if (stripos($raw, 'wrong api key') !== false) {
5559
+ $key = SucuriScanOption::get_option(':cloudproxy_apikey');
5560
+ $msg .= '; invalid CloudProxy API key: ' . SucuriScan::escape($key);
 
5561
 
5562
+ SucuriScanInterface::error($msg);
5563
+ $msg = ''; /* Force premature error message. */
5564
 
5565
+ SucuriScanOption::delete_option(':cloudproxy_apikey');
5566
+ SucuriScanOption::setAddrHeader('REMOTE_ADDR');
5567
+ SucuriScanOption::setRevProxy('disable');
5568
+ }
 
 
 
 
 
 
 
5569
 
5570
+ // Stop SSL peer verification on connection failures.
5571
+ if (stripos($raw, 'no alternative certificate')
5572
+ || stripos($raw, 'error setting certificate')
5573
+ || stripos($raw, 'SSL connect error')
5574
+ ) {
5575
+ SucuriScanOption::update_option(':verify_ssl_cert', 'false');
5576
 
5577
+ $msg .= 'There were some issues with the SSL certificate eith'
5578
+ . 'er in this server or with the remote API service. The auto'
5579
+ . 'matic verification of the certificates has been deactivate'
5580
+ . 'd to reduce the noise during the execution of the HTTP req'
5581
+ . 'uests.';
5582
+ }
5583
 
5584
+ // Check if the MX records as missing for API registration.
5585
+ if (strpos($raw, 'Invalid email') !== false) {
5586
+ $msg = 'Email has an invalid format, or the host '
5587
+ . 'associated to the email has no MX records.';
 
 
 
 
 
 
5588
  }
5589
+ }
5590
 
5591
+ if (!empty($msg) && $enqueue) {
5592
+ SucuriScanInterface::error($msg);
5593
  }
5594
 
5595
+ return false;
5596
  }
5597
 
5598
  /**
5614
  ), false);
5615
 
5616
  if (self::handleResponse($response)) {
5617
+ self::setPluginKey($response['output']['api_key']);
5618
+
5619
  SucuriScanEvent::schedule_task();
5620
  SucuriScanEvent::notify_event('plugin_change', 'Site registered and API key generated');
5621
  SucuriScanInterface::info('The API key for your site was successfully generated and saved.');
5643
 
5644
  if (self::handleResponse($response)) {
5645
  SucuriScanEvent::notify_event('plugin_change', 'API key recovered for domain: ' . $clean_domain);
5646
+ SucuriScanInterface::info($response['output']['message']);
5647
 
5648
  return true;
5649
  }
5739
 
5740
  // If success continue with the retrieval of the logs data.
5741
  if (self::handleResponse($response)) {
5742
+ return self::getLogs($response['total_entries']);
5743
  }
5744
 
5745
  return false;
5759
  ));
5760
 
5761
  if (self::handleResponse($response)) {
5762
+ $response['output_data'] = array();
5763
  $log_pattern = '/^([0-9\-]+) ([0-9:]+) (\S+) : (.+)/';
5764
  $extra_pattern = '/(.+ \(multiple entries\):) (.+)/';
5765
  $generic_pattern = '/^@?([A-Z][a-z]{3,7}): ([^;]+; )?(.+)/';
5766
  $auth_pattern = '/^User authentication (succeeded|failed): ([^<;]+)/';
5767
 
5768
+ foreach ($response['output'] as $log) {
5769
  if (@preg_match($log_pattern, $log, $log_match)) {
5770
  $log_data = array(
5771
  'event' => 'notice',
5834
  $log_data['file_list_count'] = count($log_data['file_list']);
5835
  }
5836
 
5837
+ $response['output_data'][] = $log_data;
5838
  }
5839
  }
5840
 
5841
+ return $response;
5842
  }
5843
 
5844
  return false;
5889
  {
5890
  $audit_logs = self::getLogs($lines);
5891
 
5892
+ if (is_array($audit_logs)
5893
+ && array_key_exists('total_entries', $audit_logs)
5894
+ && array_key_exists('output_data', $audit_logs)
5895
+ && !empty($audit_logs['output_data'])
5896
  ) {
5897
  // Data structure that will be returned.
5898
  $report = array(
5917
  }
5918
 
5919
  // Collect information for each report chart.
5920
+ foreach ($audit_logs['output_data'] as $event) {
5921
  $report['total_events'] += 1;
5922
 
5923
  // Increment the number of events for this event type.
6099
  *
6100
  * [1] https://sitecheck.sucuri.net/
6101
  *
6102
+ * @param string $domain The clean version of the website's domain.
6103
+ * @param boolean $clear Request the results from a fresh scan or not.
6104
+ * @return object JSON encoded website scan results.
6105
  */
6106
+ public static function getSitecheckResults($domain = '', $clear = true)
6107
  {
6108
  if (!empty($domain)) {
6109
+ $params = array();
6110
+ $timeout = (int) SucuriScanOption::get_option(':sitecheck_timeout');
6111
+ $params['scan'] = $domain;
6112
+ $params['fromwp'] = 2;
6113
+ $params['json'] = 1;
6114
+
6115
+ // Request a fresh scan or not.
6116
+ if ($clear === true) {
6117
+ $params['clear'] = 1;
6118
+ }
6119
+
6120
  $response = self::apiCall(
6121
+ 'sucuri://sitecheck.sucuri.net/',
6122
  'GET',
6123
+ $params,
 
 
 
 
 
6124
  array(
6125
  'assoc' => true,
6126
+ 'timeout' => $timeout,
6127
  )
6128
  );
6129
 
6130
+ return $response;
 
 
6131
  }
6132
 
6133
  return false;
6167
  $data_set['malware_docs'] = $match[2];
6168
  }
6169
 
6170
+ $data_set['malware_payload'] = trim($malware_parts[1]);
 
 
 
 
 
6171
  }
6172
 
6173
  return $data_set;
6185
  public static function getNewSecretKeys()
6186
  {
6187
  $pattern = self::secret_key_pattern();
6188
+ $response = self::apiCall('sucuri://api.wordpress.org/secret-key/1.1/salt/', 'GET');
6189
 
6190
+ if ($response && @preg_match_all($pattern, $response, $match)) {
6191
  $new_keys = array();
6192
 
6193
  foreach ($match[1] as $i => $value) {
6210
  */
6211
  public static function getOfficialChecksums($version = 0)
6212
  {
6213
+ $language = SucuriScanOption::get_option(':language');
6214
+ $response = self::apiCall(
6215
+ 'sucuri://api.wordpress.org/core/checksums/1.0/',
6216
+ 'GET',
6217
+ array(
6218
+ 'version' => $version,
6219
+ 'locale' => $language,
6220
+ )
6221
+ );
6222
 
6223
  if ($response) {
6224
+ if (array_key_exists('checksums', $response)
6225
+ && !empty($response['checksums'])
 
 
 
 
 
 
6226
  ) {
6227
+ if (count((array) $response['checksums']) <= 1
6228
+ && array_key_exists($version, $response['checksums'])
6229
  ) {
6230
+ return $response['checksums'][$version];
6231
  } else {
6232
+ return $response['checksums'];
 
 
 
 
 
6233
  }
6234
  }
6235
  }
6262
  // Get the plugin's basic information from WordPress transient data.
6263
  $plugins = get_plugins();
6264
  $pattern = '/^http(s)?:\/\/wordpress\.org\/plugins\/(.*)\/$/';
6265
+ $wp_market = 'sucuri://wordpress.org/plugins/%s/';
6266
 
6267
  // Loop through each plugin data and complement its information with more attributes.
6268
  foreach ($plugins as $plugin_path => $plugin_data) {
6293
 
6294
  if (isset($plugin_path_parts[0])) {
6295
  $possible_repository = sprintf($wp_market, $plugin_path_parts[0]);
6296
+ $possible_repository = SucuriScanAPI::apiUrlProtocol($possible_repository);
6297
  $resp = wp_remote_head($possible_repository);
6298
 
6299
  if (!is_wp_error($resp)
6352
  public static function getRemotePluginData($plugin = '')
6353
  {
6354
  if (!empty($plugin)) {
6355
+ $url = sprintf('sucuri://api.wordpress.org/plugins/info/1.0/%s.json', $plugin);
6356
  $response = self::apiCall($url, 'GET');
6357
 
6358
  if ($response) {
6359
+ return $response;
 
 
6360
  }
6361
  }
6362
 
6383
  $version = self::site_version();
6384
  }
6385
 
6386
+ $url = sprintf('sucuri://core.svn.wordpress.org/tags/%s/%s', $version, $filepath);
6387
  $response = self::apiCall($url, 'GET');
6388
 
6389
  if ($response) {
6390
+ return $response;
 
 
 
 
 
6391
  }
6392
  }
6393
 
6449
  }
6450
 
6451
  // Check whether the email notifications will be sent in HTML or Plain/Text.
6452
+ if (self::prettify_mails() || (isset($data_set['ForceHTML']) && $data_set['ForceHTML'])) {
6453
  $headers = array( 'content-type: text/html' );
6454
  $data_set['PrettifyType'] = 'pretty';
6455
+ unset($data_set['ForceHTML']);
6456
  } else {
6457
  $message = strip_tags($message);
6458
  }
6688
  return false;
6689
  }
6690
 
6691
+ /**
6692
+ * Check if the ads in the sidebar are visible or not.
6693
+ *
6694
+ * @return boolean True if the ads must be hidden.
6695
+ */
6696
+ private static function noAdvertisement()
6697
+ {
6698
+ return (bool) (
6699
+ defined('SUCURISCAN_HIDE_ADS')
6700
+ && SUCURISCAN_HIDE_ADS === true
6701
+ );
6702
+ }
6703
+
6704
  /**
6705
  * Gather and generate the information required globally by all the template files.
6706
  *
6707
+ * @param string $target Scenario where the params are going to be replaced.
6708
+ * @param array $params Key-value array with variables shared with the template.
6709
+ * @return array Additional list of variables for the template files.
6710
  */
6711
+ private static function sharedParams($target = null, $params = array())
6712
  {
6713
  $params = is_array($params) ? $params : array();
6714
 
6720
  $params['PageNonce'] = wp_create_nonce('sucuriscan_page_nonce');
6721
  $params['PageStyleClass'] = isset($params['PageStyleClass']) ? $params['PageStyleClass'] : 'base';
6722
  $params['CleanDomain'] = self::get_domain();
 
6723
 
6724
  // Get a list of admin users for the API key generation.
6725
+ if ($target === 'modal' /* Get API key if required */
6726
+ && SucuriScanAPI::getPluginKey() === false
6727
+ ) {
6728
  $admin_users = SucuriScan::get_users_for_api_key();
6729
  $params['AdminEmails'] = self::selectOptions($admin_users);
6730
  }
6731
 
6732
  // Hide the advertisements from the layout.
6733
+ if (self::noAdvertisement()) {
6734
  $params['LayoutType'] = 'onecolumn';
6735
  $params['AdsVisibility'] = 'hidden';
6736
  $params['ReviewNavbarButton'] = 'visible';
6773
  $url_path .= '_' . strtolower($page);
6774
  }
6775
 
6776
+ if (SucuriScan::is_multisite()) {
6777
+ $url_path = str_replace(
6778
+ 'wp-admin/network/admin-ajax.php',
6779
+ 'wp-admin/admin-ajax.php',
6780
+ $url_path
6781
+ );
6782
+ }
6783
+
6784
  return $url_path;
6785
  }
6786
 
6819
  }
6820
 
6821
  foreach ($sub_pages as $sub_page_func => $sub_page_title) {
6822
+ if ($sub_page_func === 'sucuriscan_scanner'
6823
+ && SucuriScanSiteCheck::isDisabled()
6824
  ) {
6825
  continue;
6826
  }
6871
  {
6872
  $params = is_array($params) ? $params : array();
6873
 
6874
+ $params = self::sharedParams('base', $params);
6875
  $params['PageContent'] = $html;
6876
 
6877
  return self::getTemplate('base', $params);
6949
  */
6950
  public static function getSection($template = '', $params = array())
6951
  {
6952
+ $params = self::sharedParams('section', $params);
6953
 
6954
  return self::getTemplate($template, $params, 'section');
6955
  }
6990
 
6991
  $params['Visibility'] = 'sucuriscan-' . $params['Visibility'];
6992
  $params['Identifier'] = 'sucuriscan-' . $template . '-modal';
6993
+ $params = self::sharedParams('modal', $params);
6994
 
6995
  return self::getTemplate('modalwindow', $params, 'section');
6996
  }
7075
  }
7076
 
7077
  $html_links .= sprintf(
7078
+ '<li><a href="%s&paged=%d%s" class="%s" data-page="%d">%s</a></li>',
7079
  $base_url,
7080
  $j,
7081
  $extra_url,
7082
  $link_class,
7083
+ $j,
7084
  $j
7085
  );
7086
  }
7526
  $_SERVER['SUCURIREAL_REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
7527
  $_SERVER['REMOTE_ADDR'] = SucuriScan::get_remote_addr();
7528
  }
7529
+
7530
+ SucuriScanEvent::schedule_task(false);
7531
  }
7532
 
7533
  /**
7536
  *
7537
  * @return void
7538
  */
7539
+ public static function enqueueScripts()
7540
  {
7541
  $asset_version = '';
7542
 
7562
  *
7563
  * @return void
7564
  */
7565
+ public static function addInterfaceMenu()
7566
  {
7567
  global $sucuriscan_pages;
7568
 
7583
 
7584
  foreach ($sucuriscan_pages as $sub_page_func => $sub_page_title) {
7585
  if ($sub_page_func == 'sucuriscan_scanner'
7586
+ && SucuriScanSiteCheck::isDisabled()
7587
  ) {
7588
  continue;
7589
  }
7610
  *
7611
  * @return void
7612
  */
7613
+ public static function handleOldPlugins()
7614
  {
7615
  if (class_exists('SucuriScanFileInfo')) {
7616
  $file_info = new SucuriScanFileInfo();
7630
  deactivate_plugins($plugin);
7631
  }
7632
 
7633
+ $file_info->remove_directory_tree($plugin_directory);
7634
  }
7635
  }
7636
  }
7642
  *
7643
  * @return void
7644
  */
7645
+ public static function createStorageFolder()
7646
  {
7647
  $directory = SucuriScan::datastore_folder_path();
7648
 
7683
  }
7684
  }
7685
 
7686
+ /**
7687
+ * Do something if the plugin was updated.
7688
+ *
7689
+ * Check if an option exists with the version number of the plugin, if the
7690
+ * number is different than the number defined in the constant that comes
7691
+ * with this code then we can consider this as an update, in which case we
7692
+ * will execute certain actions and/or display some messages.
7693
+ *
7694
+ * @return void
7695
+ */
7696
+ public static function noticeAfterUpdate()
7697
+ {
7698
+ $version = SucuriScanOption::get_option(':plugin_version');
7699
+
7700
+ // Use simple comparison to force type cast.
7701
+ if ($version != SUCURISCAN_VERSION) {
7702
+ /**
7703
+ * Check if the API communication has been disabled due to issues
7704
+ * with the previous version of the code, in this case we will
7705
+ * display a message at the top of the admin dashboard suggesting
7706
+ * the user to enable it once again expecting to see have a better
7707
+ * performance with the new code.
7708
+ */
7709
+ if (SucuriScanOption::is_disabled(':api_service')) {
7710
+ self::info(
7711
+ 'API service communication is disabled, if you just updated '
7712
+ . 'the plugin this might be a good opportunity to test this '
7713
+ . 'feature once again with the new code. Enable it again from '
7714
+ . 'the "API Service" panel located in the settings page.'
7715
+ );
7716
+ }
7717
+
7718
+ // Update the version number in the plugin settings.
7719
+ SucuriScanOption::update_option(':plugin_version', SUCURISCAN_VERSION);
7720
+ }
7721
+ }
7722
+
7723
  /**
7724
  * Check whether a user has the permissions to see a page from the plugin.
7725
  *
7766
  * @param string $message The message that will be printed in the alert.
7767
  * @return void
7768
  */
7769
+ private static function adminNotice($type = 'updated', $message = '')
7770
  {
7771
  $display_notice = true;
7772
 
7789
 
7790
  // Display the HTML notice to the current user.
7791
  if ($display_notice === true && !empty($message)) {
7792
+ if (defined('SUCURISCAN_THROW_EXCEPTIONS')
7793
+ && SUCURISCAN_THROW_EXCEPTIONS === true
7794
+ ) {
7795
+ $number = (string) crc32($type);
7796
+ $code = (int) substr($number, 0, 3);
7797
+ $message = str_replace(
7798
+ '<b>Sucuri:</b>',
7799
+ ($type === 'error' ? 'Error:' : 'Info:'),
7800
+ $message
7801
+ );
7802
+
7803
+ throw new Exception($message, $code);
7804
+ }
7805
+
7806
  echo SucuriScanTemplate::getSection(
7807
  'notification-admin',
7808
  array(
7822
  */
7823
  public static function error($error_msg = '')
7824
  {
7825
+ self::adminNotice('error', '<b>Sucuri:</b> ' . $error_msg);
7826
  }
7827
 
7828
  /**
7833
  */
7834
  public static function info($info_msg = '')
7835
  {
7836
+ self::adminNotice('updated', '<b>Sucuri:</b> ' . $info_msg);
7837
+ }
7838
+
7839
+ /**
7840
+ * Decide if the API key generator needs to be visible.
7841
+ *
7842
+ * Once the user activates the plugin an information bar will appear at the
7843
+ * top of the admin interface advising him to generate an unique API key for
7844
+ * his website, this will allow him to activate additional features of the
7845
+ * plugin that are only available while the API key is present.
7846
+ *
7847
+ * If the user doesn't generates the key right after the activation in the
7848
+ * plugins page we have to keep the information bar visible in certain pages
7849
+ * to remind him. This is, the home page of the admin dashboard, the plugins
7850
+ * page, and any of the pages associated to the plugin.
7851
+ *
7852
+ * @return boolean Display the API key generator button or not.
7853
+ */
7854
+ private static function displayNoticesHere()
7855
+ {
7856
+ global $sucuriscan_pages;
7857
+
7858
+ $page = SucuriScanRequest::get('page');
7859
+ $script = (string) @$_SERVER['SCRIPT_NAME'];
7860
+ $visibility = array(
7861
+ '/wp-admin/index.php',
7862
+ '/wp-admin/plugins.php',
7863
+ );
7864
+
7865
+ if ($page && array_key_exists($page, $sucuriscan_pages)) {
7866
+ return true;
7867
+ }
7868
+
7869
+ if (in_array($script, $visibility)) {
7870
+ return true;
7871
+ }
7872
+
7873
+ /**
7874
+ * Retry using a reverse name.
7875
+ *
7876
+ * People might choose to install WordPress in a sublevel of the
7877
+ * document root, this changes the structure of the script name
7878
+ * variable. To address this incompatibility we will iterate over all
7879
+ * the visible pages and check the reverse version of the string with
7880
+ * the reverse version of the script name, if the beginning of the
7881
+ * string matches then we will consider the page available.
7882
+ */
7883
+ $script = strrev($script);
7884
+
7885
+ foreach ($visibility as $visible) {
7886
+ $elbis = strrev($visible);
7887
+
7888
+ if (strpos($script, $elbis) === 0) {
7889
+ return true;
7890
+ }
7891
+ }
7892
+
7893
+ return false;
7894
  }
7895
 
7896
  /**
7903
  public static function setup_notice()
7904
  {
7905
  if (current_user_can('manage_options')
7906
+ && self::displayNoticesHere()
7907
  && !SucuriScanAPI::getPluginKey()
7908
  && SucuriScanRequest::post(':plugin_api_key') === false
7909
  && SucuriScanRequest::post(':recover_key') === false
8648
  /**
8649
  * Generate the HTML code for the firewall logs panel.
8650
  *
8651
+ * @return string The parsed-content of the firewall logs panel.
 
8652
  */
8653
+ function sucuriscan_firewall_auditlogs()
8654
  {
8655
  $date = date('Y-m-d');
8656
  $params = array();
9031
  }
9032
 
9033
  if ($fhandle) {
9034
+ $rules_str = "\n" . implode("\n", $deny_rules) . "\n";
9035
  $written = @fwrite($fhandle, $rules_str);
9036
  @fclose($fhandle);
9037
 
9138
  $file = str_replace('<', '', $file);
9139
  $file = str_replace('>', '', $file);
9140
 
9141
+ return sprintf(
9142
+ "<Files %s>\n"
9143
+ . " <IfModule !mod_authz_core.c>\n"
9144
+ . " Allow from all\n"
9145
+ . " </IfModule>\n"
9146
+ . " <IfModule mod_authz_core.c>\n"
9147
+ . " Require all granted\n"
9148
+ . " </IfModule>\n"
9149
+ . "</Files>\n",
9150
+ $file
9151
+ );
9152
  }
9153
 
9154
  public static function whitelist($file = '', $folder = '')
9175
  && is_readable($htaccess)
9176
  && is_writable($htaccess)
9177
  ) {
9178
+ $content = file_get_contents($htaccess);
9179
  $rules = self::whitelist_rule($file);
9180
  $content = str_replace($rules, '', $content);
9181
  @file_put_contents($htaccess, $content);
9185
  public static function get_whitelisted($folder = '')
9186
  {
9187
  $htaccess = self::htaccess($folder);
 
9188
 
9189
+ if (file_exists($htaccess)
9190
+ && is_readable($htaccess)
9191
+ ) {
9192
+ $content = file_get_contents($htaccess);
9193
+
9194
+ if (@preg_match_all('/<Files (\S+)>/', $content, $matches)) {
9195
+ return $matches[1];
9196
+ }
9197
  }
9198
 
9199
  return false;
9271
  'wp-content/uploads',
9272
  );
9273
 
9274
+ if (SucuriScanInterface::check_nonce()) {
9275
  // Add a new file to the hardening whitelist.
9276
  if ($fwhite = SucuriScanRequest::post(':hardening_whitelist')) {
9277
  $folder = SucuriScanRequest::post(':hardening_folder');
9298
 
9299
  SucuriScanInterface::info('Selected files were processed successfully');
9300
  }
9301
+ }
9302
 
9303
  // Read the access control file and retrieve the whitelisted files.
9304
  $counter = 0;
9349
  'Hardening.Title' => $title,
9350
  'Hardening.Description' => '',
9351
  'Hardening.Status' => 'unknown',
9352
+ 'Hardening.StatusVisibility' => 'visible',
9353
  'Hardening.FieldName' => '',
9354
  'Hardening.FieldValue' => '',
9355
  'Hardening.FieldAttributes' => '',
9387
  $template_variables['Hardening.UpdateMessage'] = '<p>' . $updatemsg . '</p>';
9388
  }
9389
 
9390
+ if ($status === 999) {
9391
+ $template_variables['Hardening.StatusVisibility'] = 'hidden';
9392
+ }
9393
+
9394
  return SucuriScanTemplate::getSnippet('hardening', $template_variables);
9395
  }
9396
 
9474
  $description .= "\x20\x20deny all;\n";
9475
  $description .= '}</pre>';
9476
 
9477
+ $description .= '<p>';
9478
+ $description .= 'If you need to unblock individual files like the one required
9479
+ to keep the TinyMCE plugin working which is located <em>(in the current
9480
+ version)</em> at <em>"/wp-includes/js/tinymce/wp-tinymce.php"</em> you may
9481
+ want to include a rule like this one, changing <em>"/path/to/file.php"</em>
9482
+ with the file path that you want to allow access relative to the document
9483
+ root.';
9484
+ $description .= '</p>';
9485
+
9486
+ $description .= "<pre class='code'>";
9487
+ $description .= "location = /path/to/file.php {\n";
9488
+ $description .= "\x20\x20allow all;\n";
9489
+ $description .= '}</pre>';
9490
+
9491
  $description .= '<p class="sucuriscan-hidden">';
9492
 
9493
  return sucuriscan_harden_status(
9824
  */
9825
  function sucuriscan_harden_adminuser()
9826
  {
 
 
9827
  $upmsg = null;
9828
  $user_query = new WP_User_Query(array(
9829
  'search' => 'admin',
10058
 
10059
  if (SucuriScanInterface::check_nonce()) {
10060
  sucuriscan_core_files_ajax();
10061
+ sucuriscan_audit_logs_ajax();
10062
  }
10063
 
10064
  wp_die();
10072
  */
10073
  function sucuriscan_auditlogs()
10074
  {
10075
+ $params = array();
10076
+ $params['PageTitle'] = 'Audit Logs';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10077
 
10078
+ if (SucuriScanOption::get_option(':api_key')) {
10079
+ return SucuriScanTemplate::getSection('integrity-auditlogs', $params);
10080
+ }
 
 
10081
 
10082
+ return '' /* Empty string */;
10083
+ }
 
 
 
10084
 
10085
+ function sucuriscan_audit_logs_ajax()
10086
+ {
10087
+ if (SucuriScanRequest::post('form_action') == 'get_audit_logs') {
10088
+ $response = array();
10089
+ $response['count'] = 0;
10090
+ $response['enable_report'] = false;
10091
+
10092
+ // Initialize the values for the pagination.
10093
+ $max_per_page = SUCURISCAN_AUDITLOGS_PER_PAGE;
10094
+ $page_number = SucuriScanTemplate::pageNumber();
10095
+ $logs_limit = ($page_number * $max_per_page);
10096
+
10097
+ ob_start();
10098
+ $audit_logs = SucuriScanAPI::getLogs($logs_limit);
10099
+ $errors = ob_get_contents();
10100
+ ob_end_clean();
10101
+
10102
+ if (!empty($errors)) {
10103
+ header('Content-Type: text/html; charset=UTF-8');
10104
+ print($errors);
10105
+ exit(0);
10106
+ }
10107
+
10108
+ if ($audit_logs) {
10109
+ $counter_i = 0;
10110
+ $total_items = count($audit_logs->output_data);
10111
+ $iterator_start = ($page_number - 1) * $max_per_page;
10112
+
10113
+ if (property_exists($audit_logs, 'total_entries')
10114
+ && $audit_logs->total_entries >= $max_per_page
10115
+ && SucuriScanOption::is_disabled(':audit_report')
10116
+ ) {
10117
+ $response['enable_report'] = true;
10118
  }
10119
 
10120
+ for ($i = $iterator_start; $i < $total_items; $i++) {
10121
+ if ($counter_i > $max_per_page) {
10122
+ break;
10123
+ }
10124
+
10125
+ if (isset($audit_logs->output_data[ $i ])) {
10126
+ $audit_log = $audit_logs->output_data[ $i ];
10127
+
10128
+ $css_class = ($counter_i % 2 === 0) ? '' : 'alternate';
10129
+ $snippet_data = array(
10130
+ 'AuditLog.CssClass' => $css_class,
10131
+ 'AuditLog.Event' => $audit_log['event'],
10132
+ 'AuditLog.EventTitle' => ucfirst($audit_log['event']),
10133
+ 'AuditLog.Timestamp' => $audit_log['timestamp'],
10134
+ 'AuditLog.DateTime' => SucuriScan::datetime($audit_log['timestamp']),
10135
+ 'AuditLog.Account' => $audit_log['account'],
10136
+ 'AuditLog.Username' => $audit_log['username'],
10137
+ 'AuditLog.RemoteAddress' => $audit_log['remote_addr'],
10138
+ 'AuditLog.Message' => $audit_log['message'],
10139
+ 'AuditLog.Extra' => '',
10140
+ );
10141
+
10142
+ // Print every file_list information item in a separate table.
10143
+ if ($audit_log['file_list']) {
10144
+ $css_scrollable = $audit_log['file_list_count'] > 10 ? 'sucuriscan-list-as-table-scrollable' : '';
10145
+ $snippet_data['AuditLog.Extra'] .= '<ul class="sucuriscan-list-as-table ' . $css_scrollable . '">';
10146
+
10147
+ foreach ($audit_log['file_list'] as $log_extra) {
10148
+ $snippet_data['AuditLog.Extra'] .= '<li>' . SucuriScan::escape($log_extra) . '</li>';
10149
+ }
10150
 
10151
+ $snippet_data['AuditLog.Extra'] .= '</ul>';
 
 
 
 
 
10152
  }
 
 
10153
 
10154
+ $response['content'] .= SucuriScanTemplate::getSnippet('integrity-auditlogs', $snippet_data);
10155
+ $counter_i += 1;
10156
+ }
10157
  }
 
10158
 
10159
+ $response['count'] = $counter_i;
 
10160
 
10161
+ if ($total_items > 1) {
10162
+ $max_pages = ceil($audit_logs->total_entries / $max_per_page);
10163
 
10164
+ if ($max_pages > SUCURISCAN_MAX_PAGINATION_BUTTONS) {
10165
+ $max_pages = SUCURISCAN_MAX_PAGINATION_BUTTONS;
10166
+ }
10167
 
10168
+ if ($max_pages > 1) {
10169
+ $response['pagination'] = SucuriScanTemplate::pagination(
10170
+ SucuriScanTemplate::getUrl(),
10171
+ ($max_per_page * $max_pages),
10172
+ $max_per_page
10173
+ );
10174
+ }
10175
  }
10176
  }
 
10177
 
10178
+ header('Content-Type: application/json');
10179
+ print(json_encode($response));
10180
+ exit(0);
10181
+ }
10182
  }
10183
 
10184
  /**
10324
  {
10325
  $affected_files = 0;
10326
  $site_version = SucuriScan::site_version();
10327
+ $integrity_is_enabled = SucuriScanOption::is_enabled(':scan_checksums');
10328
 
10329
  $params = array(
10330
  'CoreFiles.List' => '',
10334
  'CoreFiles.GoodVisibility' => 'visible',
10335
  'CoreFiles.FailureVisibility' => 'hidden',
10336
  'CoreFiles.NotFixableVisibility' => 'hidden',
10337
+ 'CoreFiles.DisabledVisibility' => 'hidden',
10338
  );
10339
 
10340
+ if ($integrity_is_enabled !== true) {
10341
+ $params['CoreFiles.GoodVisibility'] = 'hidden';
10342
+ $params['CoreFiles.DisabledVisibility'] = 'visible';
10343
+ }
10344
+
10345
+ if ($site_version && $integrity_is_enabled) {
10346
  // Check if there are added, removed, or modified files.
10347
  $latest_hashes = sucuriscan_check_core_integrity($site_version);
10348
+ $language = SucuriScanOption::get_option(':language');
10349
  $params['CoreFiles.RemoteChecksumsURL'] =
10350
  'https://api.wordpress.org/core/checksums/1.0/'
10351
+ . '?version=' . $site_version . '&locale=' . $language;
10352
 
10353
  if ($latest_hashes) {
10354
  $cache = new SucuriScanCache('integrity');
10447
  SucuriScanEvent::notify_event('plugin_change', 'Filesystem scan forced at: ' . date('r'));
10448
  SucuriScanEvent::filesystem_scan(true);
10449
  sucuriscan_core_files_data(true);
10450
+ sucuriscan_posthack_updates_content(true);
10451
  }
10452
 
10453
  // Restore, Remove, Mark as fixed the core files.
10489
  case 'restore':
10490
  $file_content = SucuriScanAPI::getOriginalCoreFile($file_path);
10491
  if ($file_content) {
10492
+ $basedir = dirname($full_path);
10493
+ if (!file_exists($basedir)) {
10494
+ @mkdir($basedir, 0755, true);
10495
+ }
10496
+ if (file_exists($basedir)) {
10497
+ $restored = @file_put_contents($full_path, $file_content);
10498
+ $files_processed += ($restored ? 1 : 0);
10499
+ $files_affected[] = $full_path;
10500
+ }
10501
  }
10502
  break;
10503
  case 'fixed':
10574
  */
10575
  function sucuriscan_get_integrity_tree($dir = './', $recursive = false)
10576
  {
 
 
10577
  $file_info = new SucuriScanFileInfo();
10578
  $file_info->ignore_files = false;
10579
  $file_info->ignore_directories = false;
10768
  $process_form = sucuriscan_posthack_process_form();
10769
 
10770
  // Page pseudo-variables initialization.
10771
+ $params['PageTitle'] = 'Post-Hack';
10772
+ $params['UpdateSecretKeys'] = sucuriscan_update_secret_keys($process_form);
10773
+ $params['ResetPassword'] = sucuriscan_posthack_users($process_form);
10774
+ $params['ResetPlugins'] = sucuriscan_posthack_plugins($process_form);
10775
+ $params['AvailableUpdates'] = sucuriscan_posthack_updates();
 
10776
 
10777
  echo SucuriScanTemplate::getTemplate('posthack', $params);
10778
  }
10788
 
10789
  if (SucuriScanInterface::check_nonce()) {
10790
  sucuriscan_posthack_plugins_ajax();
10791
+ sucuriscan_posthack_updates_ajax();
10792
  }
10793
 
10794
  wp_die();
11066
  'ResetPlugin.CssClass' => $css_class,
11067
  'ResetPlugin.Disabled' => $input_disabled,
11068
  'ResetPlugin.PluginPath' => $plugin_path,
11069
+ 'ResetPlugin.Repository' => $plugin_data['Repository'],
11070
  'ResetPlugin.Plugin' => SucuriScan::excerpt($plugin_data['Name'], 35),
11071
  'ResetPlugin.Version' => $plugin_data['Version'],
11072
  'ResetPlugin.Type' => $plugin_data['PluginType'],
11084
  }
11085
 
11086
  /**
11087
+ * Find and list available updates for plugins and themes.
 
 
 
11088
  *
 
11089
  * @return void
11090
  */
11091
+ function sucuriscan_posthack_updates()
11092
  {
11093
+ $params = array();
 
 
 
 
 
 
 
 
 
11094
 
11095
+ return SucuriScanTemplate::getSection('posthack-updates', $params);
11096
+ }
11097
 
11098
+ /**
11099
+ * Retrieve the information for the available updates.
11100
+ *
11101
+ * @return string HTML code for a table with the updates information.
11102
+ */
11103
+ function sucuriscan_posthack_updates_content($send_email = false)
11104
+ {
11105
+ if (!function_exists('wp_update_plugins')
11106
+ || !function_exists('get_plugin_updates')
11107
+ || !function_exists('wp_update_themes')
11108
+ || !function_exists('get_theme_updates')
11109
+ ) {
11110
+ return false;
11111
+ }
11112
 
11113
+ $response = '';
11114
+ $result = wp_update_plugins();
11115
+ $updates = get_plugin_updates();
11116
 
11117
+ if (is_array($updates) && !empty($updates)) {
11118
+ $counter = 0;
 
 
 
 
11119
 
11120
+ foreach ($updates as $data) {
11121
+ $css_class = ($counter % 2 == 0) ? '' : 'alternate';
11122
+ $response .= SucuriScanTemplate::getSnippet(
11123
+ 'posthack-updates',
11124
+ array(
11125
+ 'Update.CssClass' => $css_class,
11126
+ 'Update.IconType' => 'plugins',
11127
+ 'Update.Extension' => SucuriScan::excerpt($data->Name, 35),
11128
+ 'Update.Version' => $data->Version,
11129
+ 'Update.NewVersion' => $data->update->new_version,
11130
+ 'Update.TestedWith' => "WordPress\x20" . $data->update->tested,
11131
+ 'Update.ArchiveUrl' => $data->update->package,
11132
+ 'Update.MarketUrl' => $data->update->url,
11133
+ )
11134
+ );
11135
+ $counter++;
11136
+ }
11137
+ }
11138
+
11139
+ // Check for available theme updates.
11140
+ $result = wp_update_themes();
11141
+ $updates = get_theme_updates();
11142
+
11143
+ if (is_array($updates) && !empty($updates)) {
11144
+ $counter = 0;
11145
+
11146
+ foreach ($updates as $data) {
11147
+ $css_class = ($counter % 2 == 0) ? '' : 'alternate';
11148
+ $response .= SucuriScanTemplate::getSnippet(
11149
+ 'posthack-updates',
11150
+ array(
11151
+ 'Update.CssClass' => $css_class,
11152
+ 'Update.IconType' => 'appearance',
11153
+ 'Update.Extension' => SucuriScan::excerpt($data->Name, 35),
11154
+ 'Update.Version' => $data->Version,
11155
+ 'Update.NewVersion' => $data->update['new_version'],
11156
+ 'Update.TestedWith' => 'Newest WordPress',
11157
+ 'Update.ArchiveUrl' => $data->update['package'],
11158
+ 'Update.MarketUrl' => $data->update['url'],
11159
+ )
11160
+ );
11161
+ $counter++;
11162
+ }
11163
+ }
11164
+
11165
+ if (!is_string($response) || empty($response)) {
11166
+ return false;
11167
+ }
11168
+
11169
+ // Send an email notification with the affected files.
11170
+ if ($send_email === true) {
11171
+ $params = array('AvailableUpdates.Content' => $response);
11172
+ $content = SucuriScanTemplate::getSection('posthack-updates-notification', $params);
11173
+ $sent = SucuriScanEvent::notify_event('available_updates', $content);
11174
+
11175
+ return $sent;
11176
+ }
11177
+
11178
+ return $response;
11179
+ }
11180
+
11181
+ /**
11182
+ * Process the Ajax request to retrieve the available updates.
11183
+ *
11184
+ * @return string HTML code for a table with the updates information.
11185
+ */
11186
+ function sucuriscan_posthack_updates_ajax()
11187
+ {
11188
+ if (SucuriScanRequest::post('form_action') == 'get_available_updates') {
11189
+ $response = sucuriscan_posthack_updates_content();
11190
+
11191
+ if (!$response) {
11192
+ $response = '<tr><td colspan="5">No updates available.</td></tr>';
11193
+ }
11194
+
11195
+ header('Content-Type: text/html; charset=UTF-8');
11196
+ print($response);
11197
+ exit(0);
11198
+ }
11199
+ }
11200
+
11201
+ /**
11202
+ * Process the request that will start the execution of the plugin
11203
+ * reinstallation, it will check if the plugins submitted are (in fact)
11204
+ * installed in the system, then check if they are free download from the
11205
+ * WordPress market place, and finally download and install them.
11206
+ *
11207
+ * @param boolean $process_form Whether a form was submitted or not.
11208
+ * @return void
11209
+ */
11210
+ function sucuriscan_posthack_reinstall_plugins($process_form = false)
11211
+ {
11212
+ if ($process_form && isset($_POST['sucuriscan_reset_plugins'])) {
11213
+ include_once(ABSPATH . 'wp-admin/includes/class-wp-upgrader.php');
11214
+ include_once(ABSPATH . 'wp-admin/includes/plugin-install.php'); // For plugins_api.
11215
+
11216
+ if ($plugin_list = SucuriScanRequest::post('plugin_path', '_array')) {
11217
+ // Create an instance of the FileInfo interface.
11218
+ $file_info = new SucuriScanFileInfo();
11219
+ $file_info->ignore_files = false;
11220
+ $file_info->ignore_directories = false;
11221
+ $file_info->skip_directories = false;
11222
+
11223
+ // Get (possible) cached information from the installed plugins.
11224
+ $all_plugins = SucuriScanAPI::getPlugins();
11225
+
11226
+ // Loop through all the installed plugins.
11227
+ foreach ($plugin_list as $plugin_path) {
11228
+ if (array_key_exists($plugin_path, $all_plugins)) {
11229
+ $plugin_data = $all_plugins[ $plugin_path ];
11230
+
11231
+ // Check if the plugin can be downloaded from the free market.
11232
+ if ($plugin_data['IsFreePlugin'] === true) {
11233
+ $plugin_info = SucuriScanAPI::getRemotePluginData($plugin_data['RepositoryName']);
11234
+
11235
+ if ($plugin_info) {
11236
+ // First, remove all files/sub-folders from the plugin's directory.
11237
+ if (substr_count($plugin_path, '/') >= 1) {
11238
+ $plugin_directory = dirname(WP_PLUGIN_DIR . '/' . $plugin_path);
11239
+ $file_info->remove_directory_tree($plugin_directory);
11240
+ }
11241
+
11242
+ // Install a fresh copy of the plugin's files.
11243
+ $upgrader_skin = new Plugin_Installer_Skin();
11244
+ $upgrader = new Plugin_Upgrader($upgrader_skin);
11245
  $upgrader->install($plugin_info->download_link);
11246
  SucuriScanEvent::report_notice_event('Plugin re-installed: ' . $plugin_path);
11247
  } else {
11256
  }
11257
  }
11258
 
11259
+ class SucuriScanLastLogins extends SucuriScan
11260
+ {
11261
+ }
11262
+
11263
  /**
11264
  * Generate and print the HTML code for the Last Logins page.
11265
  *
11277
  ) {
11278
  $file_path = sucuriscan_lastlogins_datastore_filepath();
11279
 
11280
+ if (@unlink($file_path)) {
11281
  sucuriscan_lastlogins_datastore_exists();
11282
  SucuriScanInterface::info('Last-Logins logs were reset successfully.');
11283
  } else {
11292
  'LastLogins.AllUsers' => sucuriscan_lastlogins_all(),
11293
  'LoggedInUsers' => sucuriscan_loggedin_users_panel(),
11294
  'FailedLogins' => sucuriscan_failed_logins_panel(),
11295
+ 'BlockedUsers' => SucuriScanBlockedUsers::page(),
11296
  );
11297
 
11298
  echo SucuriScanTemplate::getTemplate('lastlogins', $params);
11932
  'FailedLogins.PaginationVisibility' => 'hidden',
11933
  );
11934
 
11935
+ if (SucuriScanInterface::check_nonce()) {
11936
+ $blockUsers = SucuriScanRequest::post(':block_user', '_array');
11937
+
11938
+ if (is_array($blockUsers) && !empty($blockUsers)) {
11939
+ SucuriScanBlockedUsers::block($blockUsers);
11940
+ SucuriScanInterface::info('Selected user accounts were blocked');
11941
+ }
11942
+ }
11943
+
11944
  // Define variables for the pagination.
11945
  $page_number = SucuriScanTemplate::pageNumber();
11946
  $max_per_page = SUCURISCAN_MAX_PAGINATION_BUTTONS;
11949
 
11950
  $max_failed_logins = SucuriScanOption::get_option(':maximum_failed_logins');
11951
  $notify_bruteforce_attack = SucuriScanOption::get_option(':notify_bruteforce_attack');
11952
+ $collect_passwords = sucuriscan_collect_wrong_passwords();
11953
+ $failed_logins = sucuriscan_get_all_failed_logins();
 
 
 
 
 
 
 
 
 
11954
 
11955
  if ($failed_logins) {
11956
  $counter = 0;
11962
  $wrong_user_password = 'hidden';
11963
  $wrong_user_password_color = 'default';
11964
 
11965
+ if ($collect_passwords === true) {
11966
  if (isset($login_data['user_password']) && !empty($login_data['user_password'])) {
11967
  $wrong_user_password = $login_data['user_password'];
11968
  $wrong_user_password_color = 'none';
12010
  $template_variables['FailedLogins.WarningVisibility'] = 'hidden';
12011
  }
12012
 
12013
+ if ($collect_passwords !== true) {
12014
  $template_variables['FailedLogins.CollectPasswordsVisibility'] = 'hidden';
12015
  }
12016
 
12065
  */
12066
  function sucuriscan_failed_logins_default_content()
12067
  {
12068
+ return "<?php exit(0); ?>\n";
12069
+ }
12070
+
12071
+ /**
12072
+ * Returns failed logins data including old entries.
12073
+ *
12074
+ * @return array Failed logins data.
12075
+ */
12076
+ function sucuriscan_get_all_failed_logins()
12077
+ {
12078
+ $all = array();
12079
+ $new = sucuriscan_get_failed_logins();
12080
+ $old = sucuriscan_get_failed_logins(true);
12081
+
12082
+ if ($new && $old) {
12083
+ // Merge the new and old failed logins.
12084
+ $all = array();
12085
 
12086
+ $all['first_attempt'] = $old['first_attempt'];
12087
+ $all['last_attempt'] = $new['last_attempt'];
12088
+ $all['count'] = $new['count'] + $old['count'];
12089
+ $all['diff_time'] = abs($all['last_attempt'] - $all['first_attempt']);
12090
+ $all['entries'] = array_merge($new['entries'], $old['entries']);
12091
+
12092
+ return $all;
12093
+ } elseif ($new && !$old) {
12094
+ return $new;
12095
+ } elseif (!$new && $old) {
12096
+ return $old;
12097
+ }
12098
+
12099
+ return false;
12100
  }
12101
 
12102
  /**
12113
  function sucuriscan_get_failed_logins($get_old_logs = false)
12114
  {
12115
  $datastore_path = sucuriscan_failed_logins_datastore_path($get_old_logs);
 
 
12116
 
12117
  if ($datastore_path) {
12118
  $lines = SucuriScanFileInfo::file_lines($datastore_path);
12165
  return false;
12166
  }
12167
 
 
12168
  /**
12169
  * Add a new entry in the datastore file where the failed logins are being kept,
12170
  * this entry will contain the username, timestamp of the login attempt, remote
12311
  return (bool) sucuriscan_failed_logins_datastore_path(false, true);
12312
  }
12313
 
12314
+ class SucuriScanBlockedUsers extends SucuriScanLastLogins
12315
+ {
12316
+ public static function page()
12317
+ {
12318
+ $output = array();
12319
+ $output['BlockedUsers.List'] = '';
12320
+ $output['BlockedUsers.NoItemsVisibility'] = 'visible';
12321
+
12322
+ if (SucuriScanInterface::check_nonce()) {
12323
+ $unblockUsers = SucuriScanRequest::post(':unblock_user', '_array');
12324
+
12325
+ if (is_array($unblockUsers) && !empty($unblockUsers)) {
12326
+ self::unblock($unblockUsers);
12327
+ SucuriScanInterface::info('Selected user accounts were unblocked');
12328
+ }
12329
+ }
12330
+
12331
+ $cache = new SucuriScanCache('blockedusers', false);
12332
+ $blocked = $cache->getAll();
12333
+
12334
+ if (is_array($blocked) && !empty($blocked)) {
12335
+ $counter = 0;
12336
+
12337
+ foreach ($blocked as $data) {
12338
+ $css_class = ($counter % 2 === 0) ? '' : 'alternate';
12339
+ $output['BlockedUsers.List'] .= SucuriScanTemplate::getSnippet(
12340
+ 'lastlogins-blockedusers',
12341
+ array(
12342
+ 'BlockedUsers.CssClass' => $css_class,
12343
+ 'BlockedUsers.Username' => $data->username,
12344
+ 'BlockedUsers.BlockedAt' => self::datetime($data->blocked_at),
12345
+ 'BlockedUsers.FirstAttempt' => self::datetime($data->first_attempt),
12346
+ 'BlockedUsers.LastAttempt' => self::datetime($data->last_attempt),
12347
+ )
12348
+ );
12349
+ $counter++;
12350
+ }
12351
+
12352
+ if ($counter > 0) {
12353
+ $output['BlockedUsers.NoItemsVisibility'] = 'hidden';
12354
+ }
12355
+ }
12356
+
12357
+ return SucuriScanTemplate::getSection('lastlogins-blockedusers', $output);
12358
+ }
12359
+
12360
+ public static function block($users = array())
12361
+ {
12362
+ if (is_array($users) && !empty($users)) {
12363
+ $logs = sucuriscan_get_all_failed_logins();
12364
+ $cache = new SucuriScanCache('blockedusers');
12365
+ $blocked = $cache->getAll();
12366
+
12367
+ foreach ($users as $user) {
12368
+ if (array_key_exists($user, $blocked)) {
12369
+ continue;
12370
+ }
12371
+
12372
+ $firstAttempt = self::firstAttempt($logs, $user);
12373
+ $lastAttempt = self::lastAttempt($logs, $user);
12374
+ $data = array(
12375
+ 'username' => $user,
12376
+ 'blocked_at' => time(),
12377
+ 'first_attempt' => $firstAttempt,
12378
+ 'last_attempt' => $lastAttempt,
12379
+ );
12380
+ $cache->add(md5($user), $data);
12381
+ }
12382
+ }
12383
+ }
12384
+
12385
+ public static function unblock($users = array())
12386
+ {
12387
+ if (is_array($users) && !empty($users)) {
12388
+ $cache = new SucuriScanCache('blockedusers');
12389
+ $blocked = $cache->getAll();
12390
+
12391
+ foreach ($users as $user) {
12392
+ $cache_key = md5($user);
12393
+
12394
+ if (array_key_exists($cache_key, $blocked)) {
12395
+ $cache->delete($cache_key);
12396
+ }
12397
+ }
12398
+ }
12399
+ }
12400
+
12401
+ public static function blockUserLogin()
12402
+ {
12403
+ if (class_exists('SucuriScanRequest')
12404
+ && class_exists('SucuriScanCache')
12405
+ ) {
12406
+ $username = SucuriScanRequest::post('log');
12407
+ $password = SucuriScanRequest::post('pwd');
12408
+
12409
+ if ($username !== false && $password !== false) {
12410
+ $cache = new SucuriScanCache('blockedusers');
12411
+ $blocked = $cache->getAll();
12412
+ $cache_key = md5($username);
12413
+
12414
+ if (array_key_exists($cache_key, $blocked)) {
12415
+ $blocked[$cache_key]->last_attempt = time();
12416
+ $cache->set($cache_key, $blocked[$cache_key]);
12417
+
12418
+ if (!headers_sent()) {
12419
+ header('HTTP/1.1 403 Forbidden');
12420
+ }
12421
+
12422
+ exit(0);
12423
+ }
12424
+ }
12425
+ }
12426
+ }
12427
+
12428
+ private static function firstAttempt($logs, $user)
12429
+ {
12430
+ $attempts = array();
12431
+
12432
+ foreach ($logs['entries'] as $login) {
12433
+ if ($login['user_login'] === $user) {
12434
+ $attempts[] = $login['attempt_time'];
12435
+ }
12436
+ }
12437
+
12438
+ if (empty($attempts)) {
12439
+ return null;
12440
+ }
12441
+
12442
+ return min($attempts);
12443
+ }
12444
+
12445
+ private static function lastAttempt($logs, $user)
12446
+ {
12447
+ $attempts = array();
12448
+
12449
+ foreach ($logs['entries'] as $login) {
12450
+ if ($login['user_login'] === $user) {
12451
+ $attempts[] = $login['attempt_time'];
12452
+ }
12453
+ }
12454
+
12455
+ if (empty($attempts)) {
12456
+ return null;
12457
+ }
12458
+
12459
+ return max($attempts);
12460
+ }
12461
+ }
12462
+
12463
  /**
12464
  * Process the requests sent by the form submissions originated in the settings
12465
  * page, all forms must have a nonce field that will be checked against the one
12471
  function sucuriscan_settings_form_submissions($page_nonce = null)
12472
  {
12473
  global $sucuriscan_schedule_allowed,
12474
+ $sucuriscan_interface_allowed;
 
 
12475
 
12476
  // Use this conditional to avoid double checking.
12477
  if (is_null($page_nonce)) {
12505
  SucuriScanInterface::info($message);
12506
  }
12507
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12508
  // Enable or disable the filesystem scanner for error logs.
12509
  if ($scan_errorlogs = SucuriScanRequest::post(':scan_errorlogs', '(en|dis)able')) {
12510
  $action_d = $scan_errorlogs . 'd';
12516
  SucuriScanInterface::info($message);
12517
  }
12518
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12519
  // Modify the schedule of the filesystem scanner.
12520
  if ($frequency = SucuriScanRequest::post(':scan_frequency')) {
12521
  if (array_key_exists($frequency, $sucuriscan_schedule_allowed)) {
12549
  }
12550
  }
12551
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12552
  // Reset the plugin security logs.
12553
+ $allowed_log_files = '(lastlogins|failedlogins)';
12554
  if ($reset_logfile = SucuriScanRequest::post(':reset_logfile', $allowed_log_files)) {
12555
  $files_to_delete = array(
12556
  'sucuri-' . $reset_logfile . '.php',
12588
  }
12589
  }
12590
 
12591
+ // Trust and IP address to ignore notifications for a subnet.
12592
+ if ($trust_ip = SucuriScanRequest::post(':trust_ip')) {
12593
+ if (SucuriScan::is_valid_ip($trust_ip)
12594
+ || SucuriScan::is_valid_cidr($trust_ip)
12595
+ ) {
12596
+ $cache = new SucuriScanCache('trustip');
12597
+ $ip_info = SucuriScan::get_ip_info($trust_ip);
12598
+ $ip_info['added_at'] = SucuriScan::local_time();
12599
+ $cache_key = md5($ip_info['remote_addr']);
12600
 
12601
+ if ($cache->exists($cache_key)) {
12602
+ SucuriScanInterface::error('The IP address specified was already trusted.');
12603
+ } elseif ($cache->add($cache_key, $ip_info)) {
12604
+ $message = 'Changes from <code>' . $trust_ip . '</code> will be ignored';
12605
+
12606
+ SucuriScanEvent::report_warning_event($message);
12607
+ SucuriScanInterface::info($message);
12608
+ } else {
12609
+ SucuriScanInterface::error('The new entry was not saved in the datastore file.');
12610
  }
12611
+ }
12612
+ }
12613
 
12614
+ // Trust and IP address to ignore notifications for a subnet.
12615
+ if ($del_trust_ip = SucuriScanRequest::post(':del_trust_ip', '_array')) {
12616
+ $cache = new SucuriScanCache('trustip');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12617
 
12618
  foreach ($del_trust_ip as $cache_key) {
12619
  $cache->delete($cache_key);
12705
  $params['SettingsSection.AuditLogStats'] = sucuriscan_settings_general_auditlogstats($nonce);
12706
  $params['SettingsSection.Datetime'] = sucuriscan_settings_general_datetime($nonce);
12707
 
 
 
12708
  return SucuriScanTemplate::getSection('settings-general', $params);
12709
  }
12710
 
12735
  @unlink(SucuriScan::datastore_folder_path('sucuri-oldfailedlogins.php'));
12736
  @unlink(SucuriScan::datastore_folder_path('sucuri-plugindata.php'));
12737
  @unlink(SucuriScan::datastore_folder_path('sucuri-sitecheck.php'));
12738
+ @unlink(SucuriScan::datastore_folder_path('sucuri-settings.php'));
12739
  @unlink(SucuriScan::datastore_folder_path('sucuri-trustip.php'));
12740
  @rmdir(SucuriScan::datastore_folder_path());
12741
 
12788
 
12789
  // Recover API key through the email registered previously.
12790
  if (SucuriScanRequest::post(':recover_key') !== false) {
12791
+ $_GET['recover'] = 'true';
12792
  SucuriScanAPI::recoverKey();
12793
  SucuriScanEvent::report_info_event('Recovery of the Sucuri API key was requested.');
 
 
 
 
 
 
 
12794
  }
12795
  }
12796
 
12797
  $api_key = SucuriScanAPI::getPluginKey();
12798
 
12799
+ if (SucuriScanRequest::get('recover') !== false) {
12800
+ $api_recovery_modal = SucuriScanTemplate::getModal(
12801
+ 'settings-apirecovery',
12802
+ array(
12803
+ 'Title' => 'Plugin API Key Recovery',
12804
+ 'CssClass' => 'sucuriscan-apirecovery',
12805
+ )
12806
+ );
12807
+ }
12808
+
12809
  // Check whether the domain name is valid or not.
12810
  if (!$api_key) {
12811
  $clean_domain = SucuriScan::get_top_level_domain();
13160
  return SucuriScanTemplate::getSection('settings-general-datetime', $params);
13161
  }
13162
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13163
  /**
13164
  * Read and parse the content of the scanner settings template.
13165
  *
13166
  * @return string Parsed HTML code for the scanner settings panel.
13167
  */
13168
+ function sucuriscan_settings_scanner($nonce)
13169
  {
13170
  global $sucuriscan_schedule_allowed,
13171
  $sucuriscan_interface_allowed;
13174
  $fs_scanner = SucuriScanOption::get_option(':fs_scanner');
13175
  $scan_freq = SucuriScanOption::get_option(':scan_frequency');
13176
  $scan_interface = SucuriScanOption::get_option(':scan_interface');
 
13177
  $scan_errorlogs = SucuriScanOption::get_option(':scan_errorlogs');
 
 
 
 
 
13178
  $runtime_scan_human = SucuriScanFSScanner::get_filesystem_runtime(true);
13179
 
13180
  // Get the file path of the security logs.
13181
+ $basedir = SucuriScan::datastore_folder_path();
13182
+ $integrity_log_path = $basedir . '/sucuri-integrity.php';
13183
+ $lastlogins_log_path = $basedir . '/sucuri-lastlogins.php';
13184
+ $failedlogins_log_path = $basedir . '/sucuri-failedlogins.php';
13185
 
13186
  // Generate the HTML code for the option list in the form select fields.
13187
  $scan_freq_options = SucuriScanTemplate::selectOptions($sucuriscan_schedule_allowed, $scan_freq);
13193
  'FsScannerSwitchText' => 'Disable',
13194
  'FsScannerSwitchValue' => 'disable',
13195
  'FsScannerSwitchCssClass' => 'button-danger',
 
 
 
 
 
 
 
 
 
 
13196
  /* Scan error logs. */
13197
  'ScanErrorlogsStatus' => 'Enabled',
13198
  'ScanErrorlogsSwitchText' => 'Disable',
13199
  'ScanErrorlogsSwitchValue' => 'disable',
13200
  'ScanErrorlogsSwitchCssClass' => 'button-danger',
 
 
 
 
 
 
 
 
 
 
13201
  /* Filsystem scanning frequency. */
13202
  'ScanningFrequency' => 'Undefined',
13203
  'ScanningFrequencyOptions' => $scan_freq_options,
13205
  'ScanningInterfaceOptions' => $scan_interface_options,
13206
  /* Filesystem scanning runtime. */
13207
  'ScanningRuntimeHuman' => $runtime_scan_human,
 
 
13208
  'IntegrityLogLife' => '0B',
13209
  'LastLoginLogLife' => '0B',
13210
  'FailedLoginLogLife' => '0B',
 
13211
  );
13212
 
13213
  if ($fs_scanner == 'disabled') {
13217
  $params['FsScannerSwitchCssClass'] = 'button-success';
13218
  }
13219
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13220
  if ($scan_errorlogs == 'disabled') {
13221
  $params['ScanErrorlogsStatus'] = 'Disabled';
13222
  $params['ScanErrorlogsSwitchText'] = 'Enable';
13224
  $params['ScanErrorlogsSwitchCssClass'] = 'button-success';
13225
  }
13226
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13227
  if (array_key_exists($scan_freq, $sucuriscan_schedule_allowed)) {
13228
  $params['ScanningFrequency'] = $sucuriscan_schedule_allowed[ $scan_freq ];
13229
  }
13232
  $params['IntegrityLogLife'] = SucuriScan::human_filesize(@filesize($integrity_log_path));
13233
  $params['LastLoginLogLife'] = SucuriScan::human_filesize(@filesize($lastlogins_log_path));
13234
  $params['FailedLoginLogLife'] = SucuriScan::human_filesize(@filesize($failedlogins_log_path));
13235
+
13236
+ $params['Settings.CoreFilesStatus'] = sucuriscan_settings_corefiles_status($nonce);
13237
+ $params['Settings.CoreFilesLanguage'] = sucuriscan_settings_corefiles_language($nonce);
13238
+ $params['Settings.CoreFilesCache'] = sucuriscan_settings_corefiles_cache($nonce);
13239
+ $params['Settings.SiteCheckStatus'] = SucuriScanSiteCheck::statusPage();
13240
+ $params['Settings.SiteCheckCache'] = SucuriScanSiteCheck::cachePage($nonce);
13241
+ $params['Settings.SiteCheckTimeout'] = SucuriScanSiteCheck::timeoutPage($nonce);
13242
 
13243
  return SucuriScanTemplate::getSection('settings-scanner', $params);
13244
  }
13245
 
13246
+ function sucuriscan_settings_corefiles_status($nonce)
13247
  {
13248
+ $params = array();
13249
+ $params['Integrity.StatusNum'] = '0';
13250
+ $params['Integrity.Status'] = 'Disabled';
13251
+ $params['Integrity.SwitchText'] = 'Enable';
13252
+ $params['Integrity.SwitchValue'] = 'enable';
13253
+ $params['Integrity.SwitchCssClass'] = 'button-success';
13254
+
13255
+ if ($nonce) {
13256
+ // Enable or disable the filesystem scanner for file integrity.
13257
+ if ($scan_checksums = SucuriScanRequest::post(':scan_checksums', '(en|dis)able')) {
13258
+ $action_d = $scan_checksums . 'd';
13259
+ $message = 'File system scanner for file integrity was <code>' . $action_d . '</code>';
13260
 
13261
+ SucuriScanOption::update_option(':scan_checksums', $action_d);
13262
+ SucuriScanEvent::report_auto_event($message);
13263
+ SucuriScanEvent::notify_event('plugin_change', $message);
13264
+ SucuriScanInterface::info($message);
13265
+ }
13266
+ }
13267
 
13268
+ if (SucuriScanOption::is_enabled(':scan_checksums')) {
13269
+ $params['Integrity.StatusNum'] = '1';
13270
+ $params['Integrity.Status'] = 'Enabled';
13271
+ $params['Integrity.SwitchText'] = 'Disable';
13272
+ $params['Integrity.SwitchValue'] = 'disable';
13273
+ $params['Integrity.SwitchCssClass'] = 'button-danger';
13274
  }
13275
 
13276
+ return SucuriScanTemplate::getSection('settings-corefiles-status', $params);
13277
+ }
13278
+
13279
+ function sucuriscan_settings_corefiles_language($nonce)
13280
+ {
13281
+ $params = array();
13282
+ $languages = SucuriScan::languages();
 
 
 
 
 
 
 
 
 
 
13283
 
13284
+ if ($nonce) {
13285
+ // Configure the language for the core integrity checks.
13286
+ if ($language = SucuriScanRequest::post(':set_language')) {
13287
+ if (array_key_exists($language, $languages)) {
13288
+ $message = 'Language for the core integrity checks set to <code>' . $language . '</code>';
13289
+
13290
+ SucuriScanOption::update_option(':language', $language);
13291
+ SucuriScanEvent::report_auto_event($message);
13292
+ SucuriScanEvent::notify_event('plugin_change', $message);
13293
+ SucuriScanInterface::info($message);
13294
+ } else {
13295
+ SucuriScanInterface::error('Selected language is not supported.');
13296
+ }
13297
+ }
13298
+ }
13299
+
13300
+ $language = SucuriScanOption::get_option(':language');
13301
+ $params['Integrity.LanguageDropdown'] = SucuriScanTemplate::selectOptions($languages, $language);
13302
+ $params['Integrity.WordPressLocale'] = get_locale();
13303
+
13304
+ return SucuriScanTemplate::getSection('settings-corefiles-language', $params);
13305
+ }
13306
+
13307
+ function sucuriscan_settings_corefiles_cache($nonce)
13308
+ {
13309
+ $params = array();
13310
+ $fpath = SucuriScan::datastore_folder_path('sucuri-integrity.php');
13311
+
13312
+ if ($nonce) {
13313
+ // Reset core integrity files marked as fixed
13314
+ if (SucuriScanRequest::post(':corefiles_cache')) {
13315
+ if (file_exists($fpath)) {
13316
+ if (@unlink($fpath)) {
13317
+ $message = 'Core integrity files marked as fixed were successfully reset.';
13318
+
13319
+ SucuriScanEvent::report_debug_event($message);
13320
+ SucuriScanInterface::info($message);
13321
+ } else {
13322
+ SucuriScanInterface::error('Count not reset the cache, delete manually.');
13323
  }
13324
+ } else {
13325
+ SucuriScanInterface::error('The cache file does not exists.');
13326
+ }
13327
+ }
13328
+ }
13329
 
13330
+ $params['CoreFiles.CacheSize'] = SucuriScan::human_filesize(@filesize($fpath));
13331
+ $params['CoreFiles.CacheLifeTime'] = SUCURISCAN_SITECHECK_LIFETIME;
13332
+ $params['CoreFiles.TableVisibility'] = 'hidden';
13333
+ $params['CoreFiles.IgnoredFiles'] = '';
13334
+ $cache = new SucuriScanCache('integrity');
13335
+ $ignored_files = $cache->getAll();
13336
+ $counter = 0;
13337
+
13338
+ if ($ignored_files) {
13339
+ $params['CoreFiles.TableVisibility'] = 'visible';
13340
+
13341
+ foreach ($ignored_files as $hash => $data) {
13342
+ $params['CoreFiles.IgnoredFiles'] .= SucuriScanTemplate::getSnippet(
13343
+ 'settings-corefiles-cache',
13344
+ array(
13345
+ 'IgnoredFile.CssClass' => ($counter % 2 === 0) ? '' : 'alternate',
13346
+ 'IgnoredFile.UniqueId' => substr($hash, 0, 8),
13347
+ 'IgnoredFile.FilePath' => $data->file_path,
13348
+ 'IgnoredFile.StatusType' => $data->file_status,
13349
+ 'IgnoredFile.IgnoredAt' => SucuriScan::datetime($data->ignored_at),
13350
+ )
13351
+ );
13352
+ $counter++;
13353
+ }
13354
+ }
13355
+
13356
+ return SucuriScanTemplate::getSection('settings-corefiles-cache', $params);
13357
+ }
13358
+
13359
+ class SucuriScanSiteCheck extends SucuriScanSettings
13360
+ {
13361
+ public static function isEnabled()
13362
+ {
13363
+ return (bool) !self::isDisabled();
13364
+ }
13365
+
13366
+ public static function isDisabled()
13367
+ {
13368
+ return (bool) (
13369
+ defined('SUCURISCAN_NO_SITECHECK')
13370
+ && SUCURISCAN_NO_SITECHECK === true
13371
+ );
13372
+ }
13373
+
13374
+ public static function statusPage()
13375
+ {
13376
+ $params = array();
13377
+ $params['SiteCheck.StatusNum'] = '1';
13378
+ $params['SiteCheck.Status'] = 'Enabled';
13379
+ $params['SiteCheck.IfEnabled'] = 'visible';
13380
+ $params['SiteCheck.IfDisabled'] = 'hidden';
13381
+
13382
+ if (SucuriScanSiteCheck::isDisabled()) {
13383
+ $params['SiteCheck.StatusNum'] = '0';
13384
+ $params['SiteCheck.Status'] = 'Disabled';
13385
+ $params['SiteCheck.IfEnabled'] = 'hidden';
13386
+ $params['SiteCheck.IfDisabled'] = 'visible';
13387
+ }
13388
+
13389
+ $params['SiteCheck.Counter'] = SucuriScanOption::get_option(':sitecheck_counter');
13390
+
13391
+ return SucuriScanTemplate::getSection('settings-sitecheck-status', $params);
13392
+ }
13393
+
13394
+ public static function cachePage($nonce)
13395
+ {
13396
+ $params = array();
13397
+ $fpath = SucuriScan::datastore_folder_path('sucuri-sitecheck.php');
13398
+
13399
+ if ($nonce) {
13400
+ // Reset SiteCheck results cache.
13401
+ if (SucuriScanRequest::post(':sitecheck_cache')) {
13402
+ if (file_exists($fpath)) {
13403
+ if (@unlink($fpath)) {
13404
+ $message = 'Malware scanner cache was successfully reset.';
13405
+
13406
+ SucuriScanEvent::report_debug_event($message);
13407
+ SucuriScanInterface::info($message);
13408
+ } else {
13409
+ SucuriScanInterface::error('Count not reset the cache, delete manually.');
13410
+ }
13411
+ } else {
13412
+ SucuriScanInterface::error('The cache file does not exists.');
13413
+ }
13414
+ }
13415
+ }
13416
+
13417
+ $params['SiteCheck.CacheSize'] = SucuriScan::human_filesize(@filesize($fpath));
13418
+ $params['SiteCheck.CacheLifeTime'] = SUCURISCAN_SITECHECK_LIFETIME;
13419
+
13420
+ return SucuriScanTemplate::getSection('settings-sitecheck-cache', $params);
13421
+ }
13422
+
13423
+ public static function timeoutPage($nonce)
13424
+ {
13425
+ $params = array();
13426
+
13427
+ // Update the SiteCheck timeout.
13428
+ if ($nonce) {
13429
+ $timeout = (int) SucuriScanRequest::post(':sitecheck_timeout', '[0-9]+');
13430
+
13431
+ if ($timeout > 0) {
13432
+ if ($timeout <= SUCURISCAN_MAX_SITECHECK_TIMEOUT) {
13433
+ $message = 'SiteCheck timeout set to <code>' . $timeout . '</code> seconds.';
13434
+
13435
+ SucuriScanOption::update_option(':sitecheck_timeout', $timeout);
13436
+ SucuriScanEvent::report_info_event($message);
13437
+ SucuriScanEvent::notify_event('plugin_change', $message);
13438
+ SucuriScanInterface::info($message);
13439
+ } else {
13440
+ SucuriScanInterface::error('SiteCheck timeout in seconds is too high.');
13441
+ }
13442
+ }
13443
+ }
13444
+
13445
+ $params['MaxRequestTimeout'] = SUCURISCAN_MAX_SITECHECK_TIMEOUT;
13446
+ $params['RequestTimeout'] = SucuriScanOption::get_option(':sitecheck_timeout') . ' seconds';
13447
+
13448
+ return SucuriScanTemplate::getSection('settings-sitecheck-timeout', $params);
13449
+ }
13450
+ }
13451
+
13452
+ /**
13453
+ * Read and parse the content of the SiteCheck settings template.
13454
+ *
13455
+ * @return string Parsed HTML code for the SiteCheck settings panel.
13456
+ */
13457
+ function sucuriscan_settings_ignorescan($nonce)
13458
+ {
13459
+ $params = array();
13460
+
13461
+ $params['SettingsSection.IgnoreScanStatus'] = sucuriscan_settings_ignore_scan_status($nonce);
13462
+ $params['SettingsSection.IgnoreScanFiles'] = sucuriscan_settings_ignore_scan_files();
13463
+ $params['SettingsSection.IgnoreScanFolders'] = sucuriscan_settings_ignore_scan_folders($nonce);
13464
+
13465
+ return SucuriScanTemplate::getSection('settings-ignorescan', $params);
13466
+ }
13467
+
13468
+ function sucuriscan_settings_ignorescan_ajax()
13469
+ {
13470
+ if (SucuriScanRequest::post('form_action') == 'get_ignored_files') {
13471
+ $response = '';
13472
+
13473
+ // Scan the project and get the ignored paths.
13474
+ if (SucuriScanOption::is_enabled(':ignore_scanning')) {
13475
+ $counter = 0;
13476
+ $ignored_dirs = SucuriScanFSScanner::get_ignored_directories_live();
13477
+
13478
+ foreach ($ignored_dirs as $group => $dir_list) {
13479
+ foreach ($dir_list as $dir_data) {
13480
+ $valid_entry = false;
13481
+ $snippet = array(
13482
+ 'IgnoreScan.CssClass' => '',
13483
+ 'IgnoreScan.Directory' => '',
13484
+ 'IgnoreScan.DirectoryPath' => '',
13485
+ 'IgnoreScan.IgnoredAt' => '',
13486
+ 'IgnoreScan.IgnoredAtText' => 'ok',
13487
+ 'IgnoreScan.IgnoredCssClass' => 'success',
13488
  );
13489
+
13490
+ if ($group == 'is_ignored') {
13491
+ $valid_entry = true;
13492
+ $snippet['IgnoreScan.Directory'] = urlencode($dir_data['directory_path']);
13493
+ $snippet['IgnoreScan.DirectoryPath'] = $dir_data['directory_path'];
13494
+ $snippet['IgnoreScan.IgnoredAt'] = SucuriScan::datetime($dir_data['ignored_at']);
13495
+ $snippet['IgnoreScan.IgnoredAtText'] = 'ignored';
13496
+ $snippet['IgnoreScan.IgnoredCssClass'] = 'warning';
13497
+ } elseif ($group == 'is_not_ignored') {
13498
+ $valid_entry = true;
13499
+ $snippet['IgnoreScan.Directory'] = urlencode($dir_data);
13500
+ $snippet['IgnoreScan.DirectoryPath'] = $dir_data;
13501
+ }
13502
+
13503
+ if ($valid_entry) {
13504
+ $snippet['IgnoreScan.CssClass'] = ($counter % 2 === 0) ? '' : 'alternate';
13505
+ $response .= SucuriScanTemplate::getSnippet('settings-ignorescan', $snippet);
13506
+ $counter++;
13507
+ }
13508
  }
13509
  }
13510
+ } else {
13511
+ $response = '<tr><td colspan="3">Enable the ignore scanning option first.</td></tr>';
13512
  }
13513
 
13514
+ print($response);
13515
+ exit(0);
13516
+ }
13517
+ }
13518
+
13519
+ function sucuriscan_settings_ignore_scan_status($nonce)
13520
+ {
13521
+ $params = array();
13522
+ $params['IgnoreScan.Status'] = 'Disabled';
13523
+ $params['IgnoreScan.SwitchText'] = 'Enable';
13524
+ $params['IgnoreScan.SwitchValue'] = 'enable';
13525
+ $params['IgnoreScan.SwitchCssClass'] = 'button-success';
13526
+
13527
+ if ($nonce) {
13528
+ // Enable or disable the filesystem scanner for error logs.
13529
+ if ($ignore = SucuriScanRequest::post(':ignore_scanning', '(en|dis)able')) {
13530
+ $action_d = $ignore . 'd';
13531
+ $message = 'File system scanner rules to ignore directories was <code>' . $action_d . '</code>';
13532
+
13533
+ SucuriScanOption::update_option(':ignore_scanning', $action_d);
13534
+ SucuriScanEvent::report_auto_event($message);
13535
+ SucuriScanEvent::notify_event('plugin_change', $message);
13536
+ SucuriScanInterface::info($message);
13537
  }
13538
  }
13539
 
13540
+ if (SucuriScanOption::is_enabled(':ignore_scanning')) {
13541
+ $params['IgnoreScan.Status'] = 'Enabled';
13542
+ $params['IgnoreScan.SwitchText'] = 'Disable';
13543
+ $params['IgnoreScan.SwitchValue'] = 'disable';
13544
+ $params['IgnoreScan.SwitchCssClass'] = 'button-danger';
13545
+ }
13546
+
13547
+ return SucuriScanTemplate::getSection('settings-ignorescan-status', $params);
13548
+ }
13549
+
13550
+ function sucuriscan_settings_ignore_scan_files()
13551
+ {
13552
+ $params = array();
13553
+
13554
+ return SucuriScanTemplate::getSection('settings-ignorescan-files', $params);
13555
+ }
13556
+
13557
+ function sucuriscan_settings_ignore_scan_folders($nonce)
13558
+ {
13559
+ $params = array();
13560
+
13561
+ if ($nonce) {
13562
+ // Ignore a new directory path for the file system scans.
13563
+ if ($action = SucuriScanRequest::post(':ignorescanning_action', '(ignore|unignore)')) {
13564
+ $ign_dirs = SucuriScanRequest::post(':ignorescanning_dirs', '_array');
13565
+ $ign_file = SucuriScanRequest::post(':ignorescanning_file');
13566
+
13567
+ if ($action == 'ignore') {
13568
+ // Target a single file path to be ignored.
13569
+ if ($ign_file !== false) {
13570
+ $ign_dirs = array($ign_file);
13571
+ unset($_POST['sucuriscan_ignorescanning_file']);
13572
+ }
13573
+
13574
+ // Target a list of directories to be ignored.
13575
+ if (is_array($ign_dirs) && !empty($ign_dirs)) {
13576
+ $were_ignored = array();
13577
+
13578
+ foreach ($ign_dirs as $resource_path) {
13579
+ if (file_exists($resource_path)
13580
+ && SucuriScanFSScanner::ignore_directory($resource_path)
13581
+ ) {
13582
+ $were_ignored[] = $resource_path;
13583
+ }
13584
+ }
13585
+
13586
+ if (!empty($were_ignored)) {
13587
+ SucuriScanInterface::info('Items selected will be ignored in future scans.');
13588
+ SucuriScanEvent::report_warning_event(sprintf(
13589
+ 'Resources will not be scanned: (multiple entries): %s',
13590
+ @implode(',', $ign_dirs)
13591
+ ));
13592
+ }
13593
+ }
13594
+ } elseif ($action == 'unignore'
13595
+ && is_array($ign_dirs)
13596
+ && !empty($ign_dirs)
13597
+ ) {
13598
+ foreach ($ign_dirs as $directory_path) {
13599
+ SucuriScanFSScanner::unignore_directory($directory_path);
13600
+ }
13601
+
13602
+ SucuriScanInterface::info('Items selected will not be ignored anymore.');
13603
+ SucuriScanEvent::report_notice_event(sprintf(
13604
+ 'Resources will be scanned: (multiple entries): %s',
13605
+ @implode(',', $ign_dirs)
13606
+ ));
13607
+ }
13608
+ }
13609
+ }
13610
+
13611
+ return SucuriScanTemplate::getSection('settings-ignorescan-folders', $params);
13612
  }
13613
 
13614
  /**
13877
  if (SucuriScanRequest::post(':save_alert_events') !== false) {
13878
  $ucounter = 0;
13879
 
 
 
 
 
13880
  foreach ($sucuriscan_notify_options as $alert_type => $alert_label) {
13881
  $option_value = SucuriScanRequest::post($alert_type, '(1|0)');
13882
 
14020
  $params['SettingsSection.ApiProxy'] = sucuriscan_settings_apiservice_proxy($nonce);
14021
  $params['SettingsSection.ApiSSL'] = sucuriscan_settings_apiservice_ssl($nonce);
14022
  $params['SettingsSection.ApiTimeout'] = sucuriscan_settings_apiservice_timeout($nonce);
14023
+ $params['SettingsSection.ApiProtocol'] = sucuriscan_settings_apiservice_https($nonce);
14024
 
14025
  return SucuriScanTemplate::getSection('settings-apiservice', $params);
14026
  }
14170
  return SucuriScanTemplate::getSection('settings-apiservice-timeout', $params);
14171
  }
14172
 
14173
+ function sucuriscan_settings_apiservice_https($nonce)
14174
+ {
14175
+ $params = array();
14176
+
14177
+ $params['ApiProtocol.StatusNum'] = '1';
14178
+ $params['ApiProtocol.Status'] = 'Enabled';
14179
+ $params['ApiProtocol.SwitchText'] = 'Disable';
14180
+ $params['ApiProtocol.SwitchValue'] = 'http';
14181
+ $params['ApiProtocol.SwitchCssClass'] = 'button-danger';
14182
+ $params['ApiProtocol.WarningVisibility'] = 'visible';
14183
+ $params['ApiProtocol.ErrorVisibility'] = 'hidden';
14184
+ $params['ApiProtocol.AffectedUrls'] = '';
14185
+
14186
+ if ($nonce) {
14187
+ // Enable or disable the API service communication.
14188
+ if ($api_protocol = SucuriScanRequest::post(':api_protocol', 'http(s)?')) {
14189
+ $message = 'API communication protocol was set to <code>' . strtoupper($api_protocol) . '</code>';
14190
+
14191
+ SucuriScanEvent::report_info_event($message);
14192
+ SucuriScanEvent::notify_event('plugin_change', $message);
14193
+ SucuriScanOption::update_option(':api_protocol', $api_protocol);
14194
+ SucuriScanInterface::info($message);
14195
+ }
14196
+ }
14197
+
14198
+ $api_protocol = SucuriScanOption::get_option(':api_protocol');
14199
+
14200
+ if ($api_protocol !== 'https') {
14201
+ $params['ApiProtocol.StatusNum'] = '0';
14202
+ $params['ApiProtocol.Status'] = 'Disabled';
14203
+ $params['ApiProtocol.SwitchText'] = 'Enable';
14204
+ $params['ApiProtocol.SwitchValue'] = 'https';
14205
+ $params['ApiProtocol.SwitchCssClass'] = 'button-success';
14206
+ $params['ApiProtocol.WarningVisibility'] = 'hidden';
14207
+ $params['ApiProtocol.ErrorVisibility'] = 'visible';
14208
+ }
14209
+
14210
+ $counter = 0;
14211
+ $affected_urls = SucuriScanAPI::ambiguousApiUrls();
14212
+
14213
+ foreach ($affected_urls as $unique => $url) {
14214
+ $counter++;
14215
+ $url = SucuriScanAPI::apiUrlProtocol($url, $api_protocol);
14216
+ $css_class = ($counter % 2 === 0) ? 'alternate' : '';
14217
+ $params['ApiProtocol.AffectedUrls'] .= SucuriScanTemplate::getSnippet(
14218
+ 'settings-apiservice-protocol',
14219
+ array(
14220
+ 'ApiProtocol.CssClass' => $css_class,
14221
+ 'ApiProtocol.ID' => $unique,
14222
+ 'ApiProtocol.URL' => $url,
14223
+ )
14224
+ );
14225
+ }
14226
+
14227
+ return SucuriScanTemplate::getSection('settings-apiservice-protocol', $params);
14228
+ }
14229
+
14230
+ function sucuriscan_settings_apiservice_https_ajax()
14231
+ {
14232
+ if (SucuriScanRequest::post('form_action') == 'debug_api_call') {
14233
+ $unique = SucuriScanRequest::post('api_unique');
14234
+ $response = SucuriScanAPI::debugApiCall($unique);
14235
+
14236
+ header('Content-Type: application/json');
14237
+ print(@json_encode($response));
14238
+ exit(0);
14239
+ }
14240
+ }
14241
+
14242
  /**
14243
  * Read and parse the content of the self-hosting settings template.
14244
  *
14296
  SucuriScanInterface::info($message);
14297
  } elseif (strpos($monitor_fpath, $_SERVER['DOCUMENT_ROOT']) !== false) {
14298
  SucuriScanInterface::error('File should not be publicly accessible.');
14299
+ } elseif (file_exists($monitor_fpath)) {
14300
+ SucuriScanInterface::error('File already exists and will not be overwritten.');
14301
+ } elseif (!is_writable(dirname($monitor_fpath))) {
14302
+ SucuriScanInterface::error('File parent directory is not writable.');
14303
  } else {
14304
+ @file_put_contents($monitor_fpath, '', LOCK_EX);
14305
  $message = 'Log exporter file path was set correctly.';
14306
 
14307
  SucuriScanEvent::report_info_event($message);
14439
  return SucuriScanTemplate::getSection('settings-heartbeat', $params);
14440
  }
14441
 
14442
+ class SucuriScanSettings extends SucuriScanOption
14443
+ {
14444
+ }
14445
+
14446
  /**
14447
  * Print a HTML code with the settings of the plugin.
14448
  *
14457
 
14458
  $params['PageTitle'] = 'Settings';
14459
  $params['Settings.General'] = sucuriscan_settings_general($nonce);
14460
+ $params['Settings.Scanner'] = sucuriscan_settings_scanner($nonce);
14461
  $params['Settings.Alerts'] = sucuriscan_settings_alert($nonce);
14462
  $params['Settings.ApiService'] = sucuriscan_settings_apiservice($nonce);
14463
  $params['Settings.SelfHosting'] = sucuriscan_settings_selfhosting($nonce);
14464
+ $params['Settings.IgnoreScanning'] = sucuriscan_settings_ignorescan($nonce);
14465
  $params['Settings.IgnoreRules'] = sucuriscan_settings_ignore_rules();
14466
  $params['Settings.TrustIP'] = sucuriscan_settings_trust_ip();
14467
  $params['Settings.Heartbeat'] = sucuriscan_settings_heartbeat();
14469
  echo SucuriScanTemplate::getTemplate('settings', $params);
14470
  }
14471
 
14472
+ /**
14473
+ * Handle an Ajax request for this specific page.
14474
+ *
14475
+ * @return mixed.
14476
+ */
14477
+ function sucuriscan_settings_ajax()
14478
+ {
14479
+ SucuriScanInterface::check_permissions();
14480
+
14481
+ if (SucuriScanInterface::check_nonce()) {
14482
+ sucuriscan_settings_ignorescan_ajax();
14483
+ sucuriscan_settings_apiservice_https_ajax();
14484
+ }
14485
+
14486
+ wp_die();
14487
+ }
14488
+
14489
  /**
14490
  * Generate and print the HTML code for the InfoSys page.
14491
  *
14515
  echo SucuriScanTemplate::getTemplate('infosys', $params);
14516
  }
14517
 
14518
+ /**
14519
+ * Handle an Ajax request for this specific page.
14520
+ *
14521
+ * @return mixed.
14522
+ */
14523
+ function sucuriscan_infosys_ajax()
14524
+ {
14525
+ SucuriScanInterface::check_permissions();
14526
+
14527
+ if (SucuriScanInterface::check_nonce()) {
14528
+ sucuriscan_infosys_errorlogs_ajax();
14529
+ }
14530
+
14531
+ wp_die();
14532
+ }
14533
+
14534
  /**
14535
  * Find the main htaccess file for the site and check whether the rules of the
14536
  * main htaccess file of the site are the default rules generated by WordPress.
14723
  );
14724
 
14725
  $cronjobs = _get_cron_array();
 
14726
  $counter = 0;
14727
 
14728
  foreach ($cronjobs as $timestamp => $cronhooks) {
14806
  ));
14807
 
14808
  foreach ($cronjobs as $task_name) {
 
14809
  $next_due = wp_next_scheduled($task_name);
14810
  wp_schedule_event($next_due, $cronjob_action, $task_name);
14811
  }
14824
  */
14825
  function sucuriscan_infosys_errorlogs()
14826
  {
14827
+ $params = array();
14828
+ $nonce = SucuriScanInterface::check_nonce();
 
 
 
 
 
 
 
 
14829
 
14830
+ $params['ErrorLogs.Status'] = sucuriscan_infosys_errorlogs_status($nonce);
14831
+ $params['ErrorLogs.FileLimit'] = sucuriscan_infosys_errorlogs_flimit($nonce);
14832
+ $params['ErrorLogs.FileReader'] = sucuriscan_infosys_errorlogs_freader();
14833
+
14834
+ return SucuriScanTemplate::getSection('infosys-errorlogs', $params);
14835
+ }
14836
+
14837
+ function sucuriscan_infosys_errorlogs_status($nonce)
14838
+ {
14839
+ $params = array();
14840
+ $params['ErrorLogs.Status'] = 'Disabled';
14841
+ $params['ErrorLogs.SwitchText'] = 'Enable';
14842
+ $params['ErrorLogs.SwitchValue'] = 'enable';
14843
+ $params['ErrorLogs.SwitchCssClass'] = 'button-success';
14844
+
14845
+ if ($nonce) {
14846
+ // Enable or disable the error logs parsing.
14847
+ if ($errorlogs = SucuriScanRequest::post(':parse_errorlogs', '(en|dis)able')) {
14848
+ $action_d = $errorlogs . 'd';
14849
+ $message = 'Analysis of the error log file was <code>' . $action_d . '</code>';
14850
 
14851
+ SucuriScanOption::update_option(':parse_errorlogs', $action_d);
14852
+ SucuriScanEvent::report_auto_event($message);
14853
+ SucuriScanEvent::notify_event('plugin_change', $message);
14854
+ SucuriScanInterface::info($message);
14855
+ }
14856
  }
14857
 
14858
+ if (SucuriScanOption::is_enabled(':parse_errorlogs')) {
14859
+ $params['ErrorLogs.Status'] = 'Enabled';
14860
+ $params['ErrorLogs.SwitchText'] = 'Disable';
14861
+ $params['ErrorLogs.SwitchValue'] = 'disable';
14862
+ $params['ErrorLogs.SwitchCssClass'] = 'button-danger';
14863
  }
14864
 
14865
+ return SucuriScanTemplate::getSection('infosys-errorlogs-status', $params);
14866
+ }
 
 
14867
 
14868
+ function sucuriscan_infosys_errorlogs_flimit($nonce)
14869
+ {
14870
+ $params = array();
 
14871
 
14872
+ if ($nonce) {
14873
+ // Update the limit of error log lines to parse.
14874
+ if ($limit = SucuriScanRequest::post(':errorlogs_limit', '[0-9]+')) {
14875
+ $message = 'Error logs file limit set to <code>' . $limit . '</code> lines.';
 
 
 
 
 
 
 
 
 
 
 
 
 
14876
 
14877
+ SucuriScanOption::update_option(':errorlogs_limit', $limit);
14878
+ SucuriScanEvent::report_auto_event($message);
14879
+ SucuriScanEvent::notify_event('plugin_change', $message);
14880
+ SucuriScanInterface::info($message);
14881
  }
 
 
14882
  }
14883
 
14884
+ $params['ErrorLogs.LogsLimit'] = SucuriScanOption::get_option(':errorlogs_limit');
14885
+
14886
+ return SucuriScanTemplate::getSection('infosys-errorlogs-flimit', $params);
14887
+ }
14888
+
14889
+ function sucuriscan_infosys_errorlogs_freader()
14890
+ {
14891
+ $params = array();
14892
+
14893
+ return SucuriScanTemplate::getSection('infosys-errorlogs-freader', $params);
14894
+ }
14895
+
14896
+ function sucuriscan_infosys_errorlogs_ajax()
14897
+ {
14898
+ if (SucuriScanRequest::post('form_action') == 'get_error_logs') {
14899
+ $response = '';
14900
+
14901
+ // Scan the project and get the ignored paths.
14902
+ if (SucuriScanOption::is_enabled(':parse_errorlogs')) {
14903
+ $fname = SucuriScan::ini_get('error_log');
14904
+ $fpath = $fname ? @realpath(ABSPATH . '/' . $fname) : false;
14905
+
14906
+ if ($fpath !== false
14907
+ && is_file($fpath)
14908
+ && file_exists($fpath)
14909
+ && is_readable($fpath)
14910
+ ) {
14911
+ $limit = SucuriScanOption::get_option(':errorlogs_limit');
14912
+ $flines = SucuriScanFileInfo::tail_file($fpath, $limit);
14913
+ $error_logs = SucuriScanFSScanner::parse_error_logs($flines);
14914
+ $error_logs = array_reverse($error_logs);
14915
+ $counter = 0;
14916
+
14917
+ foreach ($error_logs as $log) {
14918
+ $css_class = ($counter % 2 === 0) ? '' : 'alternate';
14919
+ $response .= SucuriScanTemplate::getSnippet(
14920
+ 'infosys-errorlogs',
14921
+ array(
14922
+ 'ErrorLog.CssClass' => $css_class,
14923
+ 'ErrorLog.DateTime' => SucuriScan::datetime($log->timestamp),
14924
+ 'ErrorLog.ErrorType' => $log->error_type,
14925
+ 'ErrorLog.ErrorCode' => $log->error_code,
14926
+ 'ErrorLog.ErrorAbbr' => strtoupper(substr($log->error_code, 0, 1)),
14927
+ 'ErrorLog.ErrorMessage' => $log->error_message,
14928
+ 'ErrorLog.FilePath' => $log->file_path,
14929
+ 'ErrorLog.LineNumber' => $log->line_number,
14930
+ )
14931
+ );
14932
+ $counter++;
14933
+ }
14934
+ }
14935
+ }
14936
+
14937
+ if (empty($response)) {
14938
+ $response = '<tr><td colspan="5">List is empty.</td></tr>';
14939
+ }
14940
+
14941
+ print($response);
14942
+ exit(0);
14943
+ }
14944
  }
14945
 
14946
  /**
14973
  $info_vars['Datetime_and_Timezone'] = sprintf(
14974
  '%s (GMT %s)',
14975
  SucuriScan::current_datetime(),
14976
+ SucuriScanOption::get_option('gmt_offset')
14977
  );
14978
 
14979
  if (defined('WP_DEBUG') && WP_DEBUG) {
uninstall.php CHANGED
@@ -3,7 +3,6 @@
3
  * Uninstallation instructions.
4
  *
5
  * @package Sucuri Security
6
- * @author Yorman Arias <yorman.arias@sucuri.net>
7
  * @author Daniel Cid <dcid@sucuri.net>
8
  * @copyright Since 2010-2015 Sucuri Inc.
9
  * @license Released under the GPL - see LICENSE file for details.
@@ -22,6 +21,7 @@ $sucuriscan_option_names = array(
22
  'addr_header',
23
  'ads_visibility',
24
  'api_key',
 
25
  'api_service',
26
  'audit_report',
27
  'cloudproxy_apikey',
@@ -41,10 +41,12 @@ $sucuriscan_option_names = array(
41
  'heartbeat_pulse',
42
  'ignore_scanning',
43
  'ignored_events',
 
44
  'last_email_at',
45
  'lastlogin_redirection',
46
  'logs4report',
47
  'maximum_failed_logins',
 
48
  'notify_bruteforce_attack',
49
  'notify_failed_login',
50
  'notify_plugin_activated',
@@ -68,6 +70,7 @@ $sucuriscan_option_names = array(
68
  'notify_widget_added',
69
  'notify_widget_deleted',
70
  'parse_errorlogs',
 
71
  'prettify_mails',
72
  'request_timeout',
73
  'revproxy',
@@ -82,6 +85,7 @@ $sucuriscan_option_names = array(
82
  'site_version',
83
  'sitecheck_counter',
84
  'sitecheck_scanner',
 
85
  'use_wpmail',
86
  'verify_ssl_cert',
87
  'xhr_monitor',
@@ -103,6 +107,7 @@ if ($sucuriscan_storage_path !== false
103
  @unlink($sucuriscan_storage_path . '/sucuri-oldfailedlogins.php');
104
  @unlink($sucuriscan_storage_path . '/sucuri-plugindata.php');
105
  @unlink($sucuriscan_storage_path . '/sucuri-sitecheck.php');
 
106
  @unlink($sucuriscan_storage_path . '/sucuri-trustip.php');
107
 
108
  @rmdir($sucuriscan_storage_path);
3
  * Uninstallation instructions.
4
  *
5
  * @package Sucuri Security
 
6
  * @author Daniel Cid <dcid@sucuri.net>
7
  * @copyright Since 2010-2015 Sucuri Inc.
8
  * @license Released under the GPL - see LICENSE file for details.
21
  'addr_header',
22
  'ads_visibility',
23
  'api_key',
24
+ 'api_protocol',
25
  'api_service',
26
  'audit_report',
27
  'cloudproxy_apikey',
41
  'heartbeat_pulse',
42
  'ignore_scanning',
43
  'ignored_events',
44
+ 'language',
45
  'last_email_at',
46
  'lastlogin_redirection',
47
  'logs4report',
48
  'maximum_failed_logins',
49
+ 'notify_available_updates',
50
  'notify_bruteforce_attack',
51
  'notify_failed_login',
52
  'notify_plugin_activated',
70
  'notify_widget_added',
71
  'notify_widget_deleted',
72
  'parse_errorlogs',
73
+ 'plugin_version',
74
  'prettify_mails',
75
  'request_timeout',
76
  'revproxy',
85
  'site_version',
86
  'sitecheck_counter',
87
  'sitecheck_scanner',
88
+ 'sitecheck_timeout',
89
  'use_wpmail',
90
  'verify_ssl_cert',
91
  'xhr_monitor',
107
  @unlink($sucuriscan_storage_path . '/sucuri-oldfailedlogins.php');
108
  @unlink($sucuriscan_storage_path . '/sucuri-plugindata.php');
109
  @unlink($sucuriscan_storage_path . '/sucuri-sitecheck.php');
110
+ @unlink($sucuriscan_storage_path . '/sucuri-settings.php');
111
  @unlink($sucuriscan_storage_path . '/sucuri-trustip.php');
112
 
113
  @rmdir($sucuriscan_storage_path);