Shield Security for WordPress - Version 15.1.7

Version Description

Download this release

Release Info

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

Code changes from version 15.1.6 to 15.1.7

Files changed (42) hide show
  1. cl.json +14 -0
  2. icwp-wpsf.php +1 -1
  3. plugin-spec.php +3 -3
  4. plugin.json +3 -3
  5. readme.txt +1 -1
  6. resources/css/plugin.css +7 -0
  7. resources/js/shield/audit_trail.js +0 -2
  8. resources/js/shield/scantables.js +4 -2
  9. src/lib/src/Modules/AuditTrail/Lib/LogTable/BuildAuditTableData.php +3 -3
  10. src/lib/src/Modules/AuditTrail/ModCon.php +1 -1
  11. src/lib/src/Modules/Base/Databases.php +0 -3
  12. src/lib/src/Modules/Events/Lib/EventsService.php +13 -4
  13. src/lib/src/Modules/HackGuard/Lib/ScanTables/BuildScanTableData.php +122 -0
  14. src/lib/src/Modules/HackGuard/Lib/ScanTables/BuildSearchPanesData.php +78 -0
  15. src/lib/src/Modules/HackGuard/Lib/ScanTables/DelegateAjaxHandler.php +6 -6
  16. src/lib/src/Modules/HackGuard/Lib/ScanTables/Modals/BuildInfo.php +6 -6
  17. src/lib/src/Modules/HackGuard/Lib/ScanTables/Modals/ScanItemView.php +1 -1
  18. src/lib/src/Modules/HackGuard/Lib/ScanTables/TableData/BaseLoadTableData.php +166 -0
  19. src/lib/src/Modules/HackGuard/Lib/ScanTables/TableData/BaseLoadTableDataPluginTheme.php +54 -0
  20. src/lib/src/Modules/HackGuard/Lib/ScanTables/TableData/LoadTableDataMalware.php +77 -0
  21. src/lib/src/Modules/HackGuard/Lib/ScanTables/TableData/LoadTableDataPlugin.php +28 -0
  22. src/lib/src/Modules/HackGuard/Lib/ScanTables/TableData/LoadTableDataTheme.php +28 -0
  23. src/lib/src/Modules/HackGuard/Lib/ScanTables/TableData/LoadTableDataWordpress.php +67 -0
  24. src/lib/src/Modules/HackGuard/ModCon.php +3 -6
  25. src/lib/src/Modules/HackGuard/Render/ScanResults/SectionPlugins.php +5 -5
  26. src/lib/src/Modules/HackGuard/Render/ScanResults/SectionThemes.php +5 -6
  27. src/lib/src/Modules/HackGuard/Scan/Controller/Base.php +1 -1
  28. src/lib/src/Modules/HackGuard/Scan/Results/Counts.php +0 -1
  29. src/lib/src/Modules/HackGuard/Scan/Results/Retrieve.php +64 -42
  30. src/lib/src/Modules/HackGuard/Scan/ScansController.php +1 -2
  31. src/lib/src/Modules/IPs/WpCli/Add.php +11 -13
  32. src/lib/src/Modules/IPs/WpCli/Base.php +20 -0
  33. src/lib/src/Modules/IPs/WpCli/BaseAddRemove.php +1 -3
  34. src/lib/src/Modules/IPs/WpCli/Enumerate.php +24 -18
  35. src/lib/src/Modules/IPs/WpCli/Remove.php +11 -15
  36. src/lib/src/Modules/License/Processor.php +1 -1
  37. src/lib/src/Modules/Plugin/Lib/PluginTelemetry.php +5 -2
  38. src/lib/src/Modules/Traffic/Lib/TrafficTable/BuildTrafficTableData.php +3 -3
  39. src/lib/src/Tables/DataTables/Build/Scans/BaseForScan.php +37 -15
  40. src/lib/src/Tables/DataTables/Build/Scans/ForMalware.php +15 -3
  41. src/lib/src/Tables/DataTables/LoadData/BaseBuildTableData.php +9 -9
  42. src/lib/src/Tables/Render/WpCliTable/AuditTrail.php +1 -1
cl.json CHANGED
@@ -100,6 +100,20 @@
100
  "type": "fixed"
101
  }
102
  ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  }
104
  ]
105
  },
100
  "type": "fixed"
101
  }
102
  ]
103
+ },
104
+ {
105
+ "version": "7",
106
+ "released_at": 1658226200,
107
+ "items": [
108
+ {
109
+ "title": "Eliminate errors and slow processing when displaying scan results pages for large datasets.",
110
+ "type": "improved"
111
+ },
112
+ {
113
+ "title": "Bug when specifying a particular list when adding/removing an IP address using WP-CLI.",
114
+ "type": "fixed"
115
+ }
116
+ ]
117
  }
118
  ]
119
  },
icwp-wpsf.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: Shield Security
4
  * Plugin URI: https://shsec.io/2f
5
  * Description: Powerful, Easy-To-Use #1 Rated WordPress Security System
6
- * Version: 15.1.6
7
  * Text Domain: wp-simple-firewall
8
  * Domain Path: /languages
9
  * Author: Shield Security
3
  * Plugin Name: Shield Security
4
  * Plugin URI: https://shsec.io/2f
5
  * Description: Powerful, Easy-To-Use #1 Rated WordPress Security System
6
+ * Version: 15.1.7
7
  * Text Domain: wp-simple-firewall
8
  * Domain Path: /languages
9
  * Author: Shield Security
