diff --git a/inc/spbc-backups.php b/inc/spbc-backups.php index 78a4e84ca..5fb6474ba 100644 --- a/inc/spbc-backups.php +++ b/inc/spbc-backups.php @@ -174,7 +174,7 @@ function spbc_backup__files_with_signatures_handler() $output = array('success' => true); - $files_to_backup = $wpdb->get_results('SELECT path, weak_spots, checked_heuristic, checked_signatures, status, severity FROM ' . SPBC_TBL_SCAN_FILES . ' WHERE weak_spots LIKE "%\"SIGNATURES\":%";', ARRAY_A); + $files_to_backup = $wpdb->get_results('SELECT path, weak_spots, checked_heuristic, checked_signatures, status, severity FROM ' . SPBC_TBL_SCAN_FILES . ' WHERE weak_spots LIKE "%\"SIGNATURES\":%" AND source != \'BINARY\';', ARRAY_A); if (!is_array($files_to_backup) || !count($files_to_backup)) { $output = array('success' => true); diff --git a/inc/spbc-settings.php b/inc/spbc-settings.php index d2486c918..548fcb10d 100644 --- a/inc/spbc-settings.php +++ b/inc/spbc-settings.php @@ -685,6 +685,12 @@ function spbc_settings__register() 'description' => __('Will search for known malicious signatures in files. Unknown files will be shown in the results only if both options heuristic analysis and signature analysis are enabled.', 'security-malware-firewall'), 'long_description' => true, ), + 'scanner__binary_analysis' => array( + 'type' => 'field', + 'title' => __('Binary analysis', 'security-malware-firewall'), + 'description' => __('Search for suspicious binary patterns in files.', 'security-malware-firewall'), + 'long_description' => false, + ), 'scanner__os_cron_analysis' => array( 'type' => 'field', 'title' => Scanner\OSCron\View\OSCronLocale::getInstance()->settings__option_title, @@ -2383,6 +2389,15 @@ function spbc_field_scanner__prepare_data__files(&$table) unset($row->actions['delete']); } + // Binary files: restrict modification/analysis actions, allow only approve/delete/quarantine + if ( isset($row->source) && $row->source === 'BINARY' ) { + unset($row->actions['send']); + unset($row->actions['view']); + unset($row->actions['view_bad']); + unset($row->actions['replace']); + unset($row->actions['compare']); + } + $table->items[] = array( 'cb' => $row->fast_hash, 'uid' => $row->fast_hash, @@ -3014,6 +3029,12 @@ function spbc_field_scanner() . ' -> '; } + if ($spbc->settings['scanner__binary_analysis']) { + echo '' + . __('Binary analysis', 'security-malware-firewall') + . ' -> '; + } + if ($spbc->settings['scanner__schedule_send_heuristic_suspicious_files']) { echo '' . __('Schedule suspicious files sending', 'security-malware-firewall') diff --git a/js/spbc-scanner-plugin.min.js b/js/spbc-scanner-plugin.min.js index e635fef3e..3f805b82b 100644 --- a/js/spbc-scanner-plugin.min.js +++ b/js/spbc-scanner-plugin.min.js @@ -1,2 +1,2 @@ -class SpbcMalwareScanner{first_start=!0;active=!1;root="";settings=[];states=["get_cms_hashes","get_modules_hashes","clean_results","file_system_analysis","get_approved_hashes","get_denied_hashes","signature_analysis","heuristic_analysis","schedule_send_heuristic_suspicious_files","auto_cure_backup","auto_cure","os_cron_analysis","db_trigger_analysis","outbound_links","frontend_analysis","important_files_listing","send_results"];state=null;offset=0;amount=0;amount_coefficient=1;total_scanned=0;scan_percent=0;percent_completed=0;paused=!1;button=null;spinner=null;progress_overall=null;progressbar=null;progressbar_text=null;timeout=6e4;state_timer=0;constructor(t){for(var e in jQuery("#spbcscan-results-log-module").length&&jQuery(".spbc-scan-log-title").removeClass("spbc---hidden"),void 0!==t.settings.auto_cure&&(t.settings.scanner__auto_cure_backup="1"),t)void 0!==this[e]&&(this[e]=t[e])}actionControl(){null===this.state?this.start():this.paused?(this.resume(),this.controller()):this.pause()}start(){this.active=!0,this.state_timer=Math.round((new Date).getTime()/1e3),this.state=this.getNextState(null),this.setPercents(0),this.scan_percent=0,this.offset=0,this.progress_overall.children("span").removeClass("spbc_bold").filter(".spbc_overall_scan_status_"+this.state).addClass("spbc_bold"),this.progressbar.show(500),this.progress_overall.show(500),this.button.html(spbcScaner.button_scan_pause),this.spinner.css({display:"inline"}),setTimeout(()=>{this.controller()},1e3)}pause(t,e,s){console.log("PAUSE"),this.button.html(spbcScaner.button_scan_resume),this.spinner.css({display:"none"}),this.paused=!0,this.active=!1}resume(t){console.log("RESUME"),this.button.html(spbcScaner.button_scan_pause),this.spinner.css({display:"inline"}),this.paused=!1,this.active=!0}end(t){this.progressbar.hide(500),this.progress_overall.hide(500),this.button.html(spbcScaner.button_scan_perform),this.spinner.css({display:"none"}),this.state=null,this.plug=!1,this.total_scanned=0,this.active=!1,t?document.location=document.location:spbcSendAJAXRequest({action:"spbc_scanner_tab__reload_accordion"},{notJson:!0,callback:function(t,e,s,a){jQuery(a).accordion("destroy").html(t).accordion({header:"h3",heightStyle:"content",collapsible:!0,active:!1}),spbcTblBulkActionsListen(),spbcTblRowActionsListen(),spbcTblPaginationListen(),spbcTblSortListen(),spbcStartShowHide(),spbcScannerReloadScanInfo()}},jQuery("#spbc_scan_accordion"))}controller(t){if(console.log(this.state),void 0!==t&&t.end){if(this.state=this.getNextState(this.state),void 0===this.state)return void this.end();this.setPercents(0),this.scan_percent=0,this.offset=0,this.progress_overall.children("span").removeClass("spbc_bold").filter(".spbc_overall_scan_status_"+this.state).addClass("spbc_bold")}if(!0!==this.paused){var e={action:"spbc_scanner_controller_front",method:this.state,offset:this.offset},t={type:"GET",success:this.success,callback:this.successCallback,error:this.error,errorOutput:this.errorOutput,complete:null,context:this,timeout:12e4};switch(this.state){case"get_modules_hashes":this.amount=2;break;case"clear_table":this.amount=1e4;break;case"file_system_analysis":this.amount=700;break;case"auto_cure":this.amount=5;break;case"outbound_links":this.amount=10;break;case"frontend_analysis":this.amount=spbcSettings.frontendAnalysisAmount;break;case"signature_analysis":this.amount=10,e.status="UNKNOWN,MODIFIED,OK,INFECTED,ERROR";break;case"heuristic_analysis":this.amount=4,e.status="UNKNOWN,MODIFIED,OK,INFECTED,ERROR";break;case"schedule_send_heuristic_suspicious_files":this.amount=1}e.amount=Math.round(this.amount*this.amount_coefficient),spbcSendAJAXRequest(e,t,jQuery("#spbc_scan_accordion"))}}setCoefficients(t){let e=this.amount_coefficient;"file_system_analysis"===t&&(e*=1.5),this.amount_coefficient=e}getNextState(t){return t=null===t?this.states[0]:this.states[this.states.indexOf(t)+1],t=void 0!==this.settings["scanner__"+t]&&0==+this.settings["scanner__"+t]?this.getNextState(t):t}setPercents(t){this.percent_completed=Math.floor(100*t)/100,this.progressbar.progressbar("option","value",this.percent_completed),this.progressbar_text.text(spbcScaner["progressbar_"+this.state]+" - "+this.percent_completed+"%")}success(t){t.error?this.error({status:200,responseText:t.error},t.error,t.msg):this.successCallback&&this.successCallback(t,this.data,this.obj)}successCallback(e){if(console.log(e),this.interactAccordion(e),void 0!==e.total&&(this.scan_percent=100/e.total),void 0!==e.processed_items&&("heuristic_analysis"===this.state&&0!==typeof e.total&&this.logRaw('

Heuristic Analysis

'),"signature_analysis"===this.state&&0!==typeof e.total&&this.logRaw('

Signature Analysis

'),this.logFileEntry(e.processed_items)),void 0!==e.stage_data_for_logging&&this.logStageEntry(e.stage_data_for_logging),void 0!==e.cured&&0{this.controller(e)},300)}interactAccordion(t){t.hasOwnProperty("interactivity_data")&&t.interactivity_data.hasOwnProperty("update_text")&&t.interactivity_data.update_text&&t.interactivity_data.hasOwnProperty("refresh_data")&&t.interactivity_data.refresh_data.hasOwnProperty("do_refresh")&&t.interactivity_data.refresh_data.do_refresh&&t.interactivity_data.refresh_data.hasOwnProperty("control_tab")&&t.interactivity_data.refresh_data.control_tab&&spbcReloadAccordion(t.interactivity_data.refresh_data.control_tab,t.interactivity_data.update_text)}error(t,e,s){var a=this.errorOutput;if(console.log("%c APBCT_AJAX_ERROR","color: red;"),console.log(e),console.log(s),console.log(t),"error"==e&&(""==s||"Not found"==s)&&(this.tryCount||(this.tryCount=0,this.retryLimit=30),this.tryCount++,console.log("Try #"+this.tryCount),this.setCoefficients(this.state),this.tryCount<=this.retryLimit))this.pause(),this.resume(),this.controller();else{if(200===t.status)if("parsererror"===e)a("Unexpected response from server. See console for details.",this.state),console.log("%c "+t.responseText,"color: pink;");else{let t=e;void 0!==s&&(t+=" Additional info: "+s),a(t,this.state)}else 500===t.status?a("Internal server error.",this.state):a("Unexpected response code: "+t.status+". Error: "+e,this.state);this.progressbar&&this.progressbar.fadeOut("slow"),this.end()}}errorOutput(t,e){spbcModal.open().putError(t+"
Stage: "+e)}logRaw(t){jQuery(".spbc-scan-log-title").removeClass("spbc---hidden"),jQuery(".spbc_log-wrapper").removeClass("spbc---hidden"),jQuery(".spbc_log-wrapper .panel-body").prepend(t)}logFileEntry(t){for(var e in t)e&&this.logRaw('