plugin-spec.php CHANGED
@@ -1,8 +1,8 @@
1
  {
2
  "properties": {
3
- "version": "15.1.6",
4
- "release_timestamp": 1658226200,
5
- "build": "202207.1901",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
  "text_domain": "wp-simple-firewall",
1
  {
2
  "properties": {
3
+ "version": "15.1.7",
4
+ "release_timestamp": 1658663000,
5
+ "build": "202207.2401",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
  "text_domain": "wp-simple-firewall",
plugin.json CHANGED
@@ -1,8 +1,8 @@
1
  {
2
  "properties": {
3
- "version": "15.1.6",
4
- "release_timestamp": 1658226200,
5
- "build": "202207.1901",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
  "text_domain": "wp-simple-firewall",
1
  {
2
  "properties": {
3
+ "version": "15.1.7",
4
+ "release_timestamp": 1658663000,
5
+ "build": "202207.2401",
6
  "slug_parent": "icwp",
7
  "slug_plugin": "wpsf",
8
  "text_domain": "wp-simple-firewall",
readme.txt CHANGED
@@ -8,7 +8,7 @@ Requires at least: 3.7
8
  Requires PHP: 7.0
9
  Recommended PHP: 7.4
10
  Tested up to: 6.0
11
- Stable tag: 15.1.6
12
 
13
  Bad Bots Are Your #1 Security Risk. Malware is a symptom of poor security, not the cause. Discover the advantage of powerful security over marketing.
14
 
8
  Requires PHP: 7.0
9
  Recommended PHP: 7.4
10
  Tested up to: 6.0
11
+ Stable tag: 15.1.7
12
 
13
  Bad Bots Are Your #1 Security Risk. Malware is a symptom of poor security, not the cause. Discover the advantage of powerful security over marketing.
14
 
resources/css/plugin.css CHANGED
@@ -1150,4 +1150,11 @@ button.bs-placeholder {
1150
  }
1151
  #ShieldGeneralPurposeDialog .card-header {
1152
  background: transparent;
 
 
 
 
 
 
 
1153
  }
1150
  }
1151
  #ShieldGeneralPurposeDialog .card-header {
1152
  background: transparent;
1153
+ }
1154
+ td.status {
1155
+ min-width: 150px;
1156
+ }
1157
+ td.status ul,
1158
+ td.mal_details ul {
1159
+ padding-left: 0;
1160
  }
resources/js/shield/audit_trail.js CHANGED
@@ -141,8 +141,6 @@
141
  iCWP_WPSF_BodyOverlay.show();
142
  let reqData = base.getBaseAjaxData();
143
  reqData.sub_action = 'retrieve_table_data';
144
- reqData.type = base.options.type;
145
- reqData.file = base.options.file;
146
  reqData.table_data = data;
147
  $.post( ajaxurl, reqData, function ( response ) {
148
  if ( response.success ) {
141
  iCWP_WPSF_BodyOverlay.show();
142
  let reqData = base.getBaseAjaxData();
143
  reqData.sub_action = 'retrieve_table_data';
 
 
144
  reqData.table_data = data;
145
  $.post( ajaxurl, reqData, function ( response ) {
146
  if ( response.success ) {
resources/js/shield/scantables.js CHANGED
@@ -204,14 +204,16 @@
204
  this.$table = this.$el.DataTable(
205
  $.extend( base.options.datatables_init,
206
  {
 
207
  ajax: function ( data, callback, settings ) {
208
  let reqData = base.getBaseAjaxData();
209
  reqData.sub_action = 'retrieve_table_data';
210
  reqData.type = base.options.type;
211
  reqData.file = base.options.file;
 
212
  $.post( ajaxurl, reqData, function ( response ) {
213
  if ( response.success ) {
214
- callback( response.data.vars );
215
  }
216
  else {
217
  let msg = 'Communications error with site.';
@@ -226,7 +228,7 @@
226
  select: {
227
  style: 'multi'
228
  },
229
- dom: 'Bfrtip',
230
  buttons: [
231
  {
232
  text: 'Reload',
204
  this.$table = this.$el.DataTable(
205
  $.extend( base.options.datatables_init,
206
  {
207
+ serverSide: true,
208
  ajax: function ( data, callback, settings ) {
209
  let reqData = base.getBaseAjaxData();
210
  reqData.sub_action = 'retrieve_table_data';
211
  reqData.type = base.options.type;
212
  reqData.file = base.options.file;
213
+ reqData.table_data = data;
214
  $.post( ajaxurl, reqData, function ( response ) {
215
  if ( response.success ) {
216
+ callback( response.data.datatable_data );
217
  }
218
  else {
219
  let msg = 'Communications error with site.';
228
  select: {
229
  style: 'multi'
230
  },
231
+ dom: 'Brpftip',
232
  buttons: [
233
  {
234
  text: 'Reload',
src/lib/src/Modules/AuditTrail/Lib/LogTable/BuildAuditTableData.php CHANGED
@@ -17,8 +17,8 @@ class BuildAuditTableData extends BaseBuildTableData {
17
  */
18
  private $log;
19
 
20
- protected function loadLogsWithDirectQuery() :array {
21
- return $this->loadLogsWithSearch();
22
  }
23
 
24
  protected function getSearchPanesData() :array {
@@ -30,7 +30,7 @@ class BuildAuditTableData extends BaseBuildTableData {
30
  /**
31
  * @param LogRecord[] $records
32
  */
33
- protected function buildTableRowsFromRawLogs( array $records ) :array {
34
  return array_values( array_map(
35
  function ( $log ) {
36
  $this->log = $log;
17
  */
18
  private $log;
19
 
20
+ protected function loadRecordsWithDirectQuery() :array {
21
+ return $this->loadRecordsWithSearch();
22
  }
23
 
24
  protected function getSearchPanesData() :array {
30
  /**
31
  * @param LogRecord[] $records
32
  */
33
+ protected function buildTableRowsFromRawRecords( array $records ) :array {
34
  return array_values( array_map(
35
  function ( $log ) {
36
  $this->log = $log;
src/lib/src/Modules/AuditTrail/ModCon.php CHANGED
@@ -80,7 +80,7 @@ class ModCon extends BaseShield\ModCon {
80
  array_filter( // Get all logs entries pertaining to this user:
81
  ( new Shield\Modules\AuditTrail\Lib\LogTable\BuildAuditTableData() )
82
  ->setMod( $this )
83
- ->loadForLogs(),
84
  function ( $log ) use ( $user ) {
85
  $keep = $log[ 'user_id' ] === $user->ID;
86
  if ( !$keep ) {
80
  array_filter( // Get all logs entries pertaining to this user:
81
  ( new Shield\Modules\AuditTrail\Lib\LogTable\BuildAuditTableData() )
82
  ->setMod( $this )
83
+ ->loadForRecords(),
84
  function ( $log ) use ( $user ) {
85
  $keep = $log[ 'user_id' ] === $user->ID;
86
  if ( !$keep ) {
src/lib/src/Modules/Base/Databases.php CHANGED
@@ -57,9 +57,6 @@ class Databases {
57
  $dbDef[ 'table_prefix' ] = $this->getCon()->getPluginPrefix( '_' );
58
  /** @var Core\Databases\Base\Handler|mixed $dbh */
59
  $dbh = new $dbClass( $dbDef );
60
- if ( $this->getCon()->flags[ 'db_bypass_ready_check_cache' ] ?? false ) {
61
- $dbh->bypassReadyCheckCache();
62
- }
63
  $dbh->execute();
64
 
65
  $this->dbHandlers[ $dbKey ] = $dbh;
57
  $dbDef[ 'table_prefix' ] = $this->getCon()->getPluginPrefix( '_' );
58
  /** @var Core\Databases\Base\Handler|mixed $dbh */
59
  $dbh = new $dbClass( $dbDef );
 
 
 
60
  $dbh->execute();
61
 
62
  $this->dbHandlers[ $dbKey ] = $dbh;
src/lib/src/Modules/Events/Lib/EventsService.php CHANGED
@@ -101,10 +101,19 @@ class EventsService {
101
  }
102
 
103
  public function getEventStrings( string $eventKey ) :array {
104
- return $this->getCon()
105
- ->getModule( $this->getEventDef( $eventKey )[ 'module' ] )
106
- ->getStrings()
107
- ->getEventStrings()[ $eventKey ] ?? [];
 
 
 
 
 
 
 
 
 
108
  }
109
 
110
  /**
101
  }
102
 
103
  public function getEventStrings( string $eventKey ) :array {
104
+ $eventStrings = [];
105
+
106
+ if ( $this->eventExists( $eventKey ) ) {
107
+ $eventStrings = $this->getCon()
108
+ ->getModule( $this->getEventDef( $eventKey )[ 'module' ] )
109
+ ->getStrings()
110
+ ->getEventStrings()[ $eventKey ] ?? $eventStrings;
111
+ }
112
+ else {
113
+ error_log( sprintf( 'An event %s does not exist.', $eventKey ) );
114
+ }
115
+
116
+ return $eventStrings;
117
  }
118
 
119
  /**
src/lib/src/Modules/HackGuard/Lib/ScanTables/BuildScanTableData.php ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\ScanTables;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\AuditTrail\DB\LogRecord;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Tables\DataTables\Build\Scans\BaseForScan;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Tables\DataTables\LoadData\BaseBuildTableData;
8
+ use FernleafSystems\Wordpress\Services\Services;
9
+
10
+ /**
11
+ * @property string $type
12
+ * @property string $file
13
+ */
14
+ class BuildScanTableData extends BaseBuildTableData {
15
+
16
+ protected function loadRecordsWithSearch() :array {
17
+ return $this->loadRecordsWithDirectQuery();
18
+ }
19
+
20
+ protected function getSearchPanesData() :array {
21
+ return [];
22
+ /*
23
+ return ( new BuildSearchPanesData() )
24
+ ->setMod( $this->getMod() )
25
+ ->build();
26
+ */
27
+ }
28
+
29
+ /**
30
+ * @param LogRecord[] $records
31
+ */
32
+ protected function buildTableRowsFromRawRecords( array $records ) :array {
33
+ return array_values( $records );
34
+ }
35
+
36
+ /**
37
+ * The Wheres need to align with the structure of the Query called from getRecords()
38
+ */
39
+ protected function buildWheresFromSearchParams() :array {
40
+ $wheres = [];
41
+ if ( !empty( $this->table_data[ 'searchPanes' ] ) ) {
42
+ foreach ( array_filter( $this->table_data[ 'searchPanes' ] ) as $column => $selected ) {
43
+ switch ( $column ) {
44
+ case 'event':
45
+ if ( count( $selected ) > 1 ) {
46
+ $wheres[] = sprintf( 'log.event_slug IN (`%s`)', implode( '`,`', $selected ) );
47
+ }
48
+ else {
49
+ $wheres[] = sprintf( "log.event_slug='%s'", array_pop( $selected ) );
50
+ }
51
+ break;
52
+ case 'ip':
53
+ $wheres[] = sprintf( "ips.ip=INET6_ATON('%s')", array_pop( $selected ) );
54
+ break;
55
+ default:
56
+ break;
57
+ }
58
+ }
59
+ }
60
+ return $wheres;
61
+ }
62
+
63
+ protected function countTotalRecords() :int {
64
+ return $this->getRecordsLoader()->countAll();
65
+ }
66
+
67
+ protected function countTotalRecordsFiltered() :int {
68
+ $loader = $this->getRecordsLoader();
69
+ $loader->wheres = $this->buildWheresFromSearchParams();
70
+ return $loader->countAll();
71
+ }
72
+
73
+ protected function getSearchableColumns() :array {
74
+ // Use the DataTables definition builder to locate searchable columns
75
+ return array_filter( array_map(
76
+ function ( $column ) {
77
+ return ( $column[ 'searchable' ] ?? false ) ? $column[ 'data' ] : '';
78
+ },
79
+ ( new BaseForScan() )
80
+ ->setMod( $this->getMod() )
81
+ ->buildRaw()[ 'columns' ]
82
+ ) );
83
+ }
84
+
85
+ /**
86
+ * @return array[]
87
+ */
88
+ protected function getRecords( array $wheres = [], int $offset = 0, int $limit = 0 ) :array {
89
+ $loader = $this->getRecordsLoader();
90
+ $loader->wheres = $wheres;
91
+ $loader->limit = $limit;
92
+ $loader->offset = $offset;
93
+ return $loader->run();
94
+ }
95
+
96
+ /**
97
+ * @return TableData\BaseLoadTableData
98
+ */
99
+ protected function getRecordsLoader() {
100
+ switch ( $this->type ) {
101
+ case 'plugin':
102
+ $loader = new TableData\LoadTableDataPlugin( Services::WpPlugins()->getPluginAsVo( $this->file ) );
103
+ break;
104
+ case 'theme':
105
+ $loader = new TableData\LoadTableDataTheme( Services::WpThemes()->getThemeAsVo( $this->file ) );
106
+ break;
107
+ case 'malware':
108
+ $loader = new TableData\LoadTableDataMalware();
109
+ break;
110
+ case 'wordpress':
111
+ default:
112
+ $loader = new TableData\LoadTableDataWordpress();
113
+ break;
114
+ }
115
+
116
+ $loader->order_dir = $this->getOrderDirection();
117
+ $loader->order_by = $this->order_by;
118
+ $loader->search_text = preg_replace( '#[^/a-z\d_-]#i', '', (string)$this->table_data[ 'search' ][ 'value' ] ?? '' );
119
+
120
+ return $loader->setMod( $this->getMod() );
121
+ }
122
+ }
src/lib/src/Modules/HackGuard/Lib/ScanTables/BuildSearchPanesData.php ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\ScanTables;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\ModCon;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
7
+ use FernleafSystems\Wordpress\Services\Services;
8
+
9
+ class BuildSearchPanesData {
10
+
11
+ use ModConsumer;
12
+
13
+ public function build() :array {
14
+ return [
15
+ 'options' => [
16
+ 'file_type' => $this->buildForFileTypes(),
17
+ 'status' => $this->buildForFileStatus(),
18
+ ]
19
+ ];
20
+ }
21
+
22
+ private function buildForFileTypes() :array {
23
+ $exts = [];
24
+ foreach ( $this->runQueryForFileTypes() as $item ) {
25
+ $item = $item[ 'item_id' ] ?? '';
26
+ if ( !empty( $item ) && strpos( $item, '.' ) > 0 ) {
27
+ $ext = explode( '.', $item )[ 1 ];
28
+ if ( empty( $exts[ $ext ] ) ) {
29
+ $exts[ $ext ] = [
30
+ 'label' => strtoupper( $ext ),
31
+ 'value' => $ext,
32
+ ];
33
+ }
34
+ }
35
+ }
36
+ return array_values( $exts );
37
+ }
38
+
39
+ private function buildForFileStatus() :array {
40
+ return [
41
+ [
42
+ 'label' => __( 'Malware', 'wp-simple-firewall' ),
43
+ 'value' => 'is_mal',
44
+ ],
45
+ [
46
+ 'label' => __( 'Unrecognised', 'wp-simple-firewall' ),
47
+ 'value' => 'is_unrecognised',
48
+ ],
49
+ [
50
+ 'label' => __( 'Modified From Original', 'wp-simple-firewall' ),
51
+ 'value' => 'is_checksumfail',
52
+ ],
53
+ [
54
+ 'label' => __( 'Missing', 'wp-simple-firewall' ),
55
+ 'value' => 'is_missing',
56
+ ],
57
+ ];
58
+ }
59
+
60
+ private function runQueryForFileTypes() :array {
61
+ /** @var ModCon $mod */
62
+ $mod = $this->getMod();
63
+ $results = Services::WpDb()->selectCustom(
64
+ sprintf( "SELECT DISTINCT `ri`.`item_id`
65
+ FROM `%s` as `ri`
66
+ WHERE `ri`.`item_type`='f'
67
+ AND `ri`.`ignored_at`=0
68
+ AND `ri`.`auto_filtered_at`!=0
69
+ AND `ri`.`item_repaired_at`=0
70
+ AND `ri`.`item_deleted_at`=0
71
+ AND `ri`.`deleted_at`=0
72
+ ",
73
+ $mod->getDbH_ResultItems()->getTableSchema()->table
74
+ )
75
+ );
76
+ return is_array( $results ) ? $results : [];
77
+ }
78
+ }
src/lib/src/Modules/HackGuard/Lib/ScanTables/DelegateAjaxHandler.php CHANGED
@@ -151,13 +151,13 @@ class DelegateAjaxHandler {
151
  */
152
  private function retrieveTableData() :array {
153
  $req = Services::Request();
 
 
 
 
154
  return [
155
- 'success' => true,
156
- 'vars' => [
157
- 'data' => array_values( ( new LoadRawTableData() )
158
- ->setMod( $this->getMod() )
159
- ->loadFor( $req->post( 'type' ), $req->post( 'file' ) ) )
160
- ],
161
  ];
162
  }
163
  }
151
  */
152
  private function retrieveTableData() :array {
153
  $req = Services::Request();
154
+ $builder = ( new BuildScanTableData() )->setMod( $this->getMod() );
155
+ $builder->table_data = (array)$req->post( 'table_data', [] );
156
+ $builder->type = (string)$req->post( 'type', '' );
157
+ $builder->file = (string)$req->post( 'file', '' );
158
  return [
159
+ 'success' => true,
160
+ 'datatable_data' => $builder->build(),
 
 
 
 
161
  ];
162
  }
163
  }
src/lib/src/Modules/HackGuard/Lib/ScanTables/Modals/BuildInfo.php CHANGED
@@ -74,28 +74,28 @@ class BuildInfo {
74
  }
75
  elseif ( $item->is_in_plugin ) {
76
  if ( $item->is_unrecognised ) {
77
- $description[] = __( "It's located in a WordPress plugin directory, but it's not recognised as an official file.", 'wp-simple-firewall' );
78
  }
79
  else {
80
- $description[] = __( "It's located in a WordPress plugin directory, and is a recognised official file.", 'wp-simple-firewall' );
81
  }
82
  }
83
  elseif ( $item->is_in_theme ) {
84
  if ( $item->is_unrecognised ) {
85
- $description[] = __( "It's located in a WordPress theme directory, but it's not recognised as an official file.", 'wp-simple-firewall' );
86
  }
87
  else {
88
- $description[] = __( "It's located in a WordPress theme directory, and is a recognised official file.", 'wp-simple-firewall' );
89
  }
90
  }
91
  if ( $item->is_checksumfail ) {
92
- $description[] = __( 'Contents have been modified from what is expected.', 'wp-simple-firewall' );
93
  }
94
  if ( $item->is_mal ) {
95
  $description[] = __( 'Contents could potentially contain malicious PHP malware.', 'wp-simple-firewall' );
96
  $description[] = sprintf( __( 'The false positive score of this file is %s.', 'wp-simple-firewall' ),
97
  sprintf( '<code>%s</code>', $item->mal_fp_confidence ) );
98
- $description[] = __( "The lower the score the less we know about the file and the more likely it contains malicious code.", 'wp-simple-firewall' );
99
  }
100
 
101
  return $description;
74
  }
75
  elseif ( $item->is_in_plugin ) {
76
  if ( $item->is_unrecognised ) {
77
+ $description[] = __( "It's located inside a WordPress plugin directory, but it's not recognised as an official file for that plugin version.", 'wp-simple-firewall' );
78
  }
79
  else {
80
+ $description[] = __( "It's located in a WordPress plugin directory, and is a recognised as a valid file for that plugin version.", 'wp-simple-firewall' );
81
  }
82
  }
83
  elseif ( $item->is_in_theme ) {
84
  if ( $item->is_unrecognised ) {
85
+ $description[] = __( "It's located in a WordPress theme directory, but it's not recognised as an official file for that theme version.", 'wp-simple-firewall' );
86
  }
87
  else {
88
+ $description[] = __( "It's located in a WordPress theme directory, and is a recognised as a valid file for that theme version.", 'wp-simple-firewall' );
89
  }
90
  }
91
  if ( $item->is_checksumfail ) {
92
+ $description[] = __( 'File contents have been modified when compared against the official release for that version.', 'wp-simple-firewall' );
93
  }
94
  if ( $item->is_mal ) {
95
  $description[] = __( 'Contents could potentially contain malicious PHP malware.', 'wp-simple-firewall' );
96
  $description[] = sprintf( __( 'The false positive score of this file is %s.', 'wp-simple-firewall' ),
97
  sprintf( '<code>%s</code>', $item->mal_fp_confidence ) );
98
+ $description[] = __( "The lower the score the less we know about the file or the more likely it contains malicious code.", 'wp-simple-firewall' );
99
  }
100
 
101
  return $description;
src/lib/src/Modules/HackGuard/Lib/ScanTables/Modals/ScanItemView.php CHANGED
@@ -140,7 +140,7 @@ class ScanItemView {
140
 
141
  $FS = Services::WpFs();
142
  if ( empty( $originalFileDownload ) || !$FS->isFile($originalFileDownload)) {
143
- throw new \Exception( 'There is no original file available to create a diff.' );
144
  }
145
 
146
  $conv = new ConvertLineEndings();
140
 
141
  $FS = Services::WpFs();
142
  if ( empty( $originalFileDownload ) || !$FS->isFile($originalFileDownload)) {
143
+ throw new \Exception( "A File Diff can't be created as there is no original/official file available for us to compare with." );
144
  }
145
 
146
  $conv = new ConvertLineEndings();
src/lib/src/Modules/HackGuard/Lib/ScanTables/TableData/BaseLoadTableData.php ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\ScanTables\TableData;
4
+
5
+ use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\ModCon;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Scan\Controller\Afs;
8
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Scan\Results\Retrieve;
9
+ use FernleafSystems\Wordpress\Plugin\Shield\Utilities\Tool\FormatBytes;
10
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\ModConsumer;
11
+ use FernleafSystems\Wordpress\Plugin\Shield\Scans;
12
+ use FernleafSystems\Wordpress\Services\Services;
13
+ use FernleafSystems\Wordpress\Services\Utilities\File\Paths;
14
+
15
+ /**
16
+ * @property int $limit
17
+ * @property int $offset
18
+ * @property string[] $wheres
19
+ * @property string $order_by
20
+ * @property string $order_dir
21
+ * @property string $search_text
22
+ */
23
+ abstract class BaseLoadTableData extends DynPropertiesClass {
24
+
25
+ use ModConsumer;
26
+
27
+ abstract public function run() :array;
28
+
29
+ public function countAll() :int {
30
+ return $this->getRecordRetriever()->count();
31
+ }
32
+
33
+ protected function getRecordRetriever() :Retrieve {
34
+ /** @var ModCon $mod */
35
+ $mod = $this->getMod();
36
+ $retriever = ( new Retrieve() )
37
+ ->setMod( $this->getMod() )
38
+ ->setScanController( $mod->getScanCon( Afs::SCAN_SLUG ) );
39
+ $retriever->limit = $this->limit;
40
+ $retriever->offset = $this->offset;
41
+
42
+ if ( !empty( $this->order_by ) ) {
43
+ switch ( $this->order_by ) {
44
+ case 'created_at':
45
+ $by = '`ri`.`created_at`';
46
+ break;
47
+ case 'file':
48
+ $by = '`ri`.`item_id`';
49
+ break;
50
+ default:
51
+ $by = null;
52
+ break;
53
+ }
54
+
55
+ $retriever->order_by = $by;
56
+ if ( !empty( $by ) && in_array( strtoupper( (string)$this->order_dir ), [ 'ASC', 'DESC' ] ) ) {
57
+ $retriever->order_dir = $this->order_dir;
58
+ }
59
+ }
60
+
61
+ if ( !empty( $this->search_text ) ) {
62
+ $wheres = $this->wheres ?? [];
63
+ $wheres[] = sprintf( "`ri`.`item_id` LIKE '%%%s%%'", $this->search_text );
64
+ $retriever->wheres = $wheres;
65
+ }
66
+
67
+ return $retriever;
68
+ }
69
+
70
+ /**
71
+ * @param Scans\Base\ResultItem $item
72
+ * @throws \Exception
73
+ */
74
+ protected function getActions( string $status, $item ) :array {
75
+ $con = $this->getCon();
76
+ /** @var ModCon $mod */
77
+ $mod = $this->getMod();
78
+ $actionHandler = $mod->getScanCon( $item->VO->scan )
79
+ ->getItemActionHandler()
80
+ ->setScanItem( $item );
81
+
82
+ $actions = [];
83
+
84
+ $defaultButtonClasses = [
85
+ 'btn',
86
+ 'action',
87
+ ];
88
+
89
+ if ( !empty( $item->path_fragment ) ) {
90
+ $actions[] = sprintf( '<button class="action view-file btn-dark %s" title="%s" data-rid="%s">%s</button>',
91
+ implode( ' ', $defaultButtonClasses ),
92
+ __( 'View File Details', 'wp-simple-firewall' ),
93
+ $item->VO->scanresult_id,
94
+ $con->svgs->raw( 'bootstrap/zoom-in.svg' )
95
+ );
96
+ }
97
+
98
+ if ( in_array( $status, [ 'unrecognised', 'malware' ] ) ) {
99
+ $actions[] = sprintf( '<button class="btn-danger delete %s" title="%s" data-rid="%s">%s</button>',
100
+ implode( ' ', $defaultButtonClasses ),
101
+ __( 'Delete', 'wp-simple-firewall' ),
102
+ $item->VO->scanresult_id,
103
+ $con->svgs->raw( 'bootstrap/x-square.svg' )
104
+ );
105
+ }
106
+
107
+ try {
108
+ if ( in_array( $status, [ 'modified', 'missing', 'malware' ] )
109
+ && $actionHandler->getRepairHandler()->canRepairItem() ) {
110
+ $actions[] = sprintf( '<button class="btn-warning repair %s" title="%s" data-rid="%s">%s</button>',
111
+ implode( ' ', $defaultButtonClasses ),
112
+ __( 'Repair', 'wp-simple-firewall' ),
113
+ $item->VO->scanresult_id,
114
+ $con->svgs->raw( 'bootstrap/tools.svg' )
115
+ );
116
+ }
117
+ }
118
+ catch ( \Exception $e ) {
119
+ }
120
+
121
+ $actions[] = sprintf( '<button class="btn-light ignore %s" title="%s" data-rid="%s">%s</button>',
122
+ implode( ' ', $defaultButtonClasses ),
123
+ __( 'Ignore', 'wp-simple-firewall' ),
124
+ $item->VO->scanresult_id,
125
+ $con->svgs->raw( 'bootstrap/eye-slash-fill.svg' )
126
+ );
127
+
128
+ return $actions;
129
+ }
130
+
131
+ protected function getColumnContent_File( Scans\Afs\ResultItem $item ) :string {
132
+ return sprintf( '<div>%s</div>', $this->getColumnContent_FileAsHref( $item ) );
133
+ }
134
+
135
+ protected function getColumnContent_FileStatus( Scans\Afs\ResultItem $item, string $status ) :string {
136
+ $content = $status;
137
+
138
+ $FS = Services::WpFs();
139
+ if ( $FS->isFile( $item->path_full ) ) {
140
+ $carbon = Services::Request()->carbon( true );
141
+ $content = sprintf( '%s<ul style="list-style: square inside"><li>%s</li></ul>',
142
+ $status,
143
+ implode( '</li><li>', [
144
+ sprintf( '%s: %s', __( 'Modified', 'wp-simple-firewall' ),
145
+ $carbon->setTimestamp( $FS->getModifiedTime( $item->path_full ) )
146
+ ->diffForHumans()
147
+ ),
148
+ sprintf( '%s: %s', __( 'Size', 'wp-simple-firewall' ),
149
+ FormatBytes::Format( $FS->getFileSize( $item->path_full ) )
150
+ ),
151
+ sprintf( '%s: %s', __( 'Type', 'wp-simple-firewall' ), strtoupper( Paths::Ext( $item->path_full ) ) )
152
+ ] )
153
+ );
154
+ }
155
+
156
+ return $content;
157
+ }
158
+
159
+ protected function getColumnContent_FileAsHref( Scans\Afs\ResultItem $item ) :string {
160
+ return sprintf( '<a href="#" title="%s" class="action view-file" data-rid="%s">%s</a>',
161
+ __( 'View File Contents', 'wp-simple-firewall' ),
162
+ $item->VO->scanresult_id,
163
+ $item->path_fragment
164
+ );
165
+ }
166
+ }
src/lib/src/Modules/HackGuard/Lib/ScanTables/TableData/BaseLoadTableDataPluginTheme.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\ScanTables\TableData;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Scans;
6
+ use FernleafSystems\Wordpress\Services\Services;
7
+
8
+ class BaseLoadTableDataPluginTheme extends BaseLoadTableData {
9
+
10
+ public function run() :array {
11
+ $RS = $this->getRecordRetriever()->retrieveLatest();
12
+ try {
13
+ $files = array_map(
14
+ function ( $item ) {
15
+ /** @var Scans\Afs\ResultItem $item */
16
+ $data = $item->getRawData();
17
+ $data[ 'rid' ] = $item->VO->scanresult_id;
18
+ $data[ 'file' ] = $item->path_fragment;
19
+ $data[ 'created_at' ] = $item->VO->created_at;
20
+ $data[ 'detected_since' ] = Services::Request()
21
+ ->carbon( true )
22
+ ->setTimestamp( $item->VO->created_at )
23
+ ->diffForHumans();
24
+
25
+ if ( $item->is_checksumfail ) {
26
+ $data[ 'status_slug' ] = 'modified';
27
+ $data[ 'status' ] = __( 'Modified', 'wp-simple-firewall' );
28
+ }
29
+ elseif ( $item->is_missing ) {
30
+ $data[ 'status_slug' ] = 'missing';
31
+ $data[ 'status' ] = __( 'Missing', 'wp-simple-firewall' );
32
+ }
33
+ else {
34
+ $data[ 'status_slug' ] = 'unrecognised';
35
+ $data[ 'status' ] = __( 'Unrecognised', 'wp-simple-firewall' );
36
+ }
37
+ $data[ 'status' ] = $this->getColumnContent_FileStatus( $item, $data[ 'status' ] );
38
+
39
+ $data[ 'file_as_href' ] = $this->getColumnContent_File( $item );
40
+
41
+ $data[ 'file_type' ] = strtoupper( Services::Data()->getExtension( $item->path_full ) );
42
+ $data[ 'actions' ] = implode( ' ', $this->getActions( $data[ 'status_slug' ], $item ) );
43
+ return $data;
44
+ },
45
+ $RS->getItems()
46
+ );
47
+ }
48
+ catch ( \Exception $e ) {
49
+ $files = [];
50
+ }
51
+
52
+ return $files;
53
+ }
54
+ }
src/lib/src/Modules/HackGuard/Lib/ScanTables/TableData/LoadTableDataMalware.php ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\ScanTables\TableData;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Scan\Results\Retrieve;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Scans;
7
+ use FernleafSystems\Wordpress\Services\Services;
8
+
9
+ class LoadTableDataMalware extends BaseLoadTableData {
10
+
11
+ public function run() :array {
12
+ $RS = $this->getRecordRetriever()->retrieveLatest();
13
+ try {
14
+ $files = array_map(
15
+ function ( $item ) {
16
+ /** @var Scans\Afs\ResultItem $item */
17
+ $data = $item->getRawData();
18
+
19
+ $data[ 'rid' ] = $item->VO->scanresult_id;
20
+ $data[ 'file' ] = $item->path_fragment;
21
+ $data[ 'created_at' ] = $item->VO->created_at;
22
+ $data[ 'detected_since' ] = Services::Request()
23
+ ->carbon( true )
24
+ ->setTimestamp( $item->VO->created_at )
25
+ ->diffForHumans();
26
+
27
+ $data[ 'file_as_href' ] = $this->getColumnContent_File( $item );
28
+
29
+ $data[ 'status_slug' ] = 'malware';
30
+ $data[ 'status' ] = $this->getColumnContent_FileStatus( $item, __( 'Malware', 'wp-simple-firewall' ) );
31
+
32
+ $data[ 'line_numbers' ] = implode( ', ', array_map(
33
+ function ( $line ) {
34
+ return $line + 1; // because lines start at ZERO
35
+ },
36
+ array_keys( $item->mal_fp_lines )
37
+ ) );
38
+ $data[ 'mal_sig' ] = sprintf( '<code style="white-space: nowrap">%s</code>', esc_html( $item->mal_sig ) );
39
+ $data[ 'file_type' ] = strtoupper( Services::Data()->getExtension( $item->path_full ) );
40
+ $data[ 'actions' ] = implode( ' ', $this->getActions( $data[ 'status_slug' ], $item ) );
41
+ $data[ 'mal_details' ] = $this->getColumnContent_MalwareDetails(
42
+ $data[ 'line_numbers' ],
43
+ (int)$item->mal_fp_confidence,
44
+ $data[ 'mal_sig' ]
45
+ );
46
+
47
+ return $data;
48
+ },
49
+ $RS->getMalware()->getItems()
50
+ );
51
+ }
52
+ catch ( \Exception $e ) {
53
+ $files = [];
54
+ }
55
+
56
+ return $files;
57
+ }
58
+
59
+ protected function getColumnContent_MalwareDetails( string $lines, int $confidence, string $sig ) :string {
60
+ return sprintf( '<ul style="list-style: square inside"><li>%s</li></ul>',
61
+ implode( '</li><li>', [
62
+ sprintf( '%s: %s', __( 'Line Numbers' ), $lines ),
63
+ sprintf( '%s: %s', __( 'False Positive Confidence' ), $confidence ),
64
+ sprintf( '%s: %s', __( 'Pattern Detected' ), $sig ),
65
+ ] )
66
+ );
67
+ }
68
+
69
+ protected function getRecordRetriever() :Retrieve {
70
+ $retriever = parent::getRecordRetriever();
71
+ $retriever->wheres = array_merge( [
72
+ "`rim`.`meta_key`='is_mal'",
73
+ "`rim`.`meta_value`=1",
74
+ ], $retriever->wheres ?? [] );
75
+ return $retriever;
76
+ }
77
+ }
src/lib/src/Modules/HackGuard/Lib/ScanTables/TableData/LoadTableDataPlugin.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\ScanTables\TableData;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Scan\Results\Retrieve;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Scans;
7
+ use FernleafSystems\Wordpress\Services\Core\VOs\Assets\WpPluginVo;
8
+
9
+ class LoadTableDataPlugin extends BaseLoadTableDataPluginTheme {
10
+
11
+ /**
12
+ * @var WpPluginVo
13
+ */
14
+ private $plugin;
15
+
16
+ public function __construct( WpPluginVo $plugin ) {
17
+ $this->plugin = $plugin;
18
+ }
19
+
20
+ protected function getRecordRetriever() :Retrieve {
21
+ $retriever = parent::getRecordRetriever();
22
+ $retriever->wheres = array_merge( [
23
+ "`rim`.`meta_key`='ptg_slug'",
24
+ sprintf( "`rim`.`meta_value`='%s'", $this->plugin->file ),
25
+ ], $retriever->wheres ?? [] );
26
+ return $retriever;
27
+ }
28
+ }
src/lib/src/Modules/HackGuard/Lib/ScanTables/TableData/LoadTableDataTheme.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\ScanTables\TableData;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Scan\Results\Retrieve;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Scans;
7
+ use FernleafSystems\Wordpress\Services\Core\VOs\Assets\WpThemeVo;
8
+
9
+ class LoadTableDataTheme extends BaseLoadTableDataPluginTheme {
10
+
11
+ /**
12
+ * @var WpThemeVo
13
+ */
14
+ private $theme;
15
+
16
+ public function __construct( WpThemeVo $theme ) {
17
+ $this->theme = $theme;
18
+ }
19
+
20
+ protected function getRecordRetriever() :Retrieve {
21
+ $retriever = parent::getRecordRetriever();
22
+ $retriever->wheres = array_merge( [
23
+ "`rim`.`meta_key`='ptg_slug'",
24
+ sprintf( "`rim`.`meta_value`='%s'", $this->theme->stylesheet ),
25
+ ], $retriever->wheres ?? [] );
26
+ return $retriever;
27
+ }
28
+ }
src/lib/src/Modules/HackGuard/Lib/ScanTables/TableData/LoadTableDataWordpress.php ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\ScanTables\TableData;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\ModCon;
6
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Scan\Results\Retrieve;
7
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Scan\Controller\Afs;
8
+ use FernleafSystems\Wordpress\Plugin\Shield\Scans;
9
+ use FernleafSystems\Wordpress\Services\Services;
10
+
11
+ class LoadTableDataWordpress extends BaseLoadTableData {
12
+
13
+ public function run() :array {
14
+ $RS = $this->getRecordRetriever()->retrieveLatest();
15
+ try {
16
+ $files = array_map(
17
+ function ( $item ) {
18
+ /** @var Scans\Afs\ResultItem $item */
19
+ $data = $item->getRawData();
20
+
21
+ $data[ 'rid' ] = $item->VO->scanresult_id;
22
+ $data[ 'file' ] = $item->path_fragment;
23
+ $data[ 'created_at' ] = $item->VO->created_at;
24
+ $data[ 'detected_since' ] = Services::Request()
25
+ ->carbon( true )
26
+ ->setTimestamp( $item->VO->created_at )
27
+ ->diffForHumans();
28
+
29
+ $data[ 'file_as_href' ] = $this->getColumnContent_File( $item );
30
+
31
+ if ( $item->is_checksumfail ) {
32
+ $data[ 'status_slug' ] = 'modified';
33
+ $data[ 'status' ] = __( 'Modified', 'wp-simple-firewall' );
34
+ }
35
+ elseif ( $item->is_missing ) {
36
+ $data[ 'status_slug' ] = 'missing';
37
+ $data[ 'status' ] = __( 'Missing', 'wp-simple-firewall' );
38
+ }
39
+ else {
40
+ $data[ 'status_slug' ] = 'unrecognised';
41
+ $data[ 'status' ] = __( 'Unrecognised', 'wp-simple-firewall' );
42
+ }
43
+ $data[ 'status' ] = $this->getColumnContent_FileStatus( $item, $data[ 'status' ] );
44
+
45
+ $data[ 'file_type' ] = strtoupper( Services::Data()->getExtension( $item->path_full ) );
46
+ $data[ 'actions' ] = implode( ' ', $this->getActions( $data[ 'status_slug' ], $item ) );
47
+ return $data;
48
+ },
49
+ $RS->getWordpressCore()->getItems()
50
+ );
51
+ }
52
+ catch ( \Exception $e ) {
53
+ $files = [];
54
+ }
55
+
56
+ return $files;
57
+ }
58
+
59
+ protected function getRecordRetriever() :Retrieve {
60
+ $retriever = parent::getRecordRetriever();
61
+ $retriever->wheres = array_merge( [
62
+ "`rim`.`meta_key`='is_in_core'",
63
+ "`rim`.`meta_value`=1",
64
+ ], $retriever->wheres ?? [] );
65
+ return $retriever;
66
+ }
67
+ }
src/lib/src/Modules/HackGuard/ModCon.php CHANGED
@@ -35,24 +35,21 @@ class ModCon extends BaseShield\ModCon {
35
 
36
  public function getFileLocker() :Lib\FileLocker\FileLockerController {
37
  if ( !isset( $this->oFileLocker ) ) {
38
- $this->oFileLocker = ( new Lib\FileLocker\FileLockerController() )
39
- ->setMod( $this );
40
  }
41
  return $this->oFileLocker;
42
  }
43
 
44
  public function getScansCon() :Scan\ScansController {
45
  if ( !isset( $this->scanCon ) ) {
46
- $this->scanCon = ( new Scan\ScansController() )
47
- ->setMod( $this );
48
  }
49
  return $this->scanCon;
50
  }
51
 
52
  public function getScanQueueController() :Scan\Queue\Controller {
53
  if ( !isset( $this->scanQueueCon ) ) {
54
- $this->scanQueueCon = ( new Scan\Queue\Controller() )
55
- ->setMod( $this );
56
  }
57
  return $this->scanQueueCon;
58
  }
35
 
36
  public function getFileLocker() :Lib\FileLocker\FileLockerController {
37
  if ( !isset( $this->oFileLocker ) ) {
38
+ $this->oFileLocker = ( new Lib\FileLocker\FileLockerController() )->setMod( $this );
 
39
  }
40
  return $this->oFileLocker;
41
  }
42
 
43
  public function getScansCon() :Scan\ScansController {
44
  if ( !isset( $this->scanCon ) ) {
45
+ $this->scanCon = ( new Scan\ScansController() )->setMod( $this );
 
46
  }
47
  return $this->scanCon;
48
  }
49
 
50
  public function getScanQueueController() :Scan\Queue\Controller {
51
  if ( !isset( $this->scanQueueCon ) ) {
52
+ $this->scanQueueCon = ( new Scan\Queue\Controller() )->setMod( $this );
 
53
  }
54
  return $this->scanQueueCon;
55
  }
src/lib/src/Modules/HackGuard/Render/ScanResults/SectionPlugins.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Render\ScanResults;
4
 
5
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\ScanTables\LoadRawTableData;
6
  use FernleafSystems\Wordpress\Services\Core\VOs\Assets\WpPluginVo;
7
  use FernleafSystems\Wordpress\Services\Services;
8
  use FernleafSystems\Wordpress\Services\Utilities\Assets\DetectInstallationDate;
@@ -84,9 +84,9 @@ class SectionPlugins extends SectionPluginThemesBase {
84
  $carbon = Services::Request()->carbon();
85
 
86
  $abandoned = $this->getAbandoned()->getItemForSlug( $plugin->file );
87
- $guardFilesData = ( new LoadRawTableData() )
88
  ->setMod( $this->getMod() )
89
- ->loadForPlugin( $plugin );
90
 
91
  $vulnerabilities = $this->getVulnerabilities()->getItemsForSlug( $plugin->file );
92
 
@@ -95,7 +95,7 @@ class SectionPlugins extends SectionPluginThemesBase {
95
 
96
  $flags = [
97
  'has_update' => $plugin->hasUpdate(),
98
- 'has_guard_files' => !empty( $guardFilesData ),
99
  'is_abandoned' => !empty( $abandoned ),
100
  'is_active' => $plugin->active,
101
  'is_vulnerable' => !empty( $vulnerabilities ),
@@ -140,7 +140,7 @@ class SectionPlugins extends SectionPluginThemesBase {
140
  'flags' => $flags,
141
  'vars' => [
142
  'abandoned_rid' => empty( $abandoned ) ? -1 : $abandoned->VO->scanresult_id,
143
- 'count_items' => count( $guardFilesData ) + count( $vulnerabilities )
144
  + ( empty( $abandoned ) ? 0 : 1 )
145
  ],
146
  ];
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Render\ScanResults;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\ScanTables\TableData\LoadTableDataPlugin;
6
  use FernleafSystems\Wordpress\Services\Core\VOs\Assets\WpPluginVo;
7
  use FernleafSystems\Wordpress\Services\Services;
8
  use FernleafSystems\Wordpress\Services\Utilities\Assets\DetectInstallationDate;
84
  $carbon = Services::Request()->carbon();
85
 
86
  $abandoned = $this->getAbandoned()->getItemForSlug( $plugin->file );
87
+ $countGuardFiles = ( new LoadTableDataPlugin( $plugin ) )
88
  ->setMod( $this->getMod() )
89
+ ->countAll();
90
 
91
  $vulnerabilities = $this->getVulnerabilities()->getItemsForSlug( $plugin->file );
92
 
95
 
96
  $flags = [
97
  'has_update' => $plugin->hasUpdate(),
98
+ 'has_guard_files' => $countGuardFiles > 0,
99
  'is_abandoned' => !empty( $abandoned ),
100
  'is_active' => $plugin->active,
101
  'is_vulnerable' => !empty( $vulnerabilities ),
140
  'flags' => $flags,
141
  'vars' => [
142
  'abandoned_rid' => empty( $abandoned ) ? -1 : $abandoned->VO->scanresult_id,
143
+ 'count_items' => $countGuardFiles + count( $vulnerabilities )
144
  + ( empty( $abandoned ) ? 0 : 1 )
145
  ],
146
  ];
src/lib/src/Modules/HackGuard/Render/ScanResults/SectionThemes.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Render\ScanResults;
4
 
5
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\ScanTables\LoadRawTableData;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Scans;
7
  use FernleafSystems\Wordpress\Services\Core\VOs\Assets\WpThemeVo;
8
  use FernleafSystems\Wordpress\Services\Services;
@@ -85,16 +85,16 @@ class SectionThemes extends SectionPluginThemesBase {
85
  $carbon = Services::Request()->carbon();
86
 
87
  $abandoned = $this->getAbandoned()->getItemForSlug( $theme->stylesheet );
88
- $guardFilesData = ( new LoadRawTableData() )
89
  ->setMod( $this->getMod() )
90
- ->loadForTheme( $theme );
91
 
92
  $vulnerabilities = $this->getVulnerabilities()->getItemsForSlug( $theme->stylesheet );
93
 
94
  $flags = [
95
  'has_update' => $theme->hasUpdate(),
96
  'is_abandoned' => !empty( $abandoned ),
97
- 'has_guard_files' => !empty( $guardFilesData ),
98
  'is_active' => $theme->active || $theme->is_parent,
99
  'is_ignored' => $theme->active || $theme->is_parent,
100
  'is_vulnerable' => !empty( $vulnerabilities ),
@@ -173,8 +173,7 @@ class SectionThemes extends SectionPluginThemesBase {
173
  ],
174
  'flags' => $flags,
175
  'vars' => [
176
- 'count_items' => count( $guardFilesData ) + count( $vulnerabilities )
177
- + ( empty( $abandoned ) ? 0 : 1 )
178
  ],
179
  ];
180
  }
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Render\ScanResults;
4
 
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Lib\ScanTables\TableData\LoadTableDataTheme;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Scans;
7
  use FernleafSystems\Wordpress\Services\Core\VOs\Assets\WpThemeVo;
8
  use FernleafSystems\Wordpress\Services\Services;
85
  $carbon = Services::Request()->carbon();
86
 
87
  $abandoned = $this->getAbandoned()->getItemForSlug( $theme->stylesheet );
88
+ $countGuardFiles = ( new LoadTableDataTheme( $theme ) )
89
  ->setMod( $this->getMod() )
90
+ ->countAll();
91
 
92
  $vulnerabilities = $this->getVulnerabilities()->getItemsForSlug( $theme->stylesheet );
93
 
94
  $flags = [
95
  'has_update' => $theme->hasUpdate(),
96
  'is_abandoned' => !empty( $abandoned ),
97
+ 'has_guard_files' => $countGuardFiles > 0,
98
  'is_active' => $theme->active || $theme->is_parent,
99
  'is_ignored' => $theme->active || $theme->is_parent,
100
  'is_vulnerable' => !empty( $vulnerabilities ),
173
  ],
174
  'flags' => $flags,
175
  'vars' => [
176
+ 'count_items' => $countGuardFiles + count( $vulnerabilities ) + ( empty( $abandoned ) ? 0 : 1 )
 
177
  ],
178
  ];
179
  }
src/lib/src/Modules/HackGuard/Scan/Controller/Base.php CHANGED
@@ -131,7 +131,7 @@ abstract class Base extends ExecOnceModConsumer {
131
  $this->latestResults = ( new HackGuard\Scan\Results\Retrieve() )
132
  ->setMod( $this->getMod() )
133
  ->setScanController( $this )
134
- ->retrieveLatest( true );
135
  }
136
  catch ( \Exception $e ) {
137
  }
131
  $this->latestResults = ( new HackGuard\Scan\Results\Retrieve() )
132
  ->setMod( $this->getMod() )
133
  ->setScanController( $this )
134
+ ->retrieveLatest();
135
  }
136
  catch ( \Exception $e ) {
137
  }
src/lib/src/Modules/HackGuard/Scan/Results/Counts.php CHANGED
@@ -64,7 +64,6 @@ class Counts {
64
  case 'theme_files':
65
  $count = $resultsRetrieve->setAdditionalWheres( [ "`rim`.`meta_key`='is_in_theme'", ] )->count();
66
  break;
67
-
68
  case 'abandoned':
69
  $count = $resultsRetrieve
70
  ->setScanController( $mod->getScanCon( Apc::SCAN_SLUG ) )
64
  case 'theme_files':
65
  $count = $resultsRetrieve->setAdditionalWheres( [ "`rim`.`meta_key`='is_in_theme'", ] )->count();
66
  break;
 
67
  case 'abandoned':
68
  $count = $resultsRetrieve
69
  ->setScanController( $mod->getScanCon( Apc::SCAN_SLUG ) )
src/lib/src/Modules/HackGuard/Scan/Results/Retrieve.php CHANGED
@@ -2,6 +2,7 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Scan\Results;
4
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Databases;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\DB\{
7
  ResultItemMeta as ResultItemMetaDB,
@@ -14,7 +15,14 @@ use FernleafSystems\Wordpress\Plugin\Shield\Scans;
14
  use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\ResultsSet;
15
  use FernleafSystems\Wordpress\Services\Services;
16
 
17
- class Retrieve {
 
 
 
 
 
 
 
18
 
19
  use ModConsumer;
20
  use ScanControllerConsumer;
@@ -46,14 +54,11 @@ class Retrieve {
46
  $this->setScanController( $mod->getScanCon( $scan ) );
47
 
48
  $raw = Services::WpDb()->selectCustom(
49
- sprintf( $this->getBaseQuery(),
50
- implode( ',', $this->standardSelectFields() ),
51
- implode( ' AND ', array_filter( array_merge(
52
- [
53
- sprintf( "`sr`.`id`=%s", $scanResultID )
54
- ],
55
- $this->getAdditionalWheres()
56
- ) ) )
57
  )
58
  );
59
  $rawResults = empty( $raw ) ? [] : $raw;
@@ -75,19 +80,14 @@ class Retrieve {
75
  $latestID = $this->getLatestScanID();
76
  if ( $latestID >= 0 ) {
77
  $raw = Services::WpDb()->selectCustom(
78
- sprintf( $this->getBaseQuery(),
79
- implode( ',', $this->standardSelectFields() ),
80
- implode( ' AND ', array_filter( array_merge(
81
- [
82
- sprintf( "`sr`.`id` IN (%s)", implode( ',', $IDs ) )
83
- ],
84
- $this->getAdditionalWheres()
85
- ) ) )
86
  )
87
  );
88
- if ( !empty( $raw ) ) {
89
- $results = $raw;
90
- }
91
  }
92
  }
93
 
@@ -121,14 +121,13 @@ class Retrieve {
121
  /**
122
  * @return Scans\Afs\ResultsSet|Scans\Apc\ResultsSet|Scans\Wpv\ResultsSet
123
  */
124
- public function retrieveLatest( bool $includeIgnored = true ) {
125
 
126
  $latestID = $this->getLatestScanID();
127
  if ( $latestID >= 0 ) {
128
  $results = $this
129
  ->setAdditionalWheres( [
130
  sprintf( "`sr`.`scan_ref`=%s", $latestID ),
131
- $includeIgnored ? '' : "`ri`.ignored_at = 0",
132
  "`ri`.`item_repaired_at`=0",
133
  "`ri`.`item_deleted_at`=0"
134
  ] )
@@ -145,24 +144,38 @@ class Retrieve {
145
  * @return Scans\Base\ResultsSet
146
  */
147
  public function retrieve() {
148
- $results = [];
149
  $raw = Services::WpDb()->selectCustom(
150
- sprintf( $this->getBaseQuery(),
151
- implode( ',', $this->standardSelectFields() ),
152
- implode( ' AND ', array_filter( array_merge(
153
- [
154
- "`ri`.`auto_filtered_at`=0",
155
- "`ri`.`deleted_at`=0"
156
- ],
157
- $this->getAdditionalWheres()
158
- ) ) )
159
  )
160
  );
161
- if ( !empty( $raw ) ) {
162
- $results = $raw;
163
- }
164
 
165
- return $this->convertToResultsSet( $results );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  }
167
 
168
  public function count() :int {
@@ -180,7 +193,8 @@ class Retrieve {
180
  "`ri`.`item_deleted_at`=0",
181
  "`ri`.`deleted_at`=0"
182
  ],
183
- $this->getAdditionalWheres()
 
184
  ) ) )
185
  )
186
  );
@@ -263,7 +277,7 @@ class Retrieve {
263
  return empty( $latest ) ? -1 : $latest->id;
264
  }
265
 
266
- private function getBaseQuery() :string {
267
  /** @var ModCon $mod */
268
  $mod = $this->getMod();
269
  return sprintf( "SELECT %%s
@@ -272,11 +286,19 @@ class Retrieve {
272
  ON `sr`.scan_ref = `scans`.id
273
  INNER JOIN `%s` as `ri`
274
  ON `sr`.resultitem_ref = `ri`.id
 
275
  WHERE %%s
276
- ORDER BY `sr`.`id` ASC;",
 
 
277
  $mod->getDbH_ScanResults()->getTableSchema()->table,
278
  $mod->getDbH_Scans()->getTableSchema()->table,
279
- $mod->getDbH_ResultItems()->getTableSchema()->table
 
 
 
 
 
280
  );
281
  }
282
 
@@ -325,8 +347,8 @@ class Retrieve {
325
  return is_array( $this->additionalWheres ) ? $this->additionalWheres : [];
326
  }
327
 
328
- public function setAdditionalWheres( array $wheres ) {
329
- $this->additionalWheres = $wheres;
330
  return $this;
331
  }
332
  }
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\Scan\Results;
4
 
5
+ use FernleafSystems\Utilities\Data\Adapter\DynPropertiesClass;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Databases;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\HackGuard\DB\{
8
  ResultItemMeta as ResultItemMetaDB,
15
  use FernleafSystems\Wordpress\Plugin\Shield\Scans\Base\ResultsSet;
16
  use FernleafSystems\Wordpress\Services\Services;
17
 
18
+ /**
19
+ * @property int $limit
20
+ * @property int $offset
21
+ * @property string[] $wheres
22
+ * @property string $order_by
23
+ * @property string $order_dir
24
+ */
25
+ class Retrieve extends DynPropertiesClass {
26
 
27
  use ModConsumer;
28
  use ScanControllerConsumer;
54
  $this->setScanController( $mod->getScanCon( $scan ) );
55
 
56
  $raw = Services::WpDb()->selectCustom(
57
+ $this->buildQuery(
58
+ $this->standardSelectFields(),
59
+ [
60
+ sprintf( "`sr`.`id`=%s", $scanResultID )
61
+ ]
 
 
 
62
  )
63
  );
64
  $rawResults = empty( $raw ) ? [] : $raw;
80
  $latestID = $this->getLatestScanID();
81
  if ( $latestID >= 0 ) {
82
  $raw = Services::WpDb()->selectCustom(
83
+ $this->buildQuery(
84
+ $this->standardSelectFields(),
85
+ [
86
+ sprintf( "`sr`.`id` IN (%s)", implode( ',', $IDs ) )
87
+ ]
 
 
 
88
  )
89
  );
90
+ $results = empty( $raw ) ? [] : $raw;
 
 
91
  }
92
  }
93
 
121
  /**
122
  * @return Scans\Afs\ResultsSet|Scans\Apc\ResultsSet|Scans\Wpv\ResultsSet
123
  */
124
+ public function retrieveLatest() {
125
 
126
  $latestID = $this->getLatestScanID();
127
  if ( $latestID >= 0 ) {
128
  $results = $this
129
  ->setAdditionalWheres( [
130
  sprintf( "`sr`.`scan_ref`=%s", $latestID ),
 
131
  "`ri`.`item_repaired_at`=0",
132
  "`ri`.`item_deleted_at`=0"
133
  ] )
144
  * @return Scans\Base\ResultsSet
145
  */
146
  public function retrieve() {
 
147
  $raw = Services::WpDb()->selectCustom(
148
+ $this->buildQuery(
149
+ $this->standardSelectFields(),
150
+ [
151
+ "`ri`.`auto_filtered_at`=0",
152
+ "`ri`.`deleted_at`=0"
153
+ ]
 
 
 
154
  )
155
  );
156
+ return $this->convertToResultsSet( empty( $raw ) ? [] : $raw );
157
+ }
 
158
 
159
+ public function buildQuery( array $selectFields, array $wheres ) :string {
160
+ $hasResultMeta = false;
161
+
162
+ $wheres = array_filter( array_merge(
163
+ $wheres,
164
+ $this->getAdditionalWheres(),
165
+ is_array( $this->wheres ) ? $this->wheres : []
166
+ ) );
167
+
168
+ foreach ( $wheres as $where ) {
169
+ if ( strpos( $where, '`rim`' ) !== false ) {
170
+ $hasResultMeta = true;
171
+ break;
172
+ }
173
+ }
174
+ return sprintf(
175
+ $this->getBaseQuery( $hasResultMeta ),
176
+ implode( ',', $selectFields ),
177
+ implode( ' AND ', $wheres )
178
+ );
179
  }
180
 
181
  public function count() :int {
193
  "`ri`.`item_deleted_at`=0",
194
  "`ri`.`deleted_at`=0"
195
  ],
196
+ $this->getAdditionalWheres(),
197
+ is_array( $this->wheres ) ? $this->wheres : []
198
  ) ) )
199
  )
200
  );
277
  return empty( $latest ) ? -1 : $latest->id;
278
  }
279
 
280
+ private function getBaseQuery( bool $joinWithResultMeta = false ) :string {
281
  /** @var ModCon $mod */
282
  $mod = $this->getMod();
283
  return sprintf( "SELECT %%s
286
  ON `sr`.scan_ref = `scans`.id
287
  INNER JOIN `%s` as `ri`
288
  ON `sr`.resultitem_ref = `ri`.id
289
+ %s
290
  WHERE %%s
291
+ %s
292
+ %s
293
+ %s;",
294
  $mod->getDbH_ScanResults()->getTableSchema()->table,
295
  $mod->getDbH_Scans()->getTableSchema()->table,
296
+ $mod->getDbH_ResultItems()->getTableSchema()->table,
297
+ $joinWithResultMeta ? sprintf( 'INNER JOIN `%s` as `rim` ON `rim`.`ri_ref` = `ri`.id',
298
+ $mod->getDbH_ResultItemMeta()->getTableSchema()->table ) : '',
299
+ empty( $this->order_by ) ? 'ORDER BY `sr`.`id` ASC' : sprintf( 'ORDER BY %s %s', $this->order_by, $this->order_dir ),
300
+ empty( $this->limit ) ? '' : sprintf( 'LIMIT %s', (int)$this->limit ),
301
+ empty( $this->offset ) ? '' : sprintf( 'OFFSET %s', (int)$this->offset )
302
  );
303
  }
304
 
347
  return is_array( $this->additionalWheres ) ? $this->additionalWheres : [];
348
  }
349
 
350
+ public function setAdditionalWheres( array $wheres, bool $merge = false ) {
351
+ $this->additionalWheres = $merge ? array_merge( $this->getAdditionalWheres(), $wheres ) : $wheres;
352
  return $this;
353
  }
354
  }
src/lib/src/Modules/HackGuard/Scan/ScansController.php CHANGED
@@ -75,8 +75,7 @@ class ScansController extends ExecOnceModConsumer {
75
 
76
  public function getScanResultsCount() :Results\Counts {
77
  if ( !isset( $this->scanResultsStatus ) ) {
78
- $this->scanResultsStatus = ( new Results\Counts() )
79
- ->setMod( $this->getMod() );
80
  }
81
  return $this->scanResultsStatus;
82
  }
75
 
76
  public function getScanResultsCount() :Results\Counts {
77
  if ( !isset( $this->scanResultsStatus ) ) {
78
+ $this->scanResultsStatus = ( new Results\Counts() )->setMod( $this->getMod() );
 
79
  }
80
  return $this->scanResultsStatus;
81
  }
src/lib/src/Modules/IPs/WpCli/Add.php CHANGED
@@ -28,26 +28,24 @@ class Add extends BaseAddRemove {
28
  }
29
 
30
  /**
31
- * @param array $null
32
- * @param array $args
33
  * @throws WP_CLI\ExitException
34
  */
35
  public function cmdIpAdd( array $null, array $args ) {
36
-
37
- $adder = ( new Ops\AddIp() )
38
- ->setMod( $this->getMod() )
39
- ->setIP( $args[ 'ip' ] );
40
  try {
41
- if ( $args[ 'list' ] === 'white' ) {
42
- $adder->toManualWhitelist( $args[ 'label' ] ?? '' );
43
- }
44
- else {
45
- $adder->toManualBlacklist( $args[ 'label' ] ?? '' );
46
- }
 
 
 
 
 
47
  }
48
  catch ( \Exception $e ) {
49
  WP_CLI::error( $e->getMessage() );
50
  }
51
- WP_CLI::success( __( 'IP address added successfully.', 'wp-simple-firewall' ) );
52
  }
53
  }
28
  }
29
 
30
  /**
 
 
31
  * @throws WP_CLI\ExitException
32
  */
33
  public function cmdIpAdd( array $null, array $args ) {
 
 
 
 
34
  try {
35
+ $this->checkList( $args[ 'list' ] );
36
+
37
+ $adder = ( new Ops\AddIp() )
38
+ ->setMod( $this->getMod() )
39
+ ->setIP( $args[ 'ip' ] );
40
+
41
+ in_array( $args[ 'list' ], [ 'white', 'bypass' ] ) ?
42
+ $adder->toManualWhitelist( $args[ 'label' ] ?? '' )
43
+ : $adder->toManualBlacklist( $args[ 'label' ] ?? '' );
44
+
45
+ WP_CLI::success( __( 'IP address added successfully.', 'wp-simple-firewall' ) );
46
  }
47
  catch ( \Exception $e ) {
48
  WP_CLI::error( $e->getMessage() );
49
  }
 
50
  }
51
  }
src/lib/src/Modules/IPs/WpCli/Base.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php declare( strict_types=1 );
2
+
3
+ namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\WpCli;
4
+
5
+ use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\WpCli\BaseWpCliCmd;
6
+
7
+ class Base extends BaseWpCliCmd {
8
+
9
+ /**
10
+ * @throws \Exception
11
+ */
12
+ protected function checkList( string $list ) {
13
+ if ( !in_array( $list, [ 'white', 'bypass', 'black', 'block' ] ) ) {
14
+ throw new \Exception( sprintf( '%s %s',
15
+ sprintf( __( "'%s' is an unsupported IP list.", 'wp-simple-firewall' ), $list ),
16
+ sprintf( __( 'Please use one of %s.', 'wp-simple-firewall' ), "'bypass' or 'white'; 'block' or 'black'" )
17
+ ) );
18
+ }
19
+ }
20
+ }
src/lib/src/Modules/IPs/WpCli/BaseAddRemove.php CHANGED
@@ -2,9 +2,7 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\WpCli;
4
 
5
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\WpCli\BaseWpCliCmd;
6
-
7
- class BaseAddRemove extends BaseWpCliCmd {
8
 
9
  /**
10
  * @return array[]
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\WpCli;
4
 
5
+ class BaseAddRemove extends Base {
 
 
6
 
7
  /**
8
  * @return array[]
src/lib/src/Modules/IPs/WpCli/Enumerate.php CHANGED
@@ -2,12 +2,11 @@
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\WpCli;
4
 
5
- use FernleafSystems\Wordpress\Plugin\Shield\Modules\Base\WpCli\BaseWpCliCmd;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Ops;
7
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\ModCon;
8
  use WP_CLI;
9
 
10
- class Enumerate extends BaseWpCliCmd {
11
 
12
  /**
13
  * @throws \Exception
@@ -32,24 +31,31 @@ class Enumerate extends BaseWpCliCmd {
32
  ] ) );
33
  }
34
 
35
- public function cmdPrint( $null, $aA ) {
36
  /** @var ModCon $mod */
37
  $mod = $this->getMod();
38
 
39
- $oRtr = ( new Ops\RetrieveIpsForLists() )
40
- ->setDbHandler( $mod->getDbHandler_IPs() );
41
- $aIPs = $aA[ 'list' ] === 'white' ? $oRtr->white() : $oRtr->black();
42
- $aIPs = array_map(
43
- function ( $sIP ) {
44
- return [ 'IP' => $sIP, ];
45
- },
46
- $aIPs
47
- );
48
-
49
- WP_CLI\Utils\format_items(
50
- 'table',
51
- $aIPs,
52
- [ 'IP' ]
53
- );
 
 
 
 
 
 
 
54
  }
55
  }
2
 
3
  namespace FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\WpCli;
4
 
 
5
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\Lib\Ops;
6
  use FernleafSystems\Wordpress\Plugin\Shield\Modules\IPs\ModCon;
7
  use WP_CLI;
8
 
9
+ class Enumerate extends Base {
10
 
11
  /**
12
  * @throws \Exception
31
  ] ) );
32
  }
33
 
34
+ public function cmdPrint( array $null, array $args ) {
35
  /** @var ModCon $mod */
36
  $mod = $this->getMod();
37
 
38
+ try {
39
+ $this->checkList( $args[ 'list' ] );
40
+
41
+ $retriever = ( new Ops\RetrieveIpsForLists() )
42
+ ->setDbHandler( $mod->getDbHandler_IPs() );
43
+
44
+ $IPs = array_map(
45
+ function ( $ip ) {
46
+ return [ 'IP' => $ip, ];
47
+ },
48
+ in_array( $args[ 'list' ], [ 'white', 'bypass' ] ) ? $retriever->white() : $retriever->black()
49
+ );
50
+
51
+ WP_CLI\Utils\format_items(
52
+ 'table',
53
+ $IPs,
54
+ [ 'IP' ]
55
+ );
56
+ }
57
+ catch ( \Exception $e ) {
58
+ WP_CLI::error( $e->getMessage() );
59
+ }
60
  }
61
  }
src/lib/src/Modules/IPs/WpCli/Remove.php CHANGED
@@ -20,26 +20,22 @@ class Remove extends BaseAddRemove {
20
  }
21
 
22
  /**
23
- * @param array $null
24
- * @param array $args
25
  * @throws WP_CLI\ExitException
26
  */
27
  public function cmdIpRemove( array $null, array $args ) {
28
- /** @var IPs\ModCon $mod */
29
- $mod = $this->getMod();
30
 
31
- $deleter = ( new IPs\Lib\Ops\DeleteIp() )
32
- ->setMod( $mod )
33
- ->setIP( $args[ 'ip' ] );
34
- if ( $args[ 'list' ] === 'white' ) {
35
- $success = $deleter->fromWhiteList();
 
 
36
  }
37
- else {
38
- $success = $deleter->fromBlacklist();
39
  }
40
-
41
- $success ?
42
- WP_CLI::success( __( 'IP address removed successfully.', 'wp-simple-firewall' ) )
43
- : WP_CLI::error( __( "IP address couldn't be removed. (It may not be on this list)", 'wp-simple-firewall' ) );
44
  }
45
  }
20
  }
21
 
22
  /**
 
 
23
  * @throws WP_CLI\ExitException
24
  */
25
  public function cmdIpRemove( array $null, array $args ) {
26
+ try {
27
+ $this->checkList( $args[ 'list' ] );
28
 
29
+ $del = ( new IPs\Lib\Ops\DeleteIp() )
30
+ ->setMod( $this->getMod() )
31
+ ->setIP( $args[ 'ip' ] );
32
+
33
+ ( in_array( $args[ 'list' ], [ 'white', 'bypass' ] ) ? $del->fromWhiteList() : $del->fromBlacklist() ) ?
34
+ WP_CLI::success( __( 'IP address removed successfully.', 'wp-simple-firewall' ) )
35
+ : WP_CLI::error( __( "IP address couldn't be removed. (It may not be on this list)", 'wp-simple-firewall' ) );
36
  }
37
+ catch ( \Exception $e ) {
38
+ WP_CLI::error( $e->getMessage() );
39
  }
 
 
 
 
40
  }
41
  }
src/lib/src/Modules/License/Processor.php CHANGED
@@ -11,7 +11,7 @@ class Processor extends BaseShield\Processor {
11
  $mod = $this->getMod();
12
  $mod->getLicenseHandler()->execute();
13
  ( new Lib\PluginNameSuffix() )
14
- ->setMod( $this->getMod() )
15
  ->execute();
16
  }
17
  }
11
  $mod = $this->getMod();
12
  $mod->getLicenseHandler()->execute();
13
  ( new Lib\PluginNameSuffix() )
14
+ ->setMod( $mod )
15
  ->execute();
16
  }
17
  }
src/lib/src/Modules/Plugin/Lib/PluginTelemetry.php CHANGED
@@ -135,15 +135,18 @@ class PluginTelemetry extends ExecOnceModConsumer {
135
  }
136
 
137
  private function getBaseTrackingData() :array {
 
138
  $WP = Services::WpGeneral();
139
  $WPP = Services::WpPlugins();
140
  return [
141
  'env' => [
142
- 'slug' => $this->getCon()->getPluginSlug(),
 
143
  'unique_site_hash' => sha1( network_home_url( '/' ) ),
144
  'php' => Services::Data()->getPhpVersionCleaned(),
145
  'wordpress' => $WP->getVersion(),
146
- 'version' => $this->getCon()->getVersion(),
 
147
  'is_wpms' => $WP->isMultisite() ? 1 : 0,
148
  'is_cp' => $WP->isClassicPress() ? 1 : 0,
149
  'ssl' => is_ssl() ? 1 : 0,
135
  }
136
 
137
  private function getBaseTrackingData() :array {
138
+ $con = $this->getCon();
139
  $WP = Services::WpGeneral();
140
  $WPP = Services::WpPlugins();
141
  return [
142
  'env' => [
143
+ 'slug' => $con->getPluginSlug(),
144
+ 'installation_id' => $con->getSiteInstallationId(),
145
  'unique_site_hash' => sha1( network_home_url( '/' ) ),
146
  'php' => Services::Data()->getPhpVersionCleaned(),
147
  'wordpress' => $WP->getVersion(),
148
+ 'version' => $con->getVersion(),
149
+ 'plugin_version' => $con->getVersion(),
150
  'is_wpms' => $WP->isMultisite() ? 1 : 0,
151
  'is_cp' => $WP->isClassicPress() ? 1 : 0,
152
  'ssl' => is_ssl() ? 1 : 0,
src/lib/src/Modules/Traffic/Lib/TrafficTable/BuildTrafficTableData.php CHANGED
@@ -32,8 +32,8 @@ class BuildTrafficTableData extends BaseBuildTableData {
32
 
33
  private $ipInfo = [];
34
 
35
- protected function loadLogsWithSearch() :array {
36
- return $this->loadLogsWithDirectQuery();
37
  }
38
 
39
  protected function getSearchPanesData() :array {
@@ -45,7 +45,7 @@ class BuildTrafficTableData extends BaseBuildTableData {
45
  /**
46
  * @param LogRecord[] $records
47
  */
48
- protected function buildTableRowsFromRawLogs( array $records ) :array {
49
  $this->users = [ 0 => __( 'No', 'wp-simple-firewall' ) ];
50
 
51
  return array_values( array_filter( array_map(
32
 
33
  private $ipInfo = [];
34
 
35
+ protected function loadRecordsWithSearch() :array {
36
+ return $this->loadRecordsWithDirectQuery();
37
  }
38
 
39
  protected function getSearchPanesData() :array {
45
  /**
46
  * @param LogRecord[] $records
47
  */
48
+ protected function buildTableRowsFromRawRecords( array $records ) :array {
49
  $this->users = [ 0 => __( 'No', 'wp-simple-firewall' ) ];
50
 
51
  return array_values( array_filter( array_map(
src/lib/src/Tables/DataTables/Build/Scans/BaseForScan.php CHANGED
@@ -30,6 +30,9 @@ class BaseForScan extends Base {
30
  'orderable' => true,
31
  'searchable' => false,
32
  'visible' => false,
 
 
 
33
  ],
34
  'file' => [
35
  'data' => 'file',
@@ -38,41 +41,59 @@ class BaseForScan extends Base {
38
  'orderable' => true,
39
  'searchable' => true,
40
  'visible' => true,
 
 
 
41
  ],
42
  'file_as_href' => [
43
- 'data' => 'file_as_href',
 
 
 
44
  'title' => __( 'File' ),
45
  'className' => 'file_as_href',
46
  'orderable' => true,
47
  'searchable' => true,
48
  'visible' => true,
 
 
 
49
  ],
50
  'file_type' => [
51
  'data' => 'file_type',
52
  'title' => __( 'Type' ),
53
  'className' => 'file_type',
54
- 'orderable' => true,
55
- 'searchable' => true,
56
- 'visible' => true,
 
 
 
57
  ],
58
  'status' => [
59
  'data' => 'status',
60
  'title' => __( 'Status' ),
61
  'className' => 'status',
62
- 'orderable' => true,
63
  'searchable' => false,
64
  'visible' => true,
 
 
 
65
  ],
66
  'detected' => [
67
  'data' => [
68
  '_' => 'detected_since',
69
- 'sort' => 'detected_at',
70
  ],
71
  'title' => __( 'Detected' ),
72
  'className' => 'detected',
73
  'orderable' => true,
74
  'searchable' => false,
75
  'visible' => true,
 
 
 
76
  ],
77
  'actions' => [
78
  'data' => 'actions',
@@ -81,14 +102,20 @@ class BaseForScan extends Base {
81
  'orderable' => false,
82
  'searchable' => false,
83
  'visible' => true,
 
 
 
84
  ],
85
  'mal_fp_confidence' => [
86
  'data' => 'mal_fp_confidence',
87
  'title' => __( 'False Positive Confidence' ),
88
  'className' => 'mal_fp_confidence',
89
- 'orderable' => true,
90
  'searchable' => false,
91
  'visible' => true,
 
 
 
92
  ],
93
  'line_numbers' => [
94
  'data' => 'line_numbers',
@@ -97,14 +124,9 @@ class BaseForScan extends Base {
97
  'orderable' => false,
98
  'searchable' => false,
99
  'visible' => true,
100
- ],
101
- 'mal_sig' => [
102
- 'data' => 'mal_sig',
103
- 'title' => __( 'Pattern Detected' ),
104
- 'className' => 'mal_sig',
105
- 'orderable' => false,
106
- 'searchable' => true,
107
- 'visible' => true,
108
  ],
109
  ];
110
  }
30
  'orderable' => true,
31
  'searchable' => false,
32
  'visible' => false,
33
+ 'searchPanes' => [
34
+ 'show' => false
35
+ ],
36
  ],
37
  'file' => [
38
  'data' => 'file',
41
  'orderable' => true,
42
  'searchable' => true,
43
  'visible' => true,
44
+ 'searchPanes' => [
45
+ 'show' => false
46
+ ],
47
  ],
48
  'file_as_href' => [
49
+ 'data' => [
50
+ '_' => 'file_as_href',
51
+ 'sort' => 'file',
52
+ ],
53
  'title' => __( 'File' ),
54
  'className' => 'file_as_href',
55
  'orderable' => true,
56
  'searchable' => true,
57
  'visible' => true,
58
+ 'searchPanes' => [
59
+ 'show' => false
60
+ ],
61
  ],
62
  'file_type' => [
63
  'data' => 'file_type',
64
  'title' => __( 'Type' ),
65
  'className' => 'file_type',
66
+ 'orderable' => false,
67
+ 'searchable' => false,
68
+ 'visible' => false,
69
+ 'searchPanes' => [
70
+ 'show' => true
71
+ ],
72
  ],
73
  'status' => [
74
  'data' => 'status',
75
  'title' => __( 'Status' ),
76
  'className' => 'status',
77
+ 'orderable' => false,
78
  'searchable' => false,
79
  'visible' => true,
80
+ 'searchPanes' => [
81
+ 'show' => true
82
+ ],
83
  ],
84
  'detected' => [
85
  'data' => [
86
  '_' => 'detected_since',
87
+ 'sort' => 'created_at',
88
  ],
89
  'title' => __( 'Detected' ),
90
  'className' => 'detected',
91
  'orderable' => true,
92
  'searchable' => false,
93
  'visible' => true,
94
+ 'searchPanes' => [
95
+ 'show' => false
96
+ ],
97
  ],
98
  'actions' => [
99
  'data' => 'actions',
102
  'orderable' => false,
103
  'searchable' => false,
104
  'visible' => true,
105
+ 'searchPanes' => [
106
+ 'show' => false
107
+ ],
108
  ],
109
  'mal_fp_confidence' => [
110
  'data' => 'mal_fp_confidence',
111
  'title' => __( 'False Positive Confidence' ),
112
  'className' => 'mal_fp_confidence',
113
+ 'orderable' => false,
114
  'searchable' => false,
115
  'visible' => true,
116
+ 'searchPanes' => [
117
+ 'show' => false
118
+ ],
119
  ],
120
  'line_numbers' => [
121
  'data' => 'line_numbers',
124
  'orderable' => false,
125
  'searchable' => false,
126
  'visible' => true,
127
+ 'searchPanes' => [
128
+ 'show' => false
129
+ ],
 
 
 
 
 
130
  ],
131
  ];
132
  }
src/lib/src/Tables/DataTables/Build/Scans/ForMalware.php CHANGED
@@ -14,6 +14,7 @@ class ForMalware extends BaseForScan {
14
  'mal_fp_confidence',
15
  'line_numbers',
16
  'mal_sig',
 
17
  'detected',
18
  'actions',
19
  ];
@@ -27,7 +28,7 @@ class ForMalware extends BaseForScan {
27
  'className' => 'mal_fp_confidence',
28
  'orderable' => true,
29
  'searchable' => false,
30
- 'visible' => true,
31
  ];
32
  $colDefs[ 'line_numbers' ] = [
33
  'data' => 'line_numbers',
@@ -35,14 +36,25 @@ class ForMalware extends BaseForScan {
35
  'className' => 'line_numbers',
36
  'orderable' => false,
37
  'searchable' => false,
38
- 'visible' => true,
39
  ];
40
  $colDefs[ 'mal_sig' ] = [
41
  'data' => 'mal_sig',
42
  'title' => __( 'Pattern Detected' ),
43
  'className' => 'mal_sig',
44
  'orderable' => false,
45
- 'searchable' => true,
 
 
 
 
 
 
 
 
 
 
 
46
  'visible' => true,
47
  ];
48
  return $colDefs;
14
  'mal_fp_confidence',
15
  'line_numbers',
16
  'mal_sig',
17
+ 'mal_details',
18
  'detected',
19
  'actions',
20
  ];
28
  'className' => 'mal_fp_confidence',
29
  'orderable' => true,
30
  'searchable' => false,
31
+ 'visible' => false,
32
  ];
33
  $colDefs[ 'line_numbers' ] = [
34
  'data' => 'line_numbers',
36
  'className' => 'line_numbers',
37
  'orderable' => false,
38
  'searchable' => false,
39
+ 'visible' => false,
40
  ];
41
  $colDefs[ 'mal_sig' ] = [
42
  'data' => 'mal_sig',
43
  'title' => __( 'Pattern Detected' ),
44
  'className' => 'mal_sig',
45
  'orderable' => false,
46
+ 'searchable' => false,
47
+ 'visible' => false,
48
+ 'searchPanes' => [
49
+ 'show' => false
50
+ ],
51
+ ];
52
+ $colDefs[ 'mal_details' ] = [
53
+ 'data' => 'mal_details',
54
+ 'title' => __( 'Malware Details' ),
55
+ 'className' => 'mal_details',
56
+ 'orderable' => false,
57
+ 'searchable' => false,
58
  'visible' => true,
59
  ];
60
  return $colDefs;
src/lib/src/Tables/DataTables/LoadData/BaseBuildTableData.php CHANGED
@@ -17,7 +17,7 @@ abstract class BaseBuildTableData extends DynPropertiesClass {
17
 
18
  public function build() :array {
19
  return [
20
- 'data' => $this->loadForLogs(),
21
  'recordsTotal' => $this->countTotalRecords(),
22
  'recordsFiltered' => $this->countTotalRecordsFiltered(),
23
  'searchPanes' => $this->getSearchPanesData(),
@@ -28,22 +28,22 @@ abstract class BaseBuildTableData extends DynPropertiesClass {
28
  return [];
29
  }
30
 
31
- public function loadForLogs() :array {
32
  if ( empty( $this->table_data[ 'search' ][ 'value' ] ) ) {
33
- return $this->loadLogsWithDirectQuery();
34
  }
35
  else {
36
- return $this->loadLogsWithSearch();
37
  }
38
  }
39
 
40
- protected function loadLogsWithDirectQuery() :array {
41
- return $this->buildTableRowsFromRawLogs(
42
  $this->getRecords( $this->buildWheresFromSearchParams(), (int)$this->table_data[ 'start' ], (int)$this->table_data[ 'length' ] )
43
  );
44
  }
45
 
46
- protected function loadLogsWithSearch() :array {
47
  $start = (int)$this->table_data[ 'start' ];
48
  $length = (int)$this->table_data[ 'length' ];
49
  $search = (string)$this->table_data[ 'search' ][ 'value' ] ?? '';
@@ -57,7 +57,7 @@ abstract class BaseBuildTableData extends DynPropertiesClass {
57
  $page = 0;
58
  $pageLength = 100;
59
  do {
60
- $interimResults = $this->buildTableRowsFromRawLogs(
61
  $this->getRecords( $wheres, $page*$pageLength, $pageLength )
62
  );
63
  // no more table results to process, so go with what we have.
@@ -129,7 +129,7 @@ abstract class BaseBuildTableData extends DynPropertiesClass {
129
 
130
  abstract protected function countTotalRecordsFiltered() :int;
131
 
132
- abstract protected function buildTableRowsFromRawLogs( array $records ) :array;
133
 
134
  protected function getColumnContent_Date( int $ts ) :string {
135
  return sprintf( '%s<br /><small>%s</small>',
17
 
18
  public function build() :array {
19
  return [
20
+ 'data' => $this->loadForRecords(),
21
  'recordsTotal' => $this->countTotalRecords(),
22
  'recordsFiltered' => $this->countTotalRecordsFiltered(),
23
  'searchPanes' => $this->getSearchPanesData(),
28
  return [];
29
  }
30
 
31
+ public function loadForRecords() :array {
32
  if ( empty( $this->table_data[ 'search' ][ 'value' ] ) ) {
33
+ return $this->loadRecordsWithDirectQuery();
34
  }
35
  else {
36
+ return $this->loadRecordsWithSearch();
37
  }
38
  }
39
 
40
+ protected function loadRecordsWithDirectQuery() :array {
41
+ return $this->buildTableRowsFromRawRecords(
42
  $this->getRecords( $this->buildWheresFromSearchParams(), (int)$this->table_data[ 'start' ], (int)$this->table_data[ 'length' ] )
43
  );
44
  }
45
 
46
+ protected function loadRecordsWithSearch() :array {
47
  $start = (int)$this->table_data[ 'start' ];
48
  $length = (int)$this->table_data[ 'length' ];
49
  $search = (string)$this->table_data[ 'search' ][ 'value' ] ?? '';
57
  $page = 0;
58
  $pageLength = 100;
59
  do {
60
+ $interimResults = $this->buildTableRowsFromRawRecords(
61
  $this->getRecords( $wheres, $page*$pageLength, $pageLength )
62
  );
63
  // no more table results to process, so go with what we have.
129
 
130
  abstract protected function countTotalRecordsFiltered() :int;
131
 
132
+ abstract protected function buildTableRowsFromRawRecords( array $records ) :array;
133
 
134
  protected function getColumnContent_Date( int $ts ) :string {
135
  return sprintf( '%s<br /><small>%s</small>',
src/lib/src/Tables/Render/WpCliTable/AuditTrail.php CHANGED
@@ -12,7 +12,7 @@ class AuditTrail {
12
  public function render() {
13
  $rows = ( new BuildAuditTableData() )
14
  ->setMod( $this->getMod() )
15
- ->loadForLogs();
16
 
17
  \WP_CLI\Utils\format_items(
18
  'table',
12
  public function render() {
13
  $rows = ( new BuildAuditTableData() )
14
  ->setMod( $this->getMod() )
15
+ ->loadForRecords();
16
 
17
  \WP_CLI\Utils\format_items(
18
  'table',