'+this.getSiteUTCShiftedTimeString()+" - "+t[e].path+" - "+t[e].module+": "+t[e].status+"

")}logStageEntry(t){void 0!==jQuery(".panel-body .spbc_log-line span").first()&&void 0!==jQuery(".panel-body .spbc_log-line span").first()[0]&&jQuery(".panel-body .spbc_log-line span").first()[0].textContent===t.description||this.logRaw('

test '+this.getSiteUTCShiftedTimeString()+" - "+t.title+" "+t.description+"

")}showLinkForShuffleSalts(t){jQuery("#spbc_notice_about_shuffle_link").remove(),jQuery(jQuery(".spbc_tab--active .spbc_wrapper_field p")[1]).after('")}getSiteUTCShiftedTimeString(){let t=!1;var e=-1*(new Date).getTimezoneOffset()*1e3*60,e=(t="undefined"!=typeof spbcScaner&&void 0!==spbcScaner.timezone_shift&&!1!==spbcScaner.timezone_shift?Date.now()-e+1e3*spbcScaner.timezone_shift:t)?new Date(t):new Date,s=new Intl.DateTimeFormat("en-US",{month:"short"}).format,a=String(e.getMinutes()).padStart(2,"0"),i=String(e.getSeconds()).padStart(2,"0");return s(e)+" "+e.getDate()+" "+e.getFullYear()+" "+e.getHours()+":"+a+":"+i}} +class SpbcMalwareScanner{first_start=!0;active=!1;root="";settings=[];states=["get_cms_hashes","get_modules_hashes","clean_results","file_system_analysis","get_approved_hashes","get_denied_hashes","signature_analysis","heuristic_analysis","schedule_send_heuristic_suspicious_files","auto_cure_backup","auto_cure","os_cron_analysis","db_trigger_analysis","binary_analysis","outbound_links","frontend_analysis","important_files_listing","send_results"];state=null;offset=0;amount=0;amount_coefficient=1;total_scanned=0;scan_percent=0;percent_completed=0;paused=!1;button=null;spinner=null;progress_overall=null;progressbar=null;progressbar_text=null;timeout=6e4;state_timer=0;constructor(t){for(var e in jQuery("#spbcscan-results-log-module").length&&jQuery(".spbc-scan-log-title").removeClass("spbc---hidden"),void 0!==t.settings.auto_cure&&(t.settings.scanner__auto_cure_backup="1"),t)void 0!==this[e]&&(this[e]=t[e])}actionControl(){null===this.state?this.start():this.paused?(this.resume(),this.controller()):this.pause()}start(){this.active=!0,this.state_timer=Math.round((new Date).getTime()/1e3),this.state=this.getNextState(null),this.setPercents(0),this.scan_percent=0,this.offset=0,this.progress_overall.children("span").removeClass("spbc_bold").filter(".spbc_overall_scan_status_"+this.state).addClass("spbc_bold"),this.progressbar.show(500),this.progress_overall.show(500),this.button.html(spbcScaner.button_scan_pause),this.spinner.css({display:"inline"}),setTimeout(()=>{this.controller()},1e3)}pause(t,e,s){console.log("PAUSE"),this.button.html(spbcScaner.button_scan_resume),this.spinner.css({display:"none"}),this.paused=!0,this.active=!1}resume(t){console.log("RESUME"),this.button.html(spbcScaner.button_scan_pause),this.spinner.css({display:"inline"}),this.paused=!1,this.active=!0}end(t){this.progressbar.hide(500),this.progress_overall.hide(500),this.button.html(spbcScaner.button_scan_perform),this.spinner.css({display:"none"}),this.state=null,this.plug=!1,this.total_scanned=0,this.active=!1,t?document.location=document.location:spbcSendAJAXRequest({action:"spbc_scanner_tab__reload_accordion"},{notJson:!0,callback:function(t,e,s,a){jQuery(a).accordion("destroy").html(t).accordion({header:"h3",heightStyle:"content",collapsible:!0,active:!1}),spbcTblBulkActionsListen(),spbcTblRowActionsListen(),spbcTblPaginationListen(),spbcTblSortListen(),spbcStartShowHide(),spbcScannerReloadScanInfo()}},jQuery("#spbc_scan_accordion"))}controller(t){if(console.log(this.state),void 0!==t&&t.end){if(this.state=this.getNextState(this.state),void 0===this.state)return void this.end();this.setPercents(0),this.scan_percent=0,this.offset=0,this.progress_overall.children("span").removeClass("spbc_bold").filter(".spbc_overall_scan_status_"+this.state).addClass("spbc_bold")}if(!0!==this.paused){var e={action:"spbc_scanner_controller_front",method:this.state,offset:this.offset},t={type:"GET",success:this.success,callback:this.successCallback,error:this.error,errorOutput:this.errorOutput,complete:null,context:this,timeout:12e4};switch(this.state){case"get_modules_hashes":this.amount=2;break;case"clear_table":this.amount=1e4;break;case"file_system_analysis":this.amount=700;break;case"auto_cure":this.amount=5;break;case"outbound_links":this.amount=10;break;case"frontend_analysis":this.amount=spbcSettings.frontendAnalysisAmount;break;case"signature_analysis":this.amount=10,e.status="UNKNOWN,MODIFIED,OK,INFECTED,ERROR";break;case"heuristic_analysis":case"binary_analysis":this.amount=4,e.status="UNKNOWN,MODIFIED,OK,INFECTED,ERROR";break;case"schedule_send_heuristic_suspicious_files":this.amount=1}e.amount=Math.round(this.amount*this.amount_coefficient),spbcSendAJAXRequest(e,t,jQuery("#spbc_scan_accordion"))}}setCoefficients(t){let e=this.amount_coefficient;"file_system_analysis"===t&&(e*=1.5),this.amount_coefficient=e}getNextState(t){return t=null===t?this.states[0]:this.states[this.states.indexOf(t)+1],t=void 0!==this.settings["scanner__"+t]&&0==+this.settings["scanner__"+t]?this.getNextState(t):t}setPercents(t){this.percent_completed=Math.floor(100*t)/100,this.progressbar.progressbar("option","value",this.percent_completed),this.progressbar_text.text(spbcScaner["progressbar_"+this.state]+" - "+this.percent_completed+"%")}success(t){t.error?this.error({status:200,responseText:t.error},t.error,t.msg):this.successCallback&&this.successCallback(t,this.data,this.obj)}successCallback(e){if(console.log(e),this.interactAccordion(e),void 0!==e.total&&(this.scan_percent=100/e.total),void 0!==e.processed_items&&("heuristic_analysis"===this.state&&0!==typeof e.total&&this.logRaw('

Heuristic Analysis

'),"signature_analysis"===this.state&&0!==typeof e.total&&this.logRaw('

Signature Analysis

'),this.logFileEntry(e.processed_items)),void 0!==e.stage_data_for_logging&&this.logStageEntry(e.stage_data_for_logging),void 0!==e.cured&&0{this.controller(e)},300)}interactAccordion(t){t.hasOwnProperty("interactivity_data")&&t.interactivity_data.hasOwnProperty("update_text")&&t.interactivity_data.update_text&&t.interactivity_data.hasOwnProperty("refresh_data")&&t.interactivity_data.refresh_data.hasOwnProperty("do_refresh")&&t.interactivity_data.refresh_data.do_refresh&&t.interactivity_data.refresh_data.hasOwnProperty("control_tab")&&t.interactivity_data.refresh_data.control_tab&&spbcReloadAccordion(t.interactivity_data.refresh_data.control_tab,t.interactivity_data.update_text)}error(t,e,s){var a=this.errorOutput;if(console.log("%c APBCT_AJAX_ERROR","color: red;"),console.log(e),console.log(s),console.log(t),"error"==e&&(""==s||"Not found"==s)&&(this.tryCount||(this.tryCount=0,this.retryLimit=30),this.tryCount++,console.log("Try #"+this.tryCount),this.setCoefficients(this.state),this.tryCount<=this.retryLimit))this.pause(),this.resume(),this.controller();else{if(200===t.status)if("parsererror"===e)a("Unexpected response from server. See console for details.",this.state),console.log("%c "+t.responseText,"color: pink;");else{let t=e;void 0!==s&&(t+=" Additional info: "+s),a(t,this.state)}else 500===t.status?a("Internal server error.",this.state):a("Unexpected response code: "+t.status+". Error: "+e,this.state);this.progressbar&&this.progressbar.fadeOut("slow"),this.end()}}errorOutput(t,e){spbcModal.open().putError(t+"
Stage: "+e)}logRaw(t){jQuery(".spbc-scan-log-title").removeClass("spbc---hidden"),jQuery(".spbc_log-wrapper").removeClass("spbc---hidden"),jQuery(".spbc_log-wrapper .panel-body").prepend(t)}logFileEntry(t){for(var e in t)e&&this.logRaw('

'+this.getSiteUTCShiftedTimeString()+" - "+t[e].path+" - "+t[e].module+": "+t[e].status+"

")}logStageEntry(t){void 0!==jQuery(".panel-body .spbc_log-line span").first()&&void 0!==jQuery(".panel-body .spbc_log-line span").first()[0]&&jQuery(".panel-body .spbc_log-line span").first()[0].textContent===t.description||this.logRaw('

test '+this.getSiteUTCShiftedTimeString()+" - "+t.title+" "+t.description+"

")}showLinkForShuffleSalts(t){jQuery("#spbc_notice_about_shuffle_link").remove(),jQuery(jQuery(".spbc_tab--active .spbc_wrapper_field p")[1]).after('")}getSiteUTCShiftedTimeString(){let t=!1;var e=-1*(new Date).getTimezoneOffset()*1e3*60,e=(t="undefined"!=typeof spbcScaner&&void 0!==spbcScaner.timezone_shift&&!1!==spbcScaner.timezone_shift?Date.now()-e+1e3*spbcScaner.timezone_shift:t)?new Date(t):new Date,s=new Intl.DateTimeFormat("en-US",{month:"short"}).format,a=String(e.getMinutes()).padStart(2,"0"),i=String(e.getSeconds()).padStart(2,"0");return s(e)+" "+e.getDate()+" "+e.getFullYear()+" "+e.getHours()+":"+a+":"+i}} //# sourceMappingURL=spbc-scanner-plugin.min.js.map diff --git a/js/spbc-scanner-plugin.min.js.map b/js/spbc-scanner-plugin.min.js.map index d43b21e41..403885ce3 100644 --- a/js/spbc-scanner-plugin.min.js.map +++ b/js/spbc-scanner-plugin.min.js.map @@ -1 +1 @@ -{"version":3,"file":"spbc-scanner-plugin.min.js","sources":["spbc-scanner-plugin.js"],"sourcesContent":["'use strict';\n\n/**\n * class SpbcMalwareScanner\n */\nclass SpbcMalwareScanner {/* eslint-disable-line no-unused-vars */\n first_start = true;\n\n active = false;\n\n root = '';\n settings = [];\n states = [\n 'get_cms_hashes',\n 'get_modules_hashes',\n 'clean_results',\n 'file_system_analysis',\n 'get_approved_hashes',\n 'get_denied_hashes',\n 'signature_analysis',\n 'heuristic_analysis',\n 'schedule_send_heuristic_suspicious_files',\n 'auto_cure_backup',\n 'auto_cure',\n 'os_cron_analysis',\n 'db_trigger_analysis',\n 'outbound_links',\n 'frontend_analysis',\n 'important_files_listing',\n 'send_results',\n ];\n state = null;\n offset = 0;\n amount = 0;\n amount_coefficient = 1;\n total_scanned = 0;\n scan_percent = 0;\n percent_completed = 0;\n\n paused = false;\n\n button = null;\n spinner = null;\n\n progress_overall = null;\n progressbar = null;\n progressbar_text = null;\n\n timeout = 60000;\n\n state_timer = 0;\n\n /**\n * constructor\n * @param {array} properties\n */\n constructor( properties ) {\n if (jQuery('#spbcscan-results-log-module').length) {\n jQuery('.spbc-scan-log-title').removeClass('spbc---hidden');\n }\n\n // Crunch for cure backups\n if ( typeof properties['settings']['auto_cure'] !== 'undefined' ) {\n properties['settings']['scanner__auto_cure_backup'] = '1';\n }\n\n for ( let key in properties ) {\n if ( typeof this[key] !== 'undefined' ) {\n this[key] = properties[key];\n }\n }\n };\n\n /**\n * Function Action Control\n */\n actionControl() {\n if (this.state === null) {\n this.start();\n } else if (this.paused) {\n this.resume();\n this.controller();\n } else {\n this.pause();\n }\n };\n\n /**\n * Function Start\n */\n start() {\n this.active = true;\n this.state_timer = Math.round(new Date().getTime() /1000);\n\n this.state = this.getNextState( null );\n\n this.setPercents( 0 );\n this.scan_percent = 0;\n this.offset = 0;\n this.progress_overall.children('span')\n .removeClass('spbc_bold')\n .filter('.spbc_overall_scan_status_' + this.state)\n .addClass('spbc_bold');\n\n this.progressbar.show(500);\n this.progress_overall.show(500);\n this.button.html(spbcScaner.button_scan_pause);\n this.spinner.css({display: 'inline'});\n\n setTimeout(() => {\n this.controller();\n }, 1000);\n };\n\n /**\n * Function Pause\n * @param {*} result\n * @param {*} data\n * @param {*} opt\n */\n pause( result, data, opt ) {\n console.log('PAUSE');\n this.button.html(spbcScaner.button_scan_resume);\n this.spinner.css({display: 'none'});\n this.paused = true;\n this.active = false;\n };\n\n /**\n * Function Resume\n * @param {*} opt\n */\n resume( opt ) {\n console.log('RESUME');\n this.button.html(spbcScaner.button_scan_pause);\n this.spinner.css({display: 'inline'});\n this.paused = false;\n this.active = true;\n };\n\n /**\n * Function End\n * @param {bool} reload\n */\n end( reload ) {\n this.progressbar.hide(500);\n this.progress_overall.hide(500);\n this.button.html(spbcScaner.button_scan_perform);\n this.spinner.css({display: 'none'});\n this.state = null;\n this.plug = false;\n this.total_scanned = 0;\n this.active = false;\n\n if (reload) {\n document.location = document.location;\n } else {\n spbcSendAJAXRequest(\n {action: 'spbc_scanner_tab__reload_accordion'},\n {\n notJson: true,\n callback: function(result, data, params, obj) {\n jQuery(obj).accordion('destroy')\n .html(result)\n .accordion({\n header: 'h3',\n heightStyle: 'content',\n collapsible: true,\n active: false,\n });\n spbcTblBulkActionsListen();\n spbcTblRowActionsListen();\n spbcTblPaginationListen();\n spbcTblSortListen();\n spbcStartShowHide();\n spbcScannerReloadScanInfo();\n },\n },\n jQuery('#spbc_scan_accordion'),\n );\n }\n };\n\n /**\n * Function Controller\n * @param {obj} result\n */\n controller( result ) {\n console.log(this.state);\n\n // The current stage is over. Switching to the new one\n if ( typeof result !== 'undefined' && result.end ) {\n this.state = this.getNextState( this.state );\n\n // End condition\n if (typeof this.state === 'undefined') {\n this.end();\n return;\n }\n\n // Set percent to 0\n this.setPercents( 0 );\n this.scan_percent = 0;\n this.offset = 0;\n\n // Changing visualizing of the current stage\n this.progress_overall.children('span')\n .removeClass('spbc_bold')\n .filter('.spbc_overall_scan_status_' + this.state)\n .addClass('spbc_bold');\n }\n\n // Break execution if paused\n if ( this.paused === true ) {\n return;\n }\n\n // // AJAX params\n let data = {\n action: 'spbc_scanner_controller_front',\n method: this.state,\n offset: this.offset,\n };\n\n let params = {\n type: 'GET',\n success: this.success,\n callback: this.successCallback,\n error: this.error,\n errorOutput: this.errorOutput,\n complete: null,\n context: this,\n timeout: 120000,\n };\n\n switch (this.state) {\n case 'get_modules_hashes': this.amount = 2; break;\n case 'clear_table': this.amount = 10000; break;\n case 'file_system_analysis': this.amount = 700; break;\n case 'auto_cure': this.amount = 5; break;\n case 'outbound_links': this.amount = 10; break;\n case 'frontend_analysis': this.amount = spbcSettings.frontendAnalysisAmount; break;\n case 'signature_analysis': this.amount = 10; data.status = 'UNKNOWN,MODIFIED,OK,INFECTED,ERROR'; break;\n case 'heuristic_analysis': this.amount = 4; data.status = 'UNKNOWN,MODIFIED,OK,INFECTED,ERROR'; break;\n case 'schedule_send_heuristic_suspicious_files': this.amount = 1; break;\n }\n\n data.amount = Math.round(this.amount * this.amount_coefficient);\n\n spbcSendAJAXRequest(\n data,\n params,\n jQuery('#spbc_scan_accordion'),\n );\n };\n\n /**\n * Set Coefficients\n * @param {string} state\n */\n setCoefficients( state ) {\n let coefficient = this.amount_coefficient;\n switch (state) {\n case 'file_system_analysis': coefficient *= 1.5; break;\n }\n this.amount_coefficient = coefficient;\n };\n\n /**\n * Get Next State\n * @param {string} state\n * @return {number}\n */\n getNextState( state ) {\n state = state === null ? this.states[0] : this.states[this.states.indexOf( state ) + 1];\n\n if (typeof this.settings['scanner__' + state] !== 'undefined' && +this.settings['scanner__' + state] === 0) {\n state = this.getNextState( state );\n }\n\n return state;\n };\n\n /**\n * Set Percents\n * @param {number} percents\n */\n setPercents( percents ) {\n this.percent_completed = Math.floor( percents * 100 ) / 100;\n this.progressbar.progressbar( 'option', 'value', this.percent_completed );\n this.progressbar_text.text( spbcScaner['progressbar_' + this.state] + ' - ' + this.percent_completed + '%' );\n };\n\n /**\n * Function Success\n * @param {obj} response\n */\n success( response ) {\n if ( !! response.error ) {\n this.error(\n {status: 200, responseText: response.error},\n response.error,\n response.msg,\n );\n } else {\n if ( this.successCallback ) {\n this.successCallback( response, this.data, this.obj );\n }\n }\n };\n\n // Processing response from backend\n /**\n * Success Callback\n * @param {obj} result\n */\n successCallback( result ) {\n console.log( result );\n\n this.interactAccordion(result);\n\n if ( typeof result.total !== 'undefined' ) {\n this.scan_percent = 100 / result.total;\n }\n\n if ( typeof result.processed_items !== 'undefined') {\n if ( this.state === 'heuristic_analysis' && typeof result.total !== 0 ) {\n this.logRaw('

Heuristic Analysis

');\n }\n if ( this.state === 'signature_analysis' && typeof result.total !== 0 ) {\n this.logRaw('

Signature Analysis

');\n }\n\n this.logFileEntry( result.processed_items );\n }\n\n if ( typeof result.stage_data_for_logging !== 'undefined') {\n this.logStageEntry( result.stage_data_for_logging );\n }\n\n // Add link on shuffle salt if cured\n if (result.cured !== undefined && Number(result.cured) > 0) {\n this.showLinkForShuffleSalts(result.message);\n }\n\n if ( result.end !== true && result.end !== 1 ) {\n let processedPercents = this.percent_completed + result.processed * this.scan_percent;\n if (result.stage_data_for_logging.title === 'File System Analysis' && processedPercents > 100) {\n processedPercents = 100;\n }\n this.setPercents(processedPercents);\n this.offset = this.offset + result.processed;\n this.controller( result );\n } else {\n console.log( this.state +\n ' stage took ' +\n ( Math.round(new Date().getTime() /1000) - this.state_timer ) +\n ' seconds to complete' );\n this.state_timer = Math.round(new Date().getTime()/1000);\n this.setPercents( 100 );\n this.scan_percent = 0;\n this.offset = 0;\n setTimeout(() => {\n this.controller( result );\n }, 300);\n }\n };\n\n /**\n * Run interactive refresh for accordion.\n * @param {obj|string[]} result\n */\n interactAccordion(result) {\n // validation control\n if (result.hasOwnProperty('interactivity_data') &&\n result.interactivity_data.hasOwnProperty('update_text') &&\n result.interactivity_data.update_text &&\n result.interactivity_data.hasOwnProperty('refresh_data') &&\n result.interactivity_data.refresh_data.hasOwnProperty('do_refresh') &&\n result.interactivity_data.refresh_data.do_refresh &&\n result.interactivity_data.refresh_data.hasOwnProperty('control_tab') &&\n result.interactivity_data.refresh_data.control_tab\n ) {\n spbcReloadAccordion(\n result.interactivity_data.refresh_data.control_tab,\n result.interactivity_data.update_text,\n );\n }\n }\n\n /**\n * Function Error\n * @param {object} xhr\n * @param {string} status\n * @param {string} error\n */\n error( xhr, status, error ) {\n let errorOutput = this.errorOutput;\n\n console.log( '%c APBCT_AJAX_ERROR', 'color: red;' );\n console.log( status );\n console.log( error );\n console.log( xhr );\n\n if (status == 'error' && (error == '' || error == 'Not found')) {\n if (!this.tryCount) {\n this.tryCount = 0;\n this.retryLimit = 30;\n }\n this.tryCount++;\n console.log('Try #' + this.tryCount);\n this.setCoefficients(this.state);\n if (this.tryCount <= this.retryLimit) {\n this.pause();\n this.resume();\n this.controller();\n return;\n }\n }\n\n if ( xhr.status === 200 ) {\n if ( status === 'parsererror' ) {\n errorOutput( 'Unexpected response from server. See console for details.', this.state );\n console.log( '%c ' + xhr.responseText, 'color: pink;' );\n } else {\n let errorString = status;\n if ( typeof error !== 'undefined' ) {\n errorString += ' Additional info: ' + error;\n }\n errorOutput( errorString, this.state );\n }\n } else if (xhr.status === 500) {\n errorOutput( 'Internal server error.', this.state);\n } else {\n errorOutput('Unexpected response code: ' + xhr.status + '. Error: ' + status, this.state);\n }\n\n if ( this.progressbar ) {\n this.progressbar.fadeOut('slow');\n }\n\n this.end();\n };\n\n /**\n * Error Output\n * @param {string} errorMsg\n * @param {string} stage\n */\n errorOutput( errorMsg, stage ) {\n spbcModal.open().putError( errorMsg + '
Stage: ' + stage);\n };\n\n /**\n * Log Raw\n * @param {htmlString|Element|Text|Array|jQuery} messageToLog\n */\n logRaw(messageToLog) {\n jQuery('.spbc-scan-log-title').removeClass('spbc---hidden');\n jQuery('.spbc_log-wrapper').removeClass('spbc---hidden');\n jQuery('.spbc_log-wrapper .panel-body').prepend( messageToLog );\n };\n\n /**\n * Log File Entry\n * @param {array} items\n */\n logFileEntry(items) {\n for ( let key in items ) {\n if ( key ) {\n this.logRaw(\n '

' +\n this.getSiteUTCShiftedTimeString() + ' - ' +\n items[key].path + ' - ' + items[key].module +\n ': ' + items[key].status + '' +\n '

');\n }\n }\n };\n\n /**\n * Log Stage Entry\n * @param {obj} data\n */\n logStageEntry(data) {\n if (typeof jQuery('.panel-body .spbc_log-line span').first() !== 'undefined' &&\n typeof jQuery('.panel-body .spbc_log-line span').first()[0] !== 'undefined' &&\n jQuery('.panel-body .spbc_log-line span').first()[0].textContent === data.description\n ) {\n return;\n }\n this.logRaw( '

test ' +\n this.getSiteUTCShiftedTimeString() + ' - ' + '' +\n data.title + ' ' + '' + data.description + '

' );\n };\n\n /**\n * Show Link For Shuffle Salts\n * @param {string} message\n */\n showLinkForShuffleSalts(message) {\n jQuery('#spbc_notice_about_shuffle_link').remove();\n jQuery(jQuery('.spbc_tab--active .spbc_wrapper_field p')[1])\n .after(\n '
' +\n '' +\n message +\n '' +\n '
',\n );\n }\n\n /**\n * Get Site UTC Shifted Time String\n * @return {string}\n */\n getSiteUTCShiftedTimeString() {\n let utcShiftedTs = false;\n // gettings current system/browser offset\n let currentBrowserOffset = new Date().getTimezoneOffset();\n currentBrowserOffset = currentBrowserOffset * -1 * 1000 * 60;\n // chek if global ct object is defined\n if (typeof spbcScaner !== 'undefined' &&\n typeof spbcScaner.timezone_shift !== 'undefined' &&\n spbcScaner.timezone_shift !== false) {\n utcShiftedTs = Date.now() - currentBrowserOffset + (spbcScaner.timezone_shift * 1000);\n }\n let ctDate = utcShiftedTs ? new Date(utcShiftedTs) : new Date();\n // construct date string\n let shortMonthName = new Intl.DateTimeFormat('en-US', {month: 'short'}).format;\n let minutes = String(ctDate.getMinutes()).padStart(2, '0');\n let seconds = String(ctDate.getSeconds()).padStart(2, '0');\n return shortMonthName(ctDate) + ' ' +\n ctDate.getDate() + ' ' + ctDate.getFullYear() + ' ' +\n ctDate.getHours() + ':' + minutes + ':' + seconds;\n }\n}\n"],"names":["SpbcMalwareScanner","first_start","active","root","settings","states","state","offset","amount","amount_coefficient","total_scanned","scan_percent","percent_completed","paused","button","spinner","progress_overall","progressbar","progressbar_text","timeout","state_timer","constructor","properties","let","key","jQuery","length","removeClass","this","actionControl","start","resume","controller","pause","Math","round","Date","getTime","getNextState","setPercents","children","filter","addClass","show","html","spbcScaner","button_scan_pause","css","display","setTimeout","result","data","opt","console","log","button_scan_resume","end","reload","hide","button_scan_perform","plug","document","location","spbcSendAJAXRequest","action","notJson","callback","params","obj","accordion","header","heightStyle","collapsible","spbcTblBulkActionsListen","spbcTblRowActionsListen","spbcTblPaginationListen","spbcTblSortListen","spbcStartShowHide","spbcScannerReloadScanInfo","method","type","success","successCallback","error","errorOutput","complete","context","spbcSettings","frontendAnalysisAmount","status","setCoefficients","coefficient","indexOf","percents","floor","text","response","responseText","msg","interactAccordion","total","processed_items","logRaw","logFileEntry","stage_data_for_logging","logStageEntry","undefined","cured","Number","showLinkForShuffleSalts","message","processedPercents","processed","title","hasOwnProperty","interactivity_data","update_text","refresh_data","do_refresh","control_tab","spbcReloadAccordion","xhr","tryCount","retryLimit","errorString","fadeOut","errorMsg","stage","spbcModal","open","putError","messageToLog","prepend","items","getSiteUTCShiftedTimeString","path","module","first","textContent","description","remove","after","utcShiftedTs","currentBrowserOffset","getTimezoneOffset","ctDate","timezone_shift","now","shortMonthName","Intl","DateTimeFormat","month","format","minutes","String","getMinutes","padStart","seconds","getSeconds","getDate","getFullYear","getHours"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"spbc-scanner-plugin.min.js","sources":["spbc-scanner-plugin.js"],"sourcesContent":["'use strict';\n\n/**\n * class SpbcMalwareScanner\n */\nclass SpbcMalwareScanner {/* eslint-disable-line no-unused-vars */\n first_start = true;\n\n active = false;\n\n root = '';\n settings = [];\n states = [\n 'get_cms_hashes',\n 'get_modules_hashes',\n 'clean_results',\n 'file_system_analysis',\n 'get_approved_hashes',\n 'get_denied_hashes',\n 'signature_analysis',\n 'heuristic_analysis',\n 'schedule_send_heuristic_suspicious_files',\n 'auto_cure_backup',\n 'auto_cure',\n 'os_cron_analysis',\n 'db_trigger_analysis',\n 'binary_analysis',\n 'outbound_links',\n 'frontend_analysis',\n 'important_files_listing',\n 'send_results',\n ];\n state = null;\n offset = 0;\n amount = 0;\n amount_coefficient = 1;\n total_scanned = 0;\n scan_percent = 0;\n percent_completed = 0;\n\n paused = false;\n\n button = null;\n spinner = null;\n\n progress_overall = null;\n progressbar = null;\n progressbar_text = null;\n\n timeout = 60000;\n\n state_timer = 0;\n\n /**\n * constructor\n * @param {array} properties\n */\n constructor( properties ) {\n if (jQuery('#spbcscan-results-log-module').length) {\n jQuery('.spbc-scan-log-title').removeClass('spbc---hidden');\n }\n\n // Crunch for cure backups\n if ( typeof properties['settings']['auto_cure'] !== 'undefined' ) {\n properties['settings']['scanner__auto_cure_backup'] = '1';\n }\n\n for ( let key in properties ) {\n if ( typeof this[key] !== 'undefined' ) {\n this[key] = properties[key];\n }\n }\n };\n\n /**\n * Function Action Control\n */\n actionControl() {\n if (this.state === null) {\n this.start();\n } else if (this.paused) {\n this.resume();\n this.controller();\n } else {\n this.pause();\n }\n };\n\n /**\n * Function Start\n */\n start() {\n this.active = true;\n this.state_timer = Math.round(new Date().getTime() /1000);\n\n this.state = this.getNextState( null );\n\n this.setPercents( 0 );\n this.scan_percent = 0;\n this.offset = 0;\n this.progress_overall.children('span')\n .removeClass('spbc_bold')\n .filter('.spbc_overall_scan_status_' + this.state)\n .addClass('spbc_bold');\n\n this.progressbar.show(500);\n this.progress_overall.show(500);\n this.button.html(spbcScaner.button_scan_pause);\n this.spinner.css({display: 'inline'});\n\n setTimeout(() => {\n this.controller();\n }, 1000);\n };\n\n /**\n * Function Pause\n * @param {*} result\n * @param {*} data\n * @param {*} opt\n */\n pause( result, data, opt ) {\n console.log('PAUSE');\n this.button.html(spbcScaner.button_scan_resume);\n this.spinner.css({display: 'none'});\n this.paused = true;\n this.active = false;\n };\n\n /**\n * Function Resume\n * @param {*} opt\n */\n resume( opt ) {\n console.log('RESUME');\n this.button.html(spbcScaner.button_scan_pause);\n this.spinner.css({display: 'inline'});\n this.paused = false;\n this.active = true;\n };\n\n /**\n * Function End\n * @param {bool} reload\n */\n end( reload ) {\n this.progressbar.hide(500);\n this.progress_overall.hide(500);\n this.button.html(spbcScaner.button_scan_perform);\n this.spinner.css({display: 'none'});\n this.state = null;\n this.plug = false;\n this.total_scanned = 0;\n this.active = false;\n\n if (reload) {\n document.location = document.location;\n } else {\n spbcSendAJAXRequest(\n {action: 'spbc_scanner_tab__reload_accordion'},\n {\n notJson: true,\n callback: function(result, data, params, obj) {\n jQuery(obj).accordion('destroy')\n .html(result)\n .accordion({\n header: 'h3',\n heightStyle: 'content',\n collapsible: true,\n active: false,\n });\n spbcTblBulkActionsListen();\n spbcTblRowActionsListen();\n spbcTblPaginationListen();\n spbcTblSortListen();\n spbcStartShowHide();\n spbcScannerReloadScanInfo();\n },\n },\n jQuery('#spbc_scan_accordion'),\n );\n }\n };\n\n /**\n * Function Controller\n * @param {obj} result\n */\n controller( result ) {\n console.log(this.state);\n\n // The current stage is over. Switching to the new one\n if ( typeof result !== 'undefined' && result.end ) {\n this.state = this.getNextState( this.state );\n\n // End condition\n if (typeof this.state === 'undefined') {\n this.end();\n return;\n }\n\n // Set percent to 0\n this.setPercents( 0 );\n this.scan_percent = 0;\n this.offset = 0;\n\n // Changing visualizing of the current stage\n this.progress_overall.children('span')\n .removeClass('spbc_bold')\n .filter('.spbc_overall_scan_status_' + this.state)\n .addClass('spbc_bold');\n }\n\n // Break execution if paused\n if ( this.paused === true ) {\n return;\n }\n\n // // AJAX params\n let data = {\n action: 'spbc_scanner_controller_front',\n method: this.state,\n offset: this.offset,\n };\n\n let params = {\n type: 'GET',\n success: this.success,\n callback: this.successCallback,\n error: this.error,\n errorOutput: this.errorOutput,\n complete: null,\n context: this,\n timeout: 120000,\n };\n\n switch (this.state) {\n case 'get_modules_hashes': this.amount = 2; break;\n case 'clear_table': this.amount = 10000; break;\n case 'file_system_analysis': this.amount = 700; break;\n case 'auto_cure': this.amount = 5; break;\n case 'outbound_links': this.amount = 10; break;\n case 'frontend_analysis': this.amount = spbcSettings.frontendAnalysisAmount; break;\n case 'signature_analysis': this.amount = 10; data.status = 'UNKNOWN,MODIFIED,OK,INFECTED,ERROR'; break;\n case 'heuristic_analysis': this.amount = 4; data.status = 'UNKNOWN,MODIFIED,OK,INFECTED,ERROR'; break;\n case 'binary_analysis': this.amount = 4; data.status = 'UNKNOWN,MODIFIED,OK,INFECTED,ERROR'; break;\n case 'schedule_send_heuristic_suspicious_files': this.amount = 1; break;\n }\n\n data.amount = Math.round(this.amount * this.amount_coefficient);\n\n spbcSendAJAXRequest(\n data,\n params,\n jQuery('#spbc_scan_accordion'),\n );\n };\n\n /**\n * Set Coefficients\n * @param {string} state\n */\n setCoefficients( state ) {\n let coefficient = this.amount_coefficient;\n switch (state) {\n case 'file_system_analysis': coefficient *= 1.5; break;\n }\n this.amount_coefficient = coefficient;\n };\n\n /**\n * Get Next State\n * @param {string} state\n * @return {number}\n */\n getNextState( state ) {\n state = state === null ? this.states[0] : this.states[this.states.indexOf( state ) + 1];\n\n if (typeof this.settings['scanner__' + state] !== 'undefined' && +this.settings['scanner__' + state] === 0) {\n state = this.getNextState( state );\n }\n\n return state;\n };\n\n /**\n * Set Percents\n * @param {number} percents\n */\n setPercents( percents ) {\n this.percent_completed = Math.floor( percents * 100 ) / 100;\n this.progressbar.progressbar( 'option', 'value', this.percent_completed );\n this.progressbar_text.text( spbcScaner['progressbar_' + this.state] + ' - ' + this.percent_completed + '%' );\n };\n\n /**\n * Function Success\n * @param {obj} response\n */\n success( response ) {\n if ( !! response.error ) {\n this.error(\n {status: 200, responseText: response.error},\n response.error,\n response.msg,\n );\n } else {\n if ( this.successCallback ) {\n this.successCallback( response, this.data, this.obj );\n }\n }\n };\n\n // Processing response from backend\n /**\n * Success Callback\n * @param {obj} result\n */\n successCallback( result ) {\n console.log( result );\n\n this.interactAccordion(result);\n\n if ( typeof result.total !== 'undefined' ) {\n this.scan_percent = 100 / result.total;\n }\n\n if ( typeof result.processed_items !== 'undefined') {\n if ( this.state === 'heuristic_analysis' && typeof result.total !== 0 ) {\n this.logRaw('

Heuristic Analysis

');\n }\n if ( this.state === 'signature_analysis' && typeof result.total !== 0 ) {\n this.logRaw('

Signature Analysis

');\n }\n\n this.logFileEntry( result.processed_items );\n }\n\n if ( typeof result.stage_data_for_logging !== 'undefined') {\n this.logStageEntry( result.stage_data_for_logging );\n }\n\n // Add link on shuffle salt if cured\n if (result.cured !== undefined && Number(result.cured) > 0) {\n this.showLinkForShuffleSalts(result.message);\n }\n\n if ( result.end !== true && result.end !== 1 ) {\n let processedPercents = this.percent_completed + result.processed * this.scan_percent;\n if (result.stage_data_for_logging.title === 'File System Analysis' && processedPercents > 100) {\n processedPercents = 100;\n }\n this.setPercents(processedPercents);\n this.offset = this.offset + result.processed;\n this.controller( result );\n } else {\n console.log( this.state +\n ' stage took ' +\n ( Math.round(new Date().getTime() /1000) - this.state_timer ) +\n ' seconds to complete' );\n this.state_timer = Math.round(new Date().getTime()/1000);\n this.setPercents( 100 );\n this.scan_percent = 0;\n this.offset = 0;\n setTimeout(() => {\n this.controller( result );\n }, 300);\n }\n };\n\n /**\n * Run interactive refresh for accordion.\n * @param {obj|string[]} result\n */\n interactAccordion(result) {\n // validation control\n if (result.hasOwnProperty('interactivity_data') &&\n result.interactivity_data.hasOwnProperty('update_text') &&\n result.interactivity_data.update_text &&\n result.interactivity_data.hasOwnProperty('refresh_data') &&\n result.interactivity_data.refresh_data.hasOwnProperty('do_refresh') &&\n result.interactivity_data.refresh_data.do_refresh &&\n result.interactivity_data.refresh_data.hasOwnProperty('control_tab') &&\n result.interactivity_data.refresh_data.control_tab\n ) {\n spbcReloadAccordion(\n result.interactivity_data.refresh_data.control_tab,\n result.interactivity_data.update_text,\n );\n }\n }\n\n /**\n * Function Error\n * @param {object} xhr\n * @param {string} status\n * @param {string} error\n */\n error( xhr, status, error ) {\n let errorOutput = this.errorOutput;\n\n console.log( '%c APBCT_AJAX_ERROR', 'color: red;' );\n console.log( status );\n console.log( error );\n console.log( xhr );\n\n if (status == 'error' && (error == '' || error == 'Not found')) {\n if (!this.tryCount) {\n this.tryCount = 0;\n this.retryLimit = 30;\n }\n this.tryCount++;\n console.log('Try #' + this.tryCount);\n this.setCoefficients(this.state);\n if (this.tryCount <= this.retryLimit) {\n this.pause();\n this.resume();\n this.controller();\n return;\n }\n }\n\n if ( xhr.status === 200 ) {\n if ( status === 'parsererror' ) {\n errorOutput( 'Unexpected response from server. See console for details.', this.state );\n console.log( '%c ' + xhr.responseText, 'color: pink;' );\n } else {\n let errorString = status;\n if ( typeof error !== 'undefined' ) {\n errorString += ' Additional info: ' + error;\n }\n errorOutput( errorString, this.state );\n }\n } else if (xhr.status === 500) {\n errorOutput( 'Internal server error.', this.state);\n } else {\n errorOutput('Unexpected response code: ' + xhr.status + '. Error: ' + status, this.state);\n }\n\n if ( this.progressbar ) {\n this.progressbar.fadeOut('slow');\n }\n\n this.end();\n };\n\n /**\n * Error Output\n * @param {string} errorMsg\n * @param {string} stage\n */\n errorOutput( errorMsg, stage ) {\n spbcModal.open().putError( errorMsg + '
Stage: ' + stage);\n };\n\n /**\n * Log Raw\n * @param {htmlString|Element|Text|Array|jQuery} messageToLog\n */\n logRaw(messageToLog) {\n jQuery('.spbc-scan-log-title').removeClass('spbc---hidden');\n jQuery('.spbc_log-wrapper').removeClass('spbc---hidden');\n jQuery('.spbc_log-wrapper .panel-body').prepend( messageToLog );\n };\n\n /**\n * Log File Entry\n * @param {array} items\n */\n logFileEntry(items) {\n for ( let key in items ) {\n if ( key ) {\n this.logRaw(\n '

' +\n this.getSiteUTCShiftedTimeString() + ' - ' +\n items[key].path + ' - ' + items[key].module +\n ': ' + items[key].status + '' +\n '

');\n }\n }\n };\n\n /**\n * Log Stage Entry\n * @param {obj} data\n */\n logStageEntry(data) {\n if (typeof jQuery('.panel-body .spbc_log-line span').first() !== 'undefined' &&\n typeof jQuery('.panel-body .spbc_log-line span').first()[0] !== 'undefined' &&\n jQuery('.panel-body .spbc_log-line span').first()[0].textContent === data.description\n ) {\n return;\n }\n this.logRaw( '

test ' +\n this.getSiteUTCShiftedTimeString() + ' - ' + '' +\n data.title + ' ' + '' + data.description + '

' );\n };\n\n /**\n * Show Link For Shuffle Salts\n * @param {string} message\n */\n showLinkForShuffleSalts(message) {\n jQuery('#spbc_notice_about_shuffle_link').remove();\n jQuery(jQuery('.spbc_tab--active .spbc_wrapper_field p')[1])\n .after(\n '
' +\n '' +\n message +\n '' +\n '
',\n );\n }\n\n /**\n * Get Site UTC Shifted Time String\n * @return {string}\n */\n getSiteUTCShiftedTimeString() {\n let utcShiftedTs = false;\n // gettings current system/browser offset\n let currentBrowserOffset = new Date().getTimezoneOffset();\n currentBrowserOffset = currentBrowserOffset * -1 * 1000 * 60;\n // chek if global ct object is defined\n if (typeof spbcScaner !== 'undefined' &&\n typeof spbcScaner.timezone_shift !== 'undefined' &&\n spbcScaner.timezone_shift !== false) {\n utcShiftedTs = Date.now() - currentBrowserOffset + (spbcScaner.timezone_shift * 1000);\n }\n let ctDate = utcShiftedTs ? new Date(utcShiftedTs) : new Date();\n // construct date string\n let shortMonthName = new Intl.DateTimeFormat('en-US', {month: 'short'}).format;\n let minutes = String(ctDate.getMinutes()).padStart(2, '0');\n let seconds = String(ctDate.getSeconds()).padStart(2, '0');\n return shortMonthName(ctDate) + ' ' +\n ctDate.getDate() + ' ' + ctDate.getFullYear() + ' ' +\n ctDate.getHours() + ':' + minutes + ':' + seconds;\n }\n}\n"],"names":["SpbcMalwareScanner","first_start","active","root","settings","states","state","offset","amount","amount_coefficient","total_scanned","scan_percent","percent_completed","paused","button","spinner","progress_overall","progressbar","progressbar_text","timeout","state_timer","constructor","properties","let","key","jQuery","length","removeClass","this","actionControl","start","resume","controller","pause","Math","round","Date","getTime","getNextState","setPercents","children","filter","addClass","show","html","spbcScaner","button_scan_pause","css","display","setTimeout","result","data","opt","console","log","button_scan_resume","end","reload","hide","button_scan_perform","plug","document","location","spbcSendAJAXRequest","action","notJson","callback","params","obj","accordion","header","heightStyle","collapsible","spbcTblBulkActionsListen","spbcTblRowActionsListen","spbcTblPaginationListen","spbcTblSortListen","spbcStartShowHide","spbcScannerReloadScanInfo","method","type","success","successCallback","error","errorOutput","complete","context","spbcSettings","frontendAnalysisAmount","status","setCoefficients","coefficient","indexOf","percents","floor","text","response","responseText","msg","interactAccordion","total","processed_items","logRaw","logFileEntry","stage_data_for_logging","logStageEntry","undefined","cured","Number","showLinkForShuffleSalts","message","processedPercents","processed","title","hasOwnProperty","interactivity_data","update_text","refresh_data","do_refresh","control_tab","spbcReloadAccordion","xhr","tryCount","retryLimit","errorString","fadeOut","errorMsg","stage","spbcModal","open","putError","messageToLog","prepend","items","getSiteUTCShiftedTimeString","path","module","first","textContent","description","remove","after","utcShiftedTs","currentBrowserOffset","getTimezoneOffset","ctDate","timezone_shift","now","shortMonthName","Intl","DateTimeFormat","month","format","minutes","String","getMinutes","padStart","seconds","getSeconds","getDate","getFullYear","getHours"],"mappings":"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"} \ No newline at end of file diff --git a/js/src/spbc-scanner-plugin.js b/js/src/spbc-scanner-plugin.js index e29332984..a3990bf60 100644 --- a/js/src/spbc-scanner-plugin.js +++ b/js/src/spbc-scanner-plugin.js @@ -24,6 +24,7 @@ class SpbcMalwareScanner {/* eslint-disable-line no-unused-vars */ 'auto_cure', 'os_cron_analysis', 'db_trigger_analysis', + 'binary_analysis', 'outbound_links', 'frontend_analysis', 'important_files_listing', @@ -242,6 +243,7 @@ class SpbcMalwareScanner {/* eslint-disable-line no-unused-vars */ case 'frontend_analysis': this.amount = spbcSettings.frontendAnalysisAmount; break; case 'signature_analysis': this.amount = 10; data.status = 'UNKNOWN,MODIFIED,OK,INFECTED,ERROR'; break; case 'heuristic_analysis': this.amount = 4; data.status = 'UNKNOWN,MODIFIED,OK,INFECTED,ERROR'; break; + case 'binary_analysis': this.amount = 4; data.status = 'UNKNOWN,MODIFIED,OK,INFECTED,ERROR'; break; case 'schedule_send_heuristic_suspicious_files': this.amount = 1; break; } diff --git a/lib/CleantalkSP/SpbctWP/Scanner/BinaryCheckModule/BinaryCheckModule.php b/lib/CleantalkSP/SpbctWP/Scanner/BinaryCheckModule/BinaryCheckModule.php new file mode 100644 index 000000000..6aa4eb9de --- /dev/null +++ b/lib/CleantalkSP/SpbctWP/Scanner/BinaryCheckModule/BinaryCheckModule.php @@ -0,0 +1,169 @@ +total_count = 0; + $this->scanned_count = 0; + $this->statuses = array(); + + $binary_files = $this->getBinaryFiles(); + $this->total_count = count($binary_files); + $this->analyzeBinaryFiles($binary_files); + + return array( + 'success' => true, + 'end' => 1, + 'total_count' => $this->total_count, + 'scanned_count' => $this->scanned_count, + 'statuses' => $this->statuses, + ); + } + + /** + * @return array + */ + public function getBinaryFiles() + { + global $wpdb; + + $binary_files = $wpdb->get_results( + $wpdb->prepare( + "SELECT * FROM " . SPBC_TBL_SCAN_FILES . " WHERE source = %s", + 'BINARY' + ) + ); + + return $binary_files ?: array(); + } + + /** + * @param array $binary_files + * @return void + */ + private function analyzeBinaryFiles($binary_files) + { + foreach ($binary_files as $binary_file) { + $path = realpath(ABSPATH . $binary_file->path); + if (!$path || !file_exists($path)) { + $this->incrementStatus('SKIPPED_NOT_FOUND'); + continue; + } + + if (!is_readable($path)) { + $this->incrementStatus('SKIPPED_NOT_READABLE'); + continue; + } + + $isSuspicious = $this->analyzeBinaryFile($path); + $this->scanned_count++; + + if ($isSuspicious) { + $this->markAsSuspicious($binary_file->path); + $this->incrementStatus('SUSPICIOUS'); + } else { + $this->incrementStatus('OK'); + } + } + } + + /** + * @param string $status + * @return void + */ + private function incrementStatus($status) + { + if (!isset($this->statuses[$status])) { + $this->statuses[$status] = 0; + } + $this->statuses[$status]++; + } + + private function analyzeBinaryFile($binary_file_path) + { + // Read first bytes of the file (we need at least 4 bytes for all checks) + $handle = fopen($binary_file_path, 'rb'); + if (!$handle) { + return false; + } + + // Read first 4 bytes + $first_bytes = fread($handle, 4); + fclose($handle); + + if (strlen($first_bytes) < 4) { + return false; + } + + // Method 1: Check using ord() to get byte values + $byte1 = ord($first_bytes[0]); + $byte2 = ord($first_bytes[1]); + $byte3 = ord($first_bytes[2]); + $byte4 = ord($first_bytes[3]); + + // Check for ELF (0x7F followed by "ELF" = 0x45 0x4C 0x46) + if ($byte1 === 0x7F && $byte2 === 0x45 && $byte3 === 0x4C && $byte4 === 0x46) { + return true; // ELF file detected + } + + // Check for PE/MZ (Windows executable: 0x4D 0x5A = "MZ") + if ($byte1 === 0x4D && $byte2 === 0x5A) { + return true; // PE file detected + } + + // Check for MACHO (macOS/iOS executables) + // 32-bit big-endian: 0xFE 0xED 0xFA 0xCE + // 32-bit little-endian: 0xCE 0xFA 0xED 0xFE + // 64-bit big-endian: 0xFE 0xED 0xFA 0xCF + // 64-bit little-endian: 0xCF 0xFA 0xED 0xFE + $macho_signatures = array( + array(0xFE, 0xED, 0xFA, 0xCE), // 32-bit big-endian + array(0xCE, 0xFA, 0xED, 0xFE), // 32-bit little-endian + array(0xFE, 0xED, 0xFA, 0xCF), // 64-bit big-endian + array(0xCF, 0xFA, 0xED, 0xFE), // 64-bit little-endian + ); + + foreach ($macho_signatures as $signature) { + if ($byte1 === $signature[0] && $byte2 === $signature[1] && + $byte3 === $signature[2] && $byte4 === $signature[3]) { + return true; // MACHO file detected + } + } + + return false; + } + + private function markAsSuspicious($binary_file_path) + { + global $wpdb; + + $wpdb->query( + $wpdb->prepare( + "UPDATE " . SPBC_TBL_SCAN_FILES . " SET status = 'INFECTED', severity = 'SUSPICIOUS' WHERE path = %s", + $binary_file_path + ) + ); + } +} diff --git a/lib/CleantalkSP/SpbctWP/Scanner/ScannerActions/CloudAnalysisActions.php b/lib/CleantalkSP/SpbctWP/Scanner/ScannerActions/CloudAnalysisActions.php index 7c845fac5..bff4f25e0 100644 --- a/lib/CleantalkSP/SpbctWP/Scanner/ScannerActions/CloudAnalysisActions.php +++ b/lib/CleantalkSP/SpbctWP/Scanner/ScannerActions/CloudAnalysisActions.php @@ -146,7 +146,8 @@ public static function bulkSendFileForAnalysis($fast_hashes_list = array()) $sql_result = $wpdb->get_results( 'SELECT fast_hash FROM ' . SPBC_TBL_SCAN_FILES . ' WHERE last_sent IS NULL - AND status NOT IN ("APPROVED_BY_USER","APPROVED_BY_CT","APPROVED_BY_CLOUD","DENIED_BY_CT")', + AND status NOT IN ("APPROVED_BY_USER","APPROVED_BY_CT","APPROVED_BY_CLOUD","DENIED_BY_CT") + AND source != \'BINARY\'', ARRAY_A ); diff --git a/lib/CleantalkSP/SpbctWP/Scanner/ScannerActions/FileSystemActions.php b/lib/CleantalkSP/SpbctWP/Scanner/ScannerActions/FileSystemActions.php index 115ecc4fd..651d0889f 100644 --- a/lib/CleantalkSP/SpbctWP/Scanner/ScannerActions/FileSystemActions.php +++ b/lib/CleantalkSP/SpbctWP/Scanner/ScannerActions/FileSystemActions.php @@ -331,6 +331,11 @@ public static function viewFile($file_id) return array('error' => 'FILE_NOT_FOUND'); } + // Binary files cannot be viewed as text + if (isset($file_info['source']) && $file_info['source'] === 'BINARY') { + return array('error' => esc_html__('Binary files cannot be viewed. These files contain executable code that is not human-readable.', 'security-malware-firewall')); + } + $file_path = $file_info['status'] == 'QUARANTINED' ? $file_info['q_path'] : $root_path . $file_info['path']; if (!file_exists($file_path)) { diff --git a/lib/CleantalkSP/SpbctWP/Scanner/ScannerQueue.php b/lib/CleantalkSP/SpbctWP/Scanner/ScannerQueue.php index 0173897b1..a409df17b 100644 --- a/lib/CleantalkSP/SpbctWP/Scanner/ScannerQueue.php +++ b/lib/CleantalkSP/SpbctWP/Scanner/ScannerQueue.php @@ -31,6 +31,8 @@ use CleantalkSP\SpbctWP\Scanner\ScanningStagesModule\Stages\OutboundLinks; use CleantalkSP\SpbctWP\Scanner\ScanningStagesModule\Stages\ScheduleSendHeuristicSuspiciousFiles; use CleantalkSP\SpbctWP\Scanner\ScanningStagesModule\Stages\SignatureAnalysis; +use CleantalkSP\SpbctWP\Scanner\ScanningStagesModule\Stages\BinaryAnalysis; +use CleantalkSP\SpbctWP\Scanner\BinaryCheckModule\BinaryCheckModule; use CleantalkSP\SpbctWP\Scanner\Stages\CureStage; use CleantalkSP\SpbctWP\Scanner\Stages\SendResultsStage; use CleantalkSP\SpbctWP\Scanner\Stages\SignatureAnalysis\SignatureAnalysisFacade; @@ -55,6 +57,7 @@ class ScannerQueue 'get_approved_hashes', 'signature_analysis', 'heuristic_analysis', + 'binary_analysis', 'schedule_send_heuristic_suspicious_files', 'auto_cure_backup', 'auto_cure', @@ -859,7 +862,7 @@ public function countFilesByStatusAndChecked($status = '', $caller = '') $query = 'SELECT COUNT(fast_hash) AS cnt' . ' FROM ' . SPBC_TBL_SCAN_FILES - . ' WHERE ' . $caller . " = '0' AND status IN (" . $status . ');';// No need to validate or sanitize, already did + . ' WHERE ' . $caller . " = '0' AND status IN (" . $status . ") AND source != 'BINARY'";// No need to validate or sanitize, already did $result = $this->db->fetch($query); return $result !== null @@ -952,7 +955,7 @@ public function file_system_analysis($offset = null, $amount = null, $path_to_sc //should be offset $detected_at = current_time('timestamp'); $sql_hat = 'INSERT INTO ' . SPBC_TBL_SCAN_FILES - . ' (`path`, `size`, `perms`, `mtime`, `fast_hash`, `full_hash`, `detected_at`, `checked_heuristic`) VALUES '; + . ' (`path`, `size`, `perms`, `mtime`, `fast_hash`, `full_hash`, `detected_at`, `checked_heuristic`, `source`) VALUES '; foreach ( $scanner->output_files as $_key => $file ) { // skip restored files as is @@ -973,6 +976,9 @@ public function file_system_analysis($offset = null, $amount = null, $path_to_sc $file['checked_heuristic'] = $ext === 'js' ? 1 : 0; //JS files end + // if extension is not set, set 'source' to 'binary' + $file['source'] = ! $ext ? 'BINARY' : ''; + if ( ! spbc_check_ascii($file['path']) ) { $sql_query__values_non_ascii[] = '(\'' . implode('\',\'', $file) . '\')'; } else { @@ -1425,7 +1431,7 @@ public function signature_analysis($status = 'UNKNOWN,MODIFIED,OK,INFECTED,ERROR $files = $this->db->fetchAll( 'SELECT path, source_type, source, version, status, checked_heuristic, checked_signatures, fast_hash, real_full_hash, full_hash, weak_spots, difference, severity, size, error_msg' . ' FROM ' . SPBC_TBL_SCAN_FILES - . " WHERE checked_signatures = 0 AND status IN ($status)" + . " WHERE checked_signatures = 0 AND status IN ($status) AND source != 'BINARY'" . " LIMIT 1000" ); @@ -1612,7 +1618,7 @@ public function heuristic_analysis($status = 'UNKNOWN,MODIFIED,OK,INFECTED,ERROR $files = $this->db->fetchAll( 'SELECT path, source_type, source, version, status, checked_heuristic, checked_signatures, fast_hash, real_full_hash, full_hash, weak_spots, difference, severity, size, error_msg' . ' FROM ' . SPBC_TBL_SCAN_FILES - . " WHERE checked_heuristic = 0 AND status IN ($status)" + . " WHERE checked_heuristic = 0 AND status IN ($status) AND source != 'BINARY'" . " LIMIT 1000" ); @@ -1815,7 +1821,8 @@ public function schedule_send_heuristic_suspicious_files() // phpcs:ignore PSR1. . ' AND checked_heuristic = 1 ' . ' AND weak_spots NOT LIKE "%SIGNATURES%" ' . ' AND status NOT IN ("APPROVED_BY_USER", "APPROVED_BY_CT", "APPROVED_BY_CLOUD")' - . ' AND (pscan_pending_queue IS NULL OR pscan_pending_queue = 0); ' + . ' AND (pscan_pending_queue IS NULL OR pscan_pending_queue = 0) ' + . ' AND source != \'BINARY\'; ' ); $count = (int)$result_db; @@ -1855,6 +1862,54 @@ public function schedule_send_heuristic_suspicious_files() // phpcs:ignore PSR1. ); } + public function binary_analysis() // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps + { + $output = array(); + + // Initialize scanning stages storage + $scanning_stages_storage = new ScanningStagesStorage(); + $scanning_stages_storage->converter->loadCollection(); + $stage_data_obj = $scanning_stages_storage->getStage(BinaryAnalysis::class); + + // Run binary check module + $binary_check_module = new BinaryCheckModule(); + $result = $binary_check_module->run(); + + // Update stage data + $stage_data_obj->set('total_count_files_for_analysis', $result['total_count']); + $stage_data_obj->set('count_files_to_check', $result['total_count']); + $stage_data_obj->set('scanned_count_files', $result['scanned_count']); + $stage_data_obj->set('statuses', $result['statuses']); + + // Save stage data to DB + $scanning_stages_storage->saveToDb(); + + // Adding to log + ScanningLogFacade::writeToLog( + '' . $stage_data_obj::getTitle() . ' ' . $stage_data_obj->getDescription() + ); + + // Prepare output + $output['success'] = $result['success']; + $output['end'] = $result['end']; + $output['processed'] = $result['scanned_count']; + $output['total'] = $result['total_count']; + $output['stage_data_for_logging'] = array( + 'title' => $stage_data_obj::getTitle(), + 'description' => $stage_data_obj->getDescription() + ); + + // Accordion interactivity + $suspicious_count = isset($result['statuses']['SUSPICIOUS']) ? $result['statuses']['SUSPICIOUS'] : 0; + $refresh_data = array( + 'do_refresh' => !empty($suspicious_count), + 'control_tab' => 'files', + ); + $output['interactivity_data'] = ScannerInteractivityData::prepare(__FUNCTION__, $refresh_data); + + return $output; + } + public function auto_cure_backup() // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps { return spbc_backup__files_with_signatures(true); diff --git a/lib/CleantalkSP/SpbctWP/Scanner/ScanningStagesModule/Stages/BinaryAnalysis.php b/lib/CleantalkSP/SpbctWP/Scanner/ScanningStagesModule/Stages/BinaryAnalysis.php new file mode 100644 index 000000000..67efff864 --- /dev/null +++ b/lib/CleantalkSP/SpbctWP/Scanner/ScanningStagesModule/Stages/BinaryAnalysis.php @@ -0,0 +1,59 @@ +total_count_files_for_analysis + . '; ' + . __('Files to check ', 'security-malware-firewall') + . $this->count_files_to_check + . '; ' + . __('Scanned files ', 'security-malware-firewall') + . $this->scanned_count_files + . '; ' + . __('Statuses ', 'security-malware-firewall') + . $this->getStatusesWithTitle(); + } + + public function getStatusesWithTitle() + { + $description_array = array(); + foreach ($this->statuses as $status => $count) { + $description_array[] = $status . ': ' . $count; + } + return $description_array ? implode('; ', $description_array) . '.' : ''; + } + + public function getName() + { + return __CLASS__; + } + + public function getData() + { + return array( + 'total_count_files_for_analysis' => $this->total_count_files_for_analysis, + 'count_files_to_check' => $this->count_files_to_check, + 'scanned_count_files' => $this->scanned_count_files, + 'statuses' => $this->statuses + ); + } +} diff --git a/lib/CleantalkSP/SpbctWP/Scanner/Services/SendFileToCloudService.php b/lib/CleantalkSP/SpbctWP/Scanner/Services/SendFileToCloudService.php index c431d207d..e738e1407 100644 --- a/lib/CleantalkSP/SpbctWP/Scanner/Services/SendFileToCloudService.php +++ b/lib/CleantalkSP/SpbctWP/Scanner/Services/SendFileToCloudService.php @@ -31,6 +31,11 @@ public static function sendFile($file_id, $do_rescan = true) return array('error' => 'FILE_NOT_FOUND'); } + // Binary files cannot be sent for analysis + if (isset($file_info['source']) && $file_info['source'] === 'BINARY') { + return array('error' => __('Binary files cannot be sent for analysis.', 'security-malware-firewall')); + } + $root_path = spbc_get_root_path(); // if file not exists, remove it from the database diff --git a/lib/CleantalkSP/SpbctWP/Scanner/Stages/CureStage.php b/lib/CleantalkSP/SpbctWP/Scanner/Stages/CureStage.php index a86b5e545..8af2c5b61 100644 --- a/lib/CleantalkSP/SpbctWP/Scanner/Stages/CureStage.php +++ b/lib/CleantalkSP/SpbctWP/Scanner/Stages/CureStage.php @@ -103,11 +103,11 @@ public function runStage($offset, $amount) */ public function getFilesToCure($limit = null) { - // get files with signatures + // get files with signatures (excluding binary files) $files_with_signatures = ' SELECT fast_hash, full_hash, mtime FROM ' . SPBC_TBL_SCAN_FILES . ' - WHERE weak_spots LIKE "%SIGNATURES%" + WHERE weak_spots LIKE "%SIGNATURES%" AND source != \'BINARY\' '; $files_with_signatures = $this->db->fetchAll($files_with_signatures, OBJECT_K); diff --git a/lib/CleantalkSP/SpbctWP/Scanner/Surface.php b/lib/CleantalkSP/SpbctWP/Scanner/Surface.php index 441e59b44..2c2bc7546 100644 --- a/lib/CleantalkSP/SpbctWP/Scanner/Surface.php +++ b/lib/CleantalkSP/SpbctWP/Scanner/Surface.php @@ -531,6 +531,11 @@ public function countFilesInDir($main_path) $filename = $fileInfo->getFileName(); $currentFileExtension = pathinfo($filename, PATHINFO_EXTENSION); + if ($currentFileExtension === '') { + $this->output_files_count++; + continue; + } + // Extensions filter if ( $this->ext_except || $this->ext ) { if ( @@ -623,6 +628,14 @@ public function getFileStructure($main_path, $iterator_result, $is_root_dir) $path = (string) $path; if ( is_file($path) && !is_link($path) ) { + $currentFileExtension = pathinfo($path, PATHINFO_EXTENSION); + + if ($currentFileExtension === '') { + $this->output_counter_files++; + $this->output_files[]['path'] = $path; + continue; + } + // Extensions filter if ( $this->ext_except || $this->ext ) { $currentFileExtension = pathinfo($path, PATHINFO_EXTENSION); diff --git a/lib/CleantalkSP/SpbctWP/SpbcEnqueue.php b/lib/CleantalkSP/SpbctWP/SpbcEnqueue.php index eecf642ce..af1d87d55 100644 --- a/lib/CleantalkSP/SpbctWP/SpbcEnqueue.php +++ b/lib/CleantalkSP/SpbctWP/SpbcEnqueue.php @@ -272,6 +272,7 @@ function ($key) { 'check_links' => $spbc->settings['scanner__outbound_links'] ? 1 : 0, 'check_heuristic' => $spbc->settings['scanner__heuristic_analysis'] ? 1 : 0, 'check_signature' => $spbc->settings['scanner__signature_analysis'] ? 1 : 0, + 'check_binary' => $spbc->settings['scanner__binary_analysis'] ? 1 : 0, 'auto_cure' => $spbc->settings['scanner__auto_cure'] ? 1 : 0, 'check_frontend' => $spbc->settings['scanner__frontend_analysis'] ? 1 : 0, 'check_listing' => $spbc->settings['scanner__important_files_listing'] ? 1 : 0, diff --git a/lib/CleantalkSP/SpbctWP/State.php b/lib/CleantalkSP/SpbctWP/State.php index dae3c7532..2a06db0a9 100644 --- a/lib/CleantalkSP/SpbctWP/State.php +++ b/lib/CleantalkSP/SpbctWP/State.php @@ -74,6 +74,7 @@ class State extends \CleantalkSP\Common\State 'scanner__outbound_links_mirrors' => '', 'scanner__important_files_listing' => 1, 'scanner__heuristic_analysis' => 1, + 'scanner__binary_analysis' => 0, 'scanner__schedule_send_heuristic_suspicious_files' => 2, //0 - OFF, 1 - ON, 2 - AUTO 'scanner__signature_analysis' => 1, 'scanner__auto_cure' => 1,