Shield Security for WordPress - Version 6.4.0

Version Description

  • Current Release = Released: 26th February, 2018 - Release Notes

  • (v.0) ADDED: [PRO] New Scanner to detect file changes for active plugins and themes

  • (v.0) IMPROVED: Automatic updates for vulnerable plugins ignores automatic updates delay setting

  • (v.0) CHANGED: Email notifications for scanners will now link to the Wizard where possible, instead of listing files.

Download this release

Release Info

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

Code changes from version 6.3.3 to 6.4.0

Files changed (68) hide show
  1. icwp-plugin-controller.php +13 -3
  2. icwp-wpsf.php +1 -1
  3. plugin-spec.php +2 -2
  4. readme.txt +19 -9
  5. resources/css/global-plugin.css +3 -8
  6. resources/css/plugin.css +15 -4
  7. resources/css/wizard.css +16 -0
  8. resources/js/global-plugin.js +116 -61
  9. resources/js/plugin.js +60 -1
  10. src/common/icwp-data.php +8 -0
  11. src/common/icwp-foundation.php +3 -3
  12. src/common/icwp-optionsvo.php +85 -10
  13. src/common/icwp-wpfilesystem.php +46 -51
  14. src/common/icwp-wpfunctions-plugins.php +144 -43
  15. src/common/icwp-wpfunctions-themes.php +135 -2
  16. src/common/icwp-wpfunctions.php +43 -7
  17. src/common/icwp-wpupgrades.php +46 -21
  18. src/common/lib/composer.lock +6 -6
  19. src/common/lib/vendor/composer/autoload_classmap.php +441 -0
  20. src/common/lib/vendor/composer/autoload_static.php +445 -0
  21. src/common/lib/vendor/composer/installed.json +61 -61
  22. src/common/lib/vendor/symfony/polyfill-mbstring/Mbstring.php +135 -8
  23. src/common/lib/vendor/symfony/polyfill-mbstring/bootstrap.php +2 -0
  24. src/config/feature-hack_protect.php +127 -0
  25. src/config/feature-lockdown.php +19 -4
  26. src/features/autoupdates.php +1 -1
  27. src/features/base.php +27 -1
  28. src/features/base_wpsf.php +20 -0
  29. src/features/hack_protect.php +274 -4
  30. src/features/lockdown.php +37 -10
  31. src/features/login_protect.php +1 -1
  32. src/processors/autoupdates.php +2 -5
  33. src/processors/comments_filter.php +1 -1
  34. src/processors/email.php +2 -0
  35. src/processors/firewall.php +12 -12
  36. src/processors/hack_protect.php +22 -0
  37. src/processors/hackprotect_corechecksumscan.php +92 -55
  38. src/processors/hackprotect_filecleanerscan.php +75 -45
  39. src/processors/hackprotect_pluginvulnerabilities.php +2 -1
  40. src/processors/hackprotect_ptguard.php +682 -0
  41. src/processors/hackprotect_wpvulnscan.php +3 -2
  42. src/processors/lockdown.php +23 -1
  43. src/processors/loginprotect_googleauthenticator.php +2 -1
  44. src/processors/loginprotect_intent.php +4 -2
  45. src/processors/loginprotect_twofactorauth.php +1 -1
  46. src/processors/loginprotect_wplogin.php +2 -2
  47. src/processors/sessions.php +1 -1
  48. src/processors/usermanagement_sessions.php +1 -1
  49. src/wizards/base.php +13 -17
  50. src/wizards/hack_protect.php +234 -0
  51. templates/php/snippets/hg-plugins-reinstall-dialogs.php +13 -0
  52. templates/php/snippets/module-actions-plugin.php +0 -42
  53. templates/php/snippets/module-help-template.php +1 -1
  54. templates/php/snippets/options_form.php +47 -7
  55. templates/php/snippets/pro.php +1 -1
  56. templates/twig/wizard/slides/common/base.twig +1 -1
  57. templates/twig/wizard/slides/common/no_access.twig +1 -1
  58. templates/twig/wizard/slides/ptg/config.twig +26 -0
  59. templates/twig/wizard/slides/ptg/finished.twig +7 -0
  60. templates/twig/wizard/slides/ptg/scanresult_base.twig +116 -0
  61. templates/twig/wizard/slides/ptg/scanresult_plugins.twig +1 -0
  62. templates/twig/wizard/slides/ptg/scanresult_themes.twig +1 -0
  63. templates/twig/wizard/slides/ptg/start.twig +18 -0
  64. templates/twig/wizard/slides/ufc/exclusions.twig +10 -12
  65. templates/twig/wizard/slides/ufc/scanresult.twig +3 -1
  66. templates/twig/wizard/slides/wcf/scanresult.twig +6 -2
  67. templates/twig/wizard/slides/wcf/start.twig +5 -7
  68. templates/twig/wizard/snippets/wizard_landing.twig +8 -2
icwp-plugin-controller.php CHANGED
@@ -528,12 +528,22 @@ class ICWP_WPSF_Plugin_Controller extends ICWP_WPSF_Foundation {
528
  $sMethod = $aLink[ 'url_method_name' ];
529
  if ( method_exists( $this, $sMethod ) ) {
530
  $sSettingsLink = sprintf( $sLinkTemplate, $this->{$sMethod}(), "_top", $aLink[ 'name' ] );;
531
- array_unshift( $aActionLinks, $sSettingsLink );
 
 
 
 
 
532
  }
533
  }
534
  else if ( !empty( $aLink[ 'href' ] ) ) {
535
- $sSettingsLink = sprintf( $sLinkTemplate, $aLink[ 'href' ], "_blank", $aLink[ 'name' ] );;
536
- array_unshift( $aActionLinks, $sSettingsLink );
 
 
 
 
 
537
  }
538
  }
539
  }
528
  $sMethod = $aLink[ 'url_method_name' ];
529
  if ( method_exists( $this, $sMethod ) ) {
530
  $sSettingsLink = sprintf( $sLinkTemplate, $this->{$sMethod}(), "_top", $aLink[ 'name' ] );;
531
+ $aActionLinks = array_merge(
532
+ array(
533
+ $this->doPluginPrefix( 'dashboard' ) => $sSettingsLink
534
+ ),
535
+ $aActionLinks
536
+ );
537
  }
538
  }
539
  else if ( !empty( $aLink[ 'href' ] ) ) {
540
+ $sSettingsLink = sprintf( $sLinkTemplate, $aLink[ 'href' ], "_blank", $aLink[ 'name' ] );
541
+ $aActionLinks = array_merge(
542
+ array(
543
+ $this->doPluginPrefix( 'dashboard' ) => $sSettingsLink
544
+ ),
545
+ $aActionLinks
546
+ );
547
  }
548
  }
549
  }
icwp-wpsf.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: Shield Security
4
  * Plugin URI: http://icwp.io/2f
5
  * Description: Powerful, Easy-To-Use #1 Rated WordPress Security System
6
- * Version: 6.3.3
7
  * Text Domain: wp-simple-firewall
8
  * Domain Path: /languages/
9
  * Author: iControlWP
3
  * Plugin Name: Shield Security
4
  * Plugin URI: http://icwp.io/2f
5
  * Description: Powerful, Easy-To-Use #1 Rated WordPress Security System
6
+ * Version: 6.4.0
7
  * Text Domain: wp-simple-firewall
8
  * Domain Path: /languages/
9
  * Author: iControlWP
plugin-spec.php CHANGED
@@ -1,7 +1,7 @@
1
  {
2
  "properties": {
3
- "version": "6.3.3",
4
- "release_timestamp": 1519214400,
5
  "slug_parent": "icwp",
6
  "slug_plugin": "wpsf",
7
  "human_name": "Shield",
1
  {
2
  "properties": {
3
+ "version": "6.4.0",
4
+ "release_timestamp": 1519646400,
5
  "slug_parent": "icwp",
6
  "slug_plugin": "wpsf",
7
  "human_name": "Shield",
readme.txt CHANGED
@@ -6,7 +6,7 @@ License URI: http://www.gnu.org/licenses/gpl.html
6
  Tags: security, all in one, protect, spam, scan, recaptcha, two-factor authentication, login, 2FA, ithemes, wordfence, better wp security, all-in-one, lockdown, hack
7
  Requires at least: 3.5.0
8
  Tested up to: 4.9
9
- Stable tag: 6.3.3
10
 
11
  Free All-In-One Protection for your WordPress sites, data, reputation, and users. Shield: the Highest-Rated Security Plugin for WordPress
12
 
@@ -78,7 +78,7 @@ downloading and installing Shield now
78
 
79
  = What makes the Shield different? =
80
 
81
- * No "Pro" restrictions on security features - where possible, anything pertaining directly to site security is free.
82
  * Easy-To-Setup User Interface.
83
  * It won't break your website - you'll never get that horrible,
84
  pit-of-your stomach feeling you get with other security plugins when your website doesn't load anymore.
@@ -349,18 +349,28 @@ Possible options are: network_admin, administrator, editor, author, contributor,
349
 
350
  == Changelog ==
351
 
352
- Our policy is to never restrict security features to Pro upgrades. **This has not changed**.
353
 
354
  We're now offering technical support and other features exclusively to premium customers.
355
- If you don't want to support the work, no problem! You can still continue to use Shield Security and its features in-full.
356
- Technical support, and some newer options and features will not be available to you, however.
357
 
358
- You can [go Pro for just $1/month](http://icwp.io/aa). Technical support is available to premium clients only.
 
359
 
360
- = 6.3.3 - Current Release =
361
- *Released: 21st February, 2018* - [Release Notes](http://icwp.io/bc)
362
 
363
- * **(v.3)** FIXED: Bug with automatic updates delay processing
 
 
 
 
 
 
 
 
 
364
 
365
  = 6.3 Series =
366
  *Released: 12th February, 2018* - [Release Notes](http://icwp.io/bc)
6
  Tags: security, all in one, protect, spam, scan, recaptcha, two-factor authentication, login, 2FA, ithemes, wordfence, better wp security, all-in-one, lockdown, hack
7
  Requires at least: 3.5.0
8
  Tested up to: 4.9
9
+ Stable tag: 6.4.0
10
 
11
  Free All-In-One Protection for your WordPress sites, data, reputation, and users. Shield: the Highest-Rated Security Plugin for WordPress
12
 
78
 
79
  = What makes the Shield different? =
80
 
81
+ * Powerful free security protection.
82
  * Easy-To-Setup User Interface.
83
  * It won't break your website - you'll never get that horrible,
84
  pit-of-your stomach feeling you get with other security plugins when your website doesn't load anymore.
349
 
350
  == Changelog ==
351
 
352
+ Our policy was to never restrict security features to Pro upgrades. [This has now changed](http://icwp.io/bs).
353
 
354
  We're now offering technical support and other features exclusively to premium customers.
355
+ If you don't want to support the work, no problem! You can still continue to use Shield Security and its free features in-full.
356
+ Technical support, and some newer features will not be available to you, however.
357
 
358
+ You can [go Pro for just $1/month](http://icwp.io/aa).
359
+ Technical support is available to premium clients only.
360
 
361
+ = 6.4.0 - Current Release =
362
+ *Released: 26th February, 2018* - [Release Notes](http://icwp.io/br)
363
 
364
+ * **(v.0)** ADDED: [**PRO**] New Scanner to [detect file changes for active plugins and themes](http://icwp.io/bq)
365
+ * **(v.0)** IMPROVED: Automatic updates for vulnerable plugins ignores [automatic updates delay setting](http://icwp.io/bc)
366
+ * **(v.0)** CHANGED: Email notifications for scanners will now link to the Wizard where possible, instead of listing files.
367
+
368
+ = 6.4 Series =
369
+ *Released: 26th February, 2018* - [Release Notes](http://icwp.io/br)
370
+
371
+ * **(v.0)** ADDED: [**PRO**] New Scanner to [detect file changes for active plugins and themes](http://icwp.io/bq)
372
+ * **(v.0)** IMPROVED: Automatic updates for vulnerable plugins ignores [automatic updates delay setting](http://icwp.io/bc)
373
+ * **(v.0)** CHANGED: Email notifications for scanners will now link to the Wizard where possible, instead of listing files.
374
 
375
  = 6.3 Series =
376
  *Released: 12th February, 2018* - [Release Notes](http://icwp.io/bc)
resources/css/global-plugin.css CHANGED
@@ -28,7 +28,6 @@
28
  color: rgb(103, 21, 0);
29
  text-align: right;
30
  }
31
-
32
  .notice-icon {
33
  display: none;
34
  float: left;
@@ -46,7 +45,6 @@
46
  .notice-content p {
47
  margin-left: 0;
48
  }
49
-
50
  @media (min-width: 884px) {
51
  .notice-icon {
52
  display: block;
@@ -55,7 +53,6 @@
55
  margin-left: 62px;
56
  }
57
  }
58
-
59
  .notice-icon-right {
60
  float: right;
61
  width: 74px;
@@ -71,11 +68,6 @@
71
  text-shadow: none;
72
  font-weight: bold;
73
  }
74
-
75
-
76
-
77
-
78
-
79
  ul.nav-tabs li a {
80
  color: rgba(69, 119, 0, 1);
81
  }
@@ -329,4 +321,7 @@ tr.icwp-plugin-vulnerability dd {
329
  }
330
  .icwpAjaxTableContainer table th.column-event {
331
  width: 110px;
 
 
 
332
  }
28
  color: rgb(103, 21, 0);
29
  text-align: right;
30
  }
 
31
  .notice-icon {
32
  display: none;
33
  float: left;
45
  .notice-content p {
46
  margin-left: 0;
47
  }
 
48
  @media (min-width: 884px) {
49
  .notice-icon {
50
  display: block;
53
  margin-left: 62px;
54
  }
55
  }
 
56
  .notice-icon-right {
57
  float: right;
58
  width: 74px;
68
  text-shadow: none;
69
  font-weight: bold;
70
  }
 
 
 
 
 
71
  ul.nav-tabs li a {
72
  color: rgba(69, 119, 0, 1);
73
  }
321
  }
322
  .icwpAjaxTableContainer table th.column-event {
323
  width: 110px;
324
+ }
325
+ .icwp-wpsf-dialog h3 {
326
+ margin-top: 0;
327
  }
resources/css/plugin.css CHANGED
@@ -177,11 +177,9 @@ p.code-description {
177
  margin: 10px 20px 20px;
178
  }
179
  .row_section_summary div {
180
- margin: 0;
181
- padding: 0 20px 0 2px;
182
  }
183
  .row_section_summary p {
184
- margin: 12px 20px;
185
  }
186
  .row_section_summary p.noselect {
187
  -webkit-touch-callout: none;
@@ -190,6 +188,19 @@ p.code-description {
190
  -ms-user-select: none;
191
  user-select: none;
192
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  /** End-Section summaries **/
194
 
195
  .wrap .icon32 {
@@ -710,7 +721,7 @@ input:checked + .icwp-slider:before {
710
  color: #a56300;
711
  }
712
  .modules a.module .dashicons-yes {
713
- color: #bdbdbd;
714
  }
715
  .modules a.module .dashicons-warning:before {
716
  font-size: 16px !important;
177
  margin: 10px 20px 20px;
178
  }
179
  .row_section_summary div {
 
 
180
  }
181
  .row_section_summary p {
182
+ margin: 12px 0;
183
  }
184
  .row_section_summary p.noselect {
185
  -webkit-touch-callout: none;
188
  -ms-user-select: none;
189
  user-select: none;
190
  }
191
+
192
+ .row_section_summary button.section_help_video {
193
+ position:relative;
194
+ top:25%;
195
+ }
196
+ .row_section_summary button.section_help_video .dashicons {
197
+ font-size: 33px;
198
+ width: 30px;
199
+ }
200
+ .row_section_summary .section_video > div {
201
+ box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
202
+ margin-bottom: 20px;
203
+ }
204
  /** End-Section summaries **/
205
 
206
  .wrap .icon32 {
721
  color: #a56300;
722
  }
723
  .modules a.module .dashicons-yes {
724
+ color: #69ab72;
725
  }
726
  .modules a.module .dashicons-warning:before {
727
  font-size: 16px !important;
resources/css/wizard.css CHANGED
@@ -97,6 +97,9 @@ body.wait {
97
  .wizard form .form-check-label {
98
  margin-bottom: 10px;
99
  }
 
 
 
100
 
101
  #GoProBtn {
102
  width: 128px;
@@ -138,4 +141,17 @@ body.wait {
138
  }
139
  .more_details_body {
140
  margin-bottom: 12px;
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  }
97
  .wizard form .form-check-label {
98
  margin-bottom: 10px;
99
  }
100
+ .wizard form .form-check-inline .form-check-label {
101
+ margin-bottom: 0;
102
+ }
103
 
104
  #GoProBtn {
105
  width: 128px;
141
  }
142
  .more_details_body {
143
  margin-bottom: 12px;
144
+ }
145
+
146
+ .scan-results-accordian {
147
+ }
148
+ .scan-results-accordian .card {
149
+ margin-bottom: 24px;
150
+ }
151
+ .scan-results-accordian .card-header {
152
+ padding: .5rem 1.25rem;
153
+ }
154
+ .scan-results-accordian .card-header button:hover,
155
+ .scan-results-accordian .card-header button {
156
+ color: #f1f1f1
157
  }
resources/js/global-plugin.js CHANGED
@@ -28,6 +28,115 @@ var iCWP_WPSF_SecurityAdmin = new function () {
28
  };
29
  }();
30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  var iCWP_WPSF_Autoupdates = new function () {
32
 
33
  var bRequestCurrentlyRunning = false;
@@ -76,64 +185,6 @@ var iCWP_WPSF_Autoupdates = new function () {
76
 
77
  }();
78
 
79
- var iCWP_WPSF_OptionsFormSubmit = new function () {
80
-
81
- var bRequestCurrentlyRunning = false;
82
-
83
- this.submit = function ( sMessage, bSuccess ) {
84
- var $oDiv = createDynDiv( bSuccess ? 'success' : 'failed' );
85
- $oDiv.fadeIn().html( sMessage );
86
- setTimeout( function () {
87
- $oDiv.fadeOut( 5000 );
88
- $oDiv.remove();
89
- }, 4000 );
90
- };
91
-
92
- /**
93
- */
94
- var submitOptionsForm = function ( event ) {
95
- iCWP_WPSF_BodyOverlay.show();
96
-
97
- if ( bRequestCurrentlyRunning ) {
98
- return false;
99
- }
100
-
101
- bRequestCurrentlyRunning = true;
102
-
103
- event.preventDefault();
104
-
105
- var $oForm = jQuery( this );
106
- jQuery( '<input />' ).attr( 'type', 'hidden' )
107
- .attr( 'name', 'action' )
108
- .attr( 'value', 'icwp_OptionsFormSave' )
109
- .appendTo( $oForm );
110
-
111
- jQuery.post( ajaxurl, $oForm.serialize(),
112
- function ( oResponse ) {
113
- var sMessage;
114
- if ( oResponse.data.message === undefined ) {
115
- sMessage = oResponse.success ? 'Success' : 'Failure';
116
- }
117
- else {
118
- sMessage = oResponse.data.message;
119
- }
120
- jQuery( 'div#icwpOptionsFormContainer' ).html( oResponse.data.options_form )
121
- iCWP_WPSF_Growl.showMessage( sMessage, oResponse.success );
122
- }
123
- ).always( function () {
124
- bRequestCurrentlyRunning = false;
125
- iCWP_WPSF_BodyOverlay.hide();
126
- }
127
- );
128
- };
129
-
130
- this.initialise = function () {
131
- jQuery( document ).ready( function () {
132
- jQuery( document ).on( "submit", "form.icwpOptionsForm", submitOptionsForm );
133
- } );
134
- };
135
- }();
136
-
137
  var iCWP_WPSF_Growl = new function () {
138
 
139
  this.showMessage = function ( sMessage, bSuccess ) {
@@ -183,7 +234,11 @@ var iCWP_WPSF_BodyOverlay = new function () {
183
 
184
  }();
185
 
186
- iCWP_WPSF_Autoupdates.initialise();
187
- iCWP_WPSF_OptionsFormSubmit.initialise();
188
  iCWP_WPSF_BodyOverlay.initialise();
189
- iCWP_WPSF_SecurityAdmin.initialise();
 
 
 
 
 
28
  };
29
  }();
30
 
31
+ var iCWP_WPSF_HackGuard_Reinstall = new function () {
32
+
33
+ var sActiveFile;
34
+ var bActivate;
35
+
36
+ this.initialise = function () {
37
+ jQuery( document ).ready( function () {
38
+
39
+ var $oTr;
40
+ jQuery( 'table.wp-list-table.plugins > tbody > tr' ).each( function ( nIndex ) {
41
+ $oTr = jQuery( this );
42
+ if ( $oTr.data( 'plugin' ) !== undefined
43
+ && icwp_wpsf_vars_hp.reinstallable.indexOf( $oTr.data( 'plugin' ) ) >= 0 ) {
44
+ $oTr.addClass( 'reinstallable' );
45
+ }
46
+ } );
47
+
48
+ jQuery( document ).on( "click", 'tr.reinstallable .row-actions .icwp-reinstall a', promptReinstall );
49
+ jQuery( document ).on( "click", 'tr.reinstallable .row-actions .activate a', promptActivate );
50
+
51
+ var oShareSettings = {
52
+ title: 'Re-Install Plugin',
53
+ dialogClass: 'wp-dialog',
54
+ autoOpen: false,
55
+ draggable: false,
56
+ width: 'auto',
57
+ modal: true,
58
+ resizable: false,
59
+ closeOnEscape: true,
60
+ position: {
61
+ my: "center",
62
+ at: "center",
63
+ of: window
64
+ },
65
+ open: function () {
66
+ // close dialog by clicking the overlay behind it
67
+ jQuery( '.ui-widget-overlay' ).bind( 'click', function () {
68
+ jQuery( this ).dialog( 'close' );
69
+ } )
70
+ },
71
+ create: function () {
72
+ // style fix for WordPress admin
73
+ jQuery( '.ui-dialog-titlebar-close' ).addClass( 'ui-button' );
74
+ }
75
+ };
76
+
77
+ var $oReinstallDialog = jQuery( '#icwpWpsfReinstall' );
78
+ oShareSettings[ 'buttons' ] = {
79
+ "Okay, Re-Install It": function () {
80
+ jQuery( this ).dialog( "close" );
81
+ reinstall_plugin( 1 );
82
+ },
83
+ "Cancel": function () {
84
+ jQuery( this ).dialog( "close" );
85
+ }
86
+ };
87
+ $oReinstallDialog.dialog( oShareSettings );
88
+
89
+ var $oActivateReinstallDialog = jQuery( '#icwpWpsfActivateReinstall' );
90
+ oShareSettings[ 'buttons' ] = {
91
+ "Re-Install First, Then Activate": function () {
92
+ jQuery( this ).dialog( "close" );
93
+ reinstall_plugin( 1 );
94
+ },
95
+ "Activate Only": function () {
96
+ jQuery( this ).dialog( "close" );
97
+ reinstall_plugin( 0 );
98
+ }
99
+ };
100
+ $oActivateReinstallDialog.dialog( oShareSettings );
101
+ } );
102
+ };
103
+
104
+ var promptReinstall = function ( event ) {
105
+ event.preventDefault();
106
+ bActivate = 0;
107
+ sActiveFile = jQuery( event.target ).closest( 'tr' ).data( 'plugin' );
108
+ jQuery( '#icwpWpsfReinstall' ).dialog( 'open' );
109
+ return false;
110
+ };
111
+
112
+ var promptActivate = function ( event ) {
113
+ event.preventDefault();
114
+ bActivate = 1;
115
+ sActiveFile = jQuery( event.target ).closest( 'tr' ).data( 'plugin' );
116
+ jQuery( '#icwpWpsfActivateReinstall' ).dialog( 'open' );
117
+ return false;
118
+ };
119
+
120
+ var reinstall_plugin = function ( bReinstall ) {
121
+ iCWP_WPSF_BodyOverlay.show();
122
+
123
+ var $aData = icwp_wpsf_vars_hp.ajax_reinstall;
124
+ $aData[ 'file' ] = sActiveFile;
125
+ $aData[ 'reinstall' ] = bReinstall;
126
+ $aData[ 'activate' ] = bActivate;
127
+
128
+ jQuery.post( ajaxurl, $aData, function ( oResponse ) {
129
+
130
+ } ).always( function () {
131
+ location.reload( true );
132
+ bActivate = null;
133
+ }
134
+ );
135
+
136
+ return false;
137
+ };
138
+ }();
139
+
140
  var iCWP_WPSF_Autoupdates = new function () {
141
 
142
  var bRequestCurrentlyRunning = false;
185
 
186
  }();
187
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  var iCWP_WPSF_Growl = new function () {
189
 
190
  this.showMessage = function ( sMessage, bSuccess ) {
234
 
235
  }();
236
 
237
+ // iCWP_WPSF_Autoupdates.initialise();
 
238
  iCWP_WPSF_BodyOverlay.initialise();
239
+ iCWP_WPSF_SecurityAdmin.initialise();
240
+
241
+ /** only run when HackGuard module is processing enqueues **/
242
+ if ( typeof icwp_wpsf_vars_hp !== 'undefined' ) {
243
+ iCWP_WPSF_HackGuard_Reinstall.initialise();
244
+ }
resources/js/plugin.js CHANGED
@@ -36,4 +36,63 @@ var iCWP_WPSF_OptionsPages = new function () {
36
 
37
  }();
38
 
39
- iCWP_WPSF_OptionsPages.initialise();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
  }();
38
 
39
+ var iCWP_WPSF_OptionsFormSubmit = new function () {
40
+
41
+ var bRequestCurrentlyRunning = false;
42
+
43
+ this.submit = function ( sMessage, bSuccess ) {
44
+ var $oDiv = createDynDiv( bSuccess ? 'success' : 'failed' );
45
+ $oDiv.fadeIn().html( sMessage );
46
+ setTimeout( function () {
47
+ $oDiv.fadeOut( 5000 );
48
+ $oDiv.remove();
49
+ }, 4000 );
50
+ };
51
+
52
+ /**
53
+ */
54
+ var submitOptionsForm = function ( event ) {
55
+ iCWP_WPSF_BodyOverlay.show();
56
+
57
+ if ( bRequestCurrentlyRunning ) {
58
+ return false;
59
+ }
60
+
61
+ bRequestCurrentlyRunning = true;
62
+
63
+ event.preventDefault();
64
+
65
+ var $oForm = jQuery( this );
66
+ jQuery( '<input />' ).attr( 'type', 'hidden' )
67
+ .attr( 'name', 'action' )
68
+ .attr( 'value', 'icwp_OptionsFormSave' )
69
+ .appendTo( $oForm );
70
+
71
+ jQuery.post( ajaxurl, $oForm.serialize(),
72
+ function ( oResponse ) {
73
+ var sMessage;
74
+ if ( oResponse.data.message === undefined ) {
75
+ sMessage = oResponse.success ? 'Success' : 'Failure';
76
+ }
77
+ else {
78
+ sMessage = oResponse.data.message;
79
+ }
80
+ jQuery( 'div#icwpOptionsFormContainer' ).html( oResponse.data.options_form )
81
+ iCWP_WPSF_Growl.showMessage( sMessage, oResponse.success );
82
+ }
83
+ ).always( function () {
84
+ bRequestCurrentlyRunning = false;
85
+ iCWP_WPSF_BodyOverlay.hide();
86
+ }
87
+ );
88
+ };
89
+
90
+ this.initialise = function () {
91
+ jQuery( document ).ready( function () {
92
+ jQuery( document ).on( "submit", "form.icwpOptionsForm", submitOptionsForm );
93
+ } );
94
+ };
95
+ }();
96
+
97
+ iCWP_WPSF_OptionsPages.initialise();
98
+ iCWP_WPSF_OptionsFormSubmit.initialise();
src/common/icwp-data.php CHANGED
@@ -179,6 +179,13 @@ class ICWP_WPSF_DataProcessor extends ICWP_WPSF_Foundation {
179
  return ( $nLastPeriod === false ) ? $sPath : str_replace( '.', '', substr( $sPath, $nLastPeriod ) );
180
  }
181
 
 
 
 
 
 
 
 
182
  /**
183
  * @param string $sUrl
184
  * @return string
@@ -388,6 +395,7 @@ class ICWP_WPSF_DataProcessor extends ICWP_WPSF_Foundation {
388
  }
389
 
390
  /**
 
391
  * @param string $sKey
392
  * @param mixed $mDefault
393
  * @return mixed|null
179
  return ( $nLastPeriod === false ) ? $sPath : str_replace( '.', '', substr( $sPath, $nLastPeriod ) );
180
  }
181
 
182
+ /**
183
+ * @return bool
184
+ */
185
+ public function isWindows() {
186
+ return strtoupper( substr( PHP_OS, 0, 3 ) ) === 'WIN';
187
+ }
188
+
189
  /**
190
  * @param string $sUrl
191
  * @return string
395
  }
396
 
397
  /**
398
+ * @deprecated
399
  * @param string $sKey
400
  * @param mixed $mDefault
401
  * @return mixed|null
src/common/icwp-foundation.php CHANGED
@@ -74,7 +74,7 @@ class ICWP_WPSF_Foundation {
74
  */
75
  private static $oEdd;
76
  /**
77
- * @var ICWP_APP_WpUpgrades
78
  */
79
  private static $oUpgrades;
80
 
@@ -154,12 +154,12 @@ class ICWP_WPSF_Foundation {
154
  }
155
 
156
  /**
157
- * @return ICWP_APP_WpUpgrades
158
  */
159
  static public function loadWpUpgrades() {
160
  if ( ! isset( self::$oUpgrades ) ) {
161
  self::requireCommonLib( 'icwp-wpupgrades.php' );
162
- self::$oUpgrades = ICWP_APP_WpUpgrades::GetInstance();
163
  }
164
 
165
  return self::$oUpgrades;
74
  */
75
  private static $oEdd;
76
  /**
77
+ * @var ICWP_WPSF_WpUpgrades
78
  */
79
  private static $oUpgrades;
80
 
154
  }
155
 
156
  /**
157
+ * @return ICWP_WPSF_WpUpgrades
158
  */
159
  static public function loadWpUpgrades() {
160
  if ( ! isset( self::$oUpgrades ) ) {
161
  self::requireCommonLib( 'icwp-wpupgrades.php' );
162
+ self::$oUpgrades = ICWP_WPSF_WpUpgrades::GetInstance();
163
  }
164
 
165
  return self::$oUpgrades;
src/common/icwp-optionsvo.php CHANGED
@@ -233,7 +233,16 @@ class ICWP_WPSF_OptionsVO extends ICWP_WPSF_Foundation {
233
  }
234
 
235
  /**
236
- * @return array
 
 
 
 
 
 
 
 
 
237
  */
238
  public function getSections() {
239
  $aSections = array();
@@ -245,6 +254,48 @@ class ICWP_WPSF_OptionsVO extends ICWP_WPSF_Foundation {
245
  return $aSections;
246
  }
247
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
248
  /**
249
  * @return array
250
  */
@@ -645,32 +696,56 @@ class ICWP_WPSF_OptionsVO extends ICWP_WPSF_Foundation {
645
  }
646
 
647
  /**
648
- * @param string $sOptionKey
649
  * @param mixed $mValue
650
  * @return mixed
651
  */
652
- public function setOpt( $sOptionKey, $mValue ) {
653
 
654
  // We can't use getOpt() to find the current value since we'll create an infinite loop
655
  $aOptionsValues = $this->getAllOptionsValues();
656
- $mCurrent = isset( $aOptionsValues[ $sOptionKey ] ) ? $aOptionsValues[ $sOptionKey ] : null;
657
 
658
- if ( serialize( $mCurrent ) !== serialize( $mValue ) ) {
659
  $this->setNeedSave( true );
660
 
661
  //Load the config and do some pre-set verification where possible. This will slowly grow.
662
- $aOption = $this->getRawData_SingleOption( $sOptionKey );
663
  if ( !empty( $aOption[ 'type' ] ) ) {
664
  if ( $aOption[ 'type' ] == 'boolean' && !is_bool( $mValue ) ) {
665
- return $this->resetOptToDefault( $sOptionKey );
666
  }
667
  }
668
- $this->setOldOptValue( $sOptionKey, $mCurrent );
669
- $this->aOptionsValues[ $sOptionKey ] = $mValue;
670
  }
671
  return true;
672
  }
673
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
674
  /**
675
  * @param string $sOptionKey
676
  * @param mixed $mValue
@@ -757,7 +832,7 @@ class ICWP_WPSF_OptionsVO extends ICWP_WPSF_Foundation {
757
  if ( !isset( $aConfig[ 'meta_modts' ] ) ) {
758
  $aConfig[ 'meta_modts' ] = 0;
759
  }
760
- $bRebuild = $this->getConfigModTime() > $aConfig[ 'meta_modts' ];
761
  }
762
 
763
  if ( $bRebuild ) {
233
  }
234
 
235
  /**
236
+ * @param string $sSlug
237
+ * @return array|null
238
+ */
239
+ public function getSection( $sSlug ) {
240
+ $aSections = $this->getSections();
241
+ return isset( $aSections[ $sSlug ] ) ? $aSections[ $sSlug ] : null;
242
+ }
243
+
244
+ /**
245
+ * @return array[]
246
  */
247
  public function getSections() {
248
  $aSections = array();
254
  return $aSections;
255
  }
256
 
257
+ /**
258
+ * @param string $sSlug
259
+ * @return array
260
+ */
261
+ public function getSection_Requirements( $sSlug ) {
262
+ $aSection = $this->getSection( $sSlug );
263
+ $aReqs = ( is_array( $aSection ) && isset( $aSection[ 'reqs' ] ) ) ? $aSection[ 'reqs' ] : array();
264
+ return array_merge(
265
+ array(
266
+ 'php_min' => '5.2.4'
267
+ ),
268
+ $aReqs
269
+ );
270
+ }
271
+
272
+ /**
273
+ * @param string $sSlug
274
+ * @return array|null
275
+ */
276
+ public function getSectionHelpVideo( $sSlug ) {
277
+ $aSection = $this->getSection( $sSlug );
278
+ return ( is_array( $aSection ) && isset( $aSection[ 'help_video' ] ) ) ? $aSection[ 'help_video' ] : null;
279
+ }
280
+
281
+ /**
282
+ * @param string $sSectionSlug
283
+ * @return bool
284
+ */
285
+ public function isSectionReqsMet( $sSectionSlug ) {
286
+ $aReqs = $this->getSection_Requirements( $sSectionSlug );
287
+ $bMet = $this->loadDP()->getPhpVersionIsAtLeast( $aReqs[ 'php_min' ] );
288
+ return $bMet;
289
+ }
290
+
291
+ /**
292
+ * @param string $sOptKey
293
+ * @return bool
294
+ */
295
+ public function isOptReqsMet( $sOptKey ) {
296
+ return $this->isSectionReqsMet( $this->getOptProperty( $sOptKey, 'section' ) );
297
+ }
298
+
299
  /**
300
  * @return array
301
  */
696
  }
697
 
698
  /**
699
+ * @param string $sOptKey
700
  * @param mixed $mValue
701
  * @return mixed
702
  */
703
+ public function setOpt( $sOptKey, $mValue ) {
704
 
705
  // We can't use getOpt() to find the current value since we'll create an infinite loop
706
  $aOptionsValues = $this->getAllOptionsValues();
707
+ $mCurrent = isset( $aOptionsValues[ $sOptKey ] ) ? $aOptionsValues[ $sOptKey ] : null;
708
 
709
+ if ( serialize( $mCurrent ) !== serialize( $mValue ) && $this->verifySet( $sOptKey, $mValue ) ) {
710
  $this->setNeedSave( true );
711
 
712
  //Load the config and do some pre-set verification where possible. This will slowly grow.
713
+ $aOption = $this->getRawData_SingleOption( $sOptKey );
714
  if ( !empty( $aOption[ 'type' ] ) ) {
715
  if ( $aOption[ 'type' ] == 'boolean' && !is_bool( $mValue ) ) {
716
+ return $this->resetOptToDefault( $sOptKey );
717
  }
718
  }
719
+ $this->setOldOptValue( $sOptKey, $mCurrent );
720
+ $this->aOptionsValues[ $sOptKey ] = $mValue;
721
  }
722
  return true;
723
  }
724
 
725
+ /**
726
+ * @param string $sOptKey
727
+ * @param mixed $mValue
728
+ * @return bool
729
+ */
730
+ protected function verifySet( $sOptKey, $mValue ) {
731
+ $bValid = true;
732
+
733
+ switch ( $this->getOptionType( $sOptKey ) ) {
734
+
735
+ case 'integer':
736
+ $nMin = $this->getOptProperty( $sOptKey, 'min' );
737
+ if ( !is_null( $nMin ) ) {
738
+ $bValid = $mValue >= $nMin;
739
+ }
740
+ $nMax = $this->getOptProperty( $sOptKey, 'max' );
741
+ if ( !is_null( $nMax ) ) {
742
+ $bValid = $mValue <= $nMax;
743
+ }
744
+ break;
745
+ }
746
+ return $bValid;
747
+ }
748
+
749
  /**
750
  * @param string $sOptionKey
751
  * @param mixed $mValue
832
  if ( !isset( $aConfig[ 'meta_modts' ] ) ) {
833
  $aConfig[ 'meta_modts' ] = 0;
834
  }
835
+ $bRebuild = $this->getConfigModTime() != $aConfig[ 'meta_modts' ];
836
  }
837
 
838
  if ( $bRebuild ) {
src/common/icwp-wpfilesystem.php CHANGED
@@ -67,69 +67,64 @@ class ICWP_WPSF_WpFilesystem {
67
  $sNeedle = strtolower( $sNeedle );
68
  }
69
 
70
- $oDirIt = null;
71
- $bUseDirectoryIterator = class_exists( 'DirectoryIterator', false );
72
- if ( $bUseDirectoryIterator ) {
73
- try {
74
- $oDirIt = new DirectoryIterator( $sDir );
75
- }
76
- catch ( Exception $oE ) { // UnexpectedValueException, RuntimeException, Exception
77
- $bUseDirectoryIterator = false; // Path doesn't exist or don't have access to open
78
- }
79
- }
80
-
81
- if ( $bUseDirectoryIterator && $oDirIt ) {
82
 
83
- //if the file you're searching for doesn't have an extension, then we don't include extensions in search
84
- $nDotPosition = strpos( $sNeedle, '.' );
85
- $bHasExtension = $nDotPosition !== false;
86
- $bIncludeExtension = $bIncludeExtension && $bHasExtension;
87
 
88
- $sNeedlePreExtension = $bHasExtension ? substr( $sNeedle, 0, $nDotPosition ) : $sNeedle;
89
-
90
- $bFound = false;
91
- foreach ( $oDirIt as $oFileItem ) {
92
- if ( !$oFileItem->isFile() ) {
93
- continue;
94
- }
95
- $sFilename = $oFileItem->getFilename();
96
- if ( !$bCaseSensitive ) {
97
- $sFilename = strtolower( $sFilename );
98
- }
99
 
100
- if ( $bIncludeExtension ) {
101
- $bFound = ( $sFilename == $sNeedle );
102
- }
103
- else {
104
- // This is not entirely accurate as it only finds whether a file "starts" with needle, ignoring subsequent characters
105
- $bFound = ( strpos( $sFilename, $sNeedlePreExtension ) === 0 );
106
- }
107
 
108
- if ( $bFound ) {
109
- break;
110
- }
 
 
 
111
  }
112
 
113
- return $bFound;
 
 
114
  }
115
 
116
- if ( $bCaseSensitive ) {
117
- return $this->exists( $this->pathJoin( $sDir, $sNeedle ) );
118
- }
119
- $sNeedle = strtolower( $sNeedle );
120
- if ( $oHandle = opendir( $sDir ) ) {
121
 
122
- while ( false !== ( $sFileEntry = readdir( $oHandle ) ) ) {
123
- if ( !$this->isFile( $this->pathJoin( $sDir, $sFileEntry ) ) ) {
124
- continue;
125
- }
126
- if ( $sNeedle == strtolower( $sFileEntry ) ) {
127
- return true;
128
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  }
130
  }
 
 
131
 
132
- return false;
133
  }
134
 
135
  /**
67
  $sNeedle = strtolower( $sNeedle );
68
  }
69
 
70
+ //if the file you're searching for doesn't have an extension, then we don't include extensions in search
71
+ $nDotPosition = strpos( $sNeedle, '.' );
72
+ $bHasExtension = $nDotPosition !== false;
73
+ $bIncludeExtension = $bIncludeExtension && $bHasExtension;
 
 
 
 
 
 
 
 
74
 
75
+ $sNeedlePreExtension = $bHasExtension ? substr( $sNeedle, 0, $nDotPosition ) : $sNeedle;
 
 
 
76
 
77
+ $bFound = false;
78
+ foreach ( $this->getFilesInDir( $sDir ) as $oFileItem ) {
 
 
 
 
 
 
 
 
 
79
 
80
+ $sFilename = $oFileItem->getFilename();
81
+ if ( !$bCaseSensitive ) {
82
+ $sFilename = strtolower( $sFilename );
83
+ }
 
 
 
84
 
85
+ if ( $bIncludeExtension ) {
86
+ $bFound = ( $sFilename == $sNeedle );
87
+ }
88
+ else {
89
+ // This is not entirely accurate as it only finds whether a file "starts" with needle, ignoring subsequent characters
90
+ $bFound = ( strpos( $sFilename, $sNeedlePreExtension ) === 0 );
91
  }
92
 
93
+ if ( $bFound ) {
94
+ break;
95
+ }
96
  }
97
 
98
+ return $bFound;
99
+ }
 
 
 
100
 
101
+ /**
102
+ * @param string $sDir
103
+ * @param int $nMaxDepth - set to zero for no max
104
+ * @param RecursiveDirectoryIterator $oDirIterator
105
+ * @return SplFileInfo[]
106
+ */
107
+ public function getFilesInDir( $sDir, $nMaxDepth = 1, $oDirIterator = null ) {
108
+ $aList = array();
109
+
110
+ try {
111
+ if ( empty( $oDirIterator ) ) {
112
+ $oDirIterator = new RecursiveDirectoryIterator( $sDir );
113
+ $oDirIterator->setFlags( RecursiveDirectoryIterator::SKIP_DOTS );
114
+ }
115
+
116
+ $oRecurIter = new RecursiveIteratorIterator( $oDirIterator );
117
+ $oRecurIter->setMaxDepth( $nMaxDepth - 1 ); //since they start at zero.
118
+
119
+ /** @var SplFileInfo $oFile */
120
+ foreach ( $oRecurIter as $oFile ) {
121
+ $aList[] = clone $oFile;
122
  }
123
  }
124
+ catch ( Exception $oE ) { // UnexpectedValueException, RuntimeException, Exception
125
+ }
126
 
127
+ return $aList;
128
  }
129
 
130
  /**
src/common/icwp-wpfunctions-plugins.php CHANGED
@@ -33,6 +33,15 @@ class ICWP_WPSF_WpFunctions_Plugins extends ICWP_WPSF_Foundation {
33
  return activate_plugin( $sPluginFile, '', $bNetworkWide );
34
  }
35
 
 
 
 
 
 
 
 
 
 
36
  /**
37
  * @param string $sPluginFile
38
  * @param bool $bNetworkWide
@@ -44,22 +53,30 @@ class ICWP_WPSF_WpFunctions_Plugins extends ICWP_WPSF_Foundation {
44
  /**
45
  * @param string $sPluginFile
46
  * @param bool $bNetworkWide
 
 
 
 
 
 
 
 
47
  * @return bool
48
  */
49
- public function delete( $sPluginFile, $bNetworkWide = false ) {
50
- if ( !$this->isPluginInstalled( $sPluginFile ) ) {
51
  return false;
52
  }
53
 
54
- if ( $this->isPluginActive( $sPluginFile ) ) {
55
- $this->deactivate( $sPluginFile, $bNetworkWide );
56
  }
57
- $this->uninstall( $sPluginFile );
58
 
59
  // delete the folder
60
- $sPluginDir = dirname( $sPluginFile );
61
  if ( $sPluginDir == '.' ) { //it's not within a sub-folder
62
- $sPluginDir = $sPluginFile;
63
  }
64
  $sPath = path_join( WP_PLUGIN_DIR, $sPluginDir );
65
  return $this->loadFS()->deleteDir( $sPath );
@@ -68,9 +85,10 @@ class ICWP_WPSF_WpFunctions_Plugins extends ICWP_WPSF_Foundation {
68
  /**
69
  * @param string $sUrlToInstall
70
  * @param bool $bOverwrite
71
- * @return bool
 
72
  */
73
- public function install( $sUrlToInstall, $bOverwrite = true ) {
74
  $this->loadWpUpgrades();
75
 
76
  $aResult = array(
@@ -82,9 +100,18 @@ class ICWP_WPSF_WpFunctions_Plugins extends ICWP_WPSF_Foundation {
82
  $oUpgraderSkin = new ICWP_Upgrader_Skin();
83
  $oUpgrader = new ICWP_Plugin_Upgrader( $oUpgraderSkin );
84
  $oUpgrader->setOverwriteMode( $bOverwrite );
 
 
 
 
85
  ob_start();
86
  $sInstallResult = $oUpgrader->install( $sUrlToInstall );
87
  ob_end_clean();
 
 
 
 
 
88
  if ( is_wp_error( $oUpgraderSkin->m_aErrors[ 0 ] ) ) {
89
  $aResult[ 'successful' ] = false;
90
  $aResult[ 'errors' ] = $oUpgraderSkin->m_aErrors[ 0 ]->get_error_messages();
@@ -94,10 +121,69 @@ class ICWP_WPSF_WpFunctions_Plugins extends ICWP_WPSF_Foundation {
94
  }
95
 
96
  $aResult[ 'feedback' ] = $oUpgraderSkin->getFeedback();
97
-
98
  return $aResult;
99
  }
100
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  /**
102
  * @param string $sFile
103
  * @return array
@@ -282,18 +368,32 @@ class ICWP_WPSF_WpFunctions_Plugins extends ICWP_WPSF_Foundation {
282
  }
283
 
284
  /**
285
- * @return array
286
  */
287
- public function getAllSlugs() {
288
- $aSlugs = array();
289
-
290
  $oData = $this->loadWp()->getTransient( 'update_plugins' );
291
- $aPlugins = array_merge(
292
  isset( $oData->no_update ) ? $oData->no_update : array(),
293
  isset( $oData->response ) ? $oData->response : array()
294
  );
 
295
 
296
- foreach ( $aPlugins as $sBaseName => $oPlugData ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297
  if ( isset( $oPlugData->slug ) ) {
298
  $aSlugs[ $sBaseName ] = $oPlugData->slug;
299
  }
@@ -304,11 +404,11 @@ class ICWP_WPSF_WpFunctions_Plugins extends ICWP_WPSF_Foundation {
304
 
305
  /**
306
  * @param $sBaseName
307
- * @return string|null
308
  */
309
  public function getSlug( $sBaseName ) {
310
- $aSlugs = $this->getAllSlugs();
311
- return array_key_exists( $sBaseName, $aSlugs ) ? $aSlugs[ $sBaseName ] : null;
312
  }
313
 
314
  /**
@@ -316,24 +416,25 @@ class ICWP_WPSF_WpFunctions_Plugins extends ICWP_WPSF_Foundation {
316
  * @return bool
317
  */
318
  public function isWpOrg( $sBaseName ) {
319
- return !is_null( $this->getSlug( $sBaseName ) );
 
320
  }
321
 
322
  /**
323
- * @param string $sPluginFile
324
  * @return stdClass|null
325
  */
326
- public function getUpdateInfo( $sPluginFile ) {
327
  $aU = $this->getUpdates();
328
- return isset( $aU[ $sPluginFile ] ) ? $aU[ $sPluginFile ] : null;
329
  }
330
 
331
  /**
332
- * @param string $sPluginFile
333
  * @return string
334
  */
335
- public function getUpdateNewVersion( $sPluginFile ) {
336
- $oInfo = $this->getUpdateInfo( $sPluginFile );
337
  return ( !is_null( $oInfo ) && isset( $oInfo->new_version ) ) ? $oInfo->new_version : '';
338
  }
339
 
@@ -351,62 +452,62 @@ class ICWP_WPSF_WpFunctions_Plugins extends ICWP_WPSF_Foundation {
351
  }
352
 
353
  /**
354
- * @param string $sPluginFile
355
  * @return bool
356
  */
357
- public function isPluginActive( $sPluginFile ) {
358
- return ( $this->isPluginInstalled( $sPluginFile ) && is_plugin_active( $sPluginFile ) );
359
  }
360
 
361
  /**
362
  * @param string $sFile The full plugin file.
363
  * @return bool
364
  */
365
- public function isPluginInstalled( $sFile ) {
366
  return !empty( $sFile ) && !is_null( $this->getPlugin( $sFile ) );
367
  }
368
 
369
  /**
370
- * @param string $sPluginFile
371
  * @return boolean|stdClass
372
  */
373
- public function isUpdateAvailable( $sPluginFile ) {
374
- return !is_null( $this->getUpdateInfo( $sPluginFile ) );
375
  }
376
 
377
  /**
378
- * @param string $sPluginFile
379
  * @param int $nDesiredPosition
380
  */
381
- public function setActivePluginLoadPosition( $sPluginFile, $nDesiredPosition = 0 ) {
382
  $oWp = $this->loadWp();
383
 
384
  $aActive = $this->loadDataProcessor()
385
  ->setArrayValueToPosition(
386
  $oWp->getOption( 'active_plugins' ),
387
- $sPluginFile,
388
  $nDesiredPosition
389
  );
390
  $oWp->updateOption( 'active_plugins', $aActive );
391
 
392
  if ( $oWp->isMultisite() ) {
393
  $aActive = $this->loadDataProcessor()
394
- ->setArrayValueToPosition( $oWp->getOption( 'active_sitewide_plugins' ), $sPluginFile, $nDesiredPosition );
395
  $oWp->updateOption( 'active_sitewide_plugins', $aActive );
396
  }
397
  }
398
 
399
  /**
400
- * @param string $sPluginFile
401
  */
402
- public function setActivePluginLoadFirst( $sPluginFile ) {
403
- $this->setActivePluginLoadPosition( $sPluginFile, 0 );
404
  }
405
 
406
  /**
407
- * @param string $sPluginFile
408
  */
409
- public function setActivePluginLoadLast( $sPluginFile ) {
410
- $this->setActivePluginLoadPosition( $sPluginFile, 1000 );
411
  }
412
  }
33
  return activate_plugin( $sPluginFile, '', $bNetworkWide );
34
  }
35
 
36
+ /**
37
+ * @param string $sPluginFile
38
+ * @param bool $bNetworkWide
39
+ * @return null|WP_Error
40
+ */
41
+ protected function activateQuietly( $sPluginFile, $bNetworkWide = false ) {
42
+ return activate_plugin( $sPluginFile, '', $bNetworkWide, true );
43
+ }
44
+
45
  /**
46
  * @param string $sPluginFile
47
  * @param bool $bNetworkWide
53
  /**
54
  * @param string $sPluginFile
55
  * @param bool $bNetworkWide
56
+ */
57
+ protected function deactivateQuietly( $sPluginFile, $bNetworkWide = false ) {
58
+ deactivate_plugins( $sPluginFile, true, $bNetworkWide );
59
+ }
60
+
61
+ /**
62
+ * @param string $sFile
63
+ * @param bool $bNetworkWide
64
  * @return bool
65
  */
66
+ public function delete( $sFile, $bNetworkWide = false ) {
67
+ if ( !$this->isInstalled( $sFile ) ) {
68
  return false;
69
  }
70
 
71
+ if ( $this->isActive( $sFile ) ) {
72
+ $this->deactivate( $sFile, $bNetworkWide );
73
  }
74
+ $this->uninstall( $sFile );
75
 
76
  // delete the folder
77
+ $sPluginDir = dirname( $sFile );
78
  if ( $sPluginDir == '.' ) { //it's not within a sub-folder
79
+ $sPluginDir = $sFile;
80
  }
81
  $sPath = path_join( WP_PLUGIN_DIR, $sPluginDir );
82
  return $this->loadFS()->deleteDir( $sPath );
85
  /**
86
  * @param string $sUrlToInstall
87
  * @param bool $bOverwrite
88
+ * @param bool $bMaintenanceMode
89
+ * @return array
90
  */
91
+ public function install( $sUrlToInstall, $bOverwrite = true, $bMaintenanceMode = false ) {
92
  $this->loadWpUpgrades();
93
 
94
  $aResult = array(
100
  $oUpgraderSkin = new ICWP_Upgrader_Skin();
101
  $oUpgrader = new ICWP_Plugin_Upgrader( $oUpgraderSkin );
102
  $oUpgrader->setOverwriteMode( $bOverwrite );
103
+ if ( $bMaintenanceMode ) {
104
+ $oUpgrader->maintenance_mode( true );
105
+ }
106
+
107
  ob_start();
108
  $sInstallResult = $oUpgrader->install( $sUrlToInstall );
109
  ob_end_clean();
110
+
111
+ if ( $bMaintenanceMode ) {
112
+ $oUpgrader->maintenance_mode( false );
113
+ }
114
+
115
  if ( is_wp_error( $oUpgraderSkin->m_aErrors[ 0 ] ) ) {
116
  $aResult[ 'successful' ] = false;
117
  $aResult[ 'errors' ] = $oUpgraderSkin->m_aErrors[ 0 ]->get_error_messages();
121
  }
122
 
123
  $aResult[ 'feedback' ] = $oUpgraderSkin->getFeedback();
124
+ $aResult[ 'raw' ] = $sInstallResult;
125
  return $aResult;
126
  }
127
 
128
+ /**
129
+ * @param $sSlug
130
+ * @return array|bool
131
+ */
132
+ public function installFromWpOrg( $sSlug ) {
133
+ include_once( ABSPATH.'wp-admin/includes/plugin-install.php' );
134
+
135
+ $api = plugins_api( 'plugin_information', array(
136
+ 'slug' => $sSlug,
137
+ 'fields' => array(
138
+ 'sections' => false,
139
+ ),
140
+ ) );
141
+
142
+ if ( !is_wp_error( $api ) ) {
143
+ return $this->install( $api->download_link, true, true );
144
+ }
145
+ return false;
146
+ }
147
+
148
+ /**
149
+ * @param string $sFile
150
+ * @param bool $bUseBackup
151
+ * @return bool
152
+ */
153
+ public function reinstall( $sFile, $bUseBackup = false ) {
154
+ $bSuccess = false;
155
+
156
+ if ( $this->isInstalled( $sFile ) ) {
157
+
158
+ $sSlug = $this->getSlug( $sFile );
159
+ if ( !empty( $sSlug ) ) {
160
+ $oFS = $this->loadFS();
161
+
162
+ $sDir = dirname( path_join( WP_PLUGIN_DIR, $sFile ) );
163
+ $sBackupDir = WP_PLUGIN_DIR.'/../'.basename( $sDir ).'bak'.time();
164
+ if ( $bUseBackup ) {
165
+ rename( $sDir, $sBackupDir );
166
+ }
167
+
168
+ $aResult = $this->installFromWpOrg( $sSlug );
169
+ $bSuccess = $aResult[ 'successful' ];
170
+ if ( $bSuccess ) {
171
+ wp_update_plugins(); //refreshes our update information
172
+ if ( $bUseBackup ) {
173
+ $oFS->deleteDir( $sBackupDir );
174
+ }
175
+ }
176
+ else {
177
+ if ( $bUseBackup ) {
178
+ $oFS->deleteDir( $sDir );
179
+ rename( $sBackupDir, $sDir );
180
+ }
181
+ }
182
+ }
183
+ }
184
+ return $bSuccess;
185
+ }
186
+
187
  /**
188
  * @param string $sFile
189
  * @return array
368
  }
369
 
370
  /**
371
+ * @return stdClass[] - keys are plugin base files
372
  */
373
+ public function getAllExtendedData() {
 
 
374
  $oData = $this->loadWp()->getTransient( 'update_plugins' );
375
+ return array_merge(
376
  isset( $oData->no_update ) ? $oData->no_update : array(),
377
  isset( $oData->response ) ? $oData->response : array()
378
  );
379
+ }
380
 
381
+ /**
382
+ * @param $sBaseFile
383
+ * @return null|stdClass
384
+ */
385
+ public function getExtendedData( $sBaseFile ) {
386
+ $aData = $this->getAllExtendedData();
387
+ return isset( $aData[ $sBaseFile ] ) ? $aData[ $sBaseFile ] : null;
388
+ }
389
+
390
+ /**
391
+ * @return array
392
+ */
393
+ public function getAllSlugs() {
394
+ $aSlugs = array();
395
+
396
+ foreach ( $this->getAllExtendedData() as $sBaseName => $oPlugData ) {
397
  if ( isset( $oPlugData->slug ) ) {
398
  $aSlugs[ $sBaseName ] = $oPlugData->slug;
399
  }
404
 
405
  /**
406
  * @param $sBaseName
407
+ * @return string
408
  */
409
  public function getSlug( $sBaseName ) {
410
+ $oPluginInfo = $this->getExtendedData( $sBaseName );
411
+ return isset( $oPluginInfo->slug ) ? $oPluginInfo->slug : '';
412
  }
413
 
414
  /**
416
  * @return bool
417
  */
418
  public function isWpOrg( $sBaseName ) {
419
+ $oPluginInfo = $this->getExtendedData( $sBaseName );
420
+ return isset( $oPluginInfo->id ) ? strpos( $oPluginInfo->id, 'w.org/' ) === 0 : false;
421
  }
422
 
423
  /**
424
+ * @param string $sFile
425
  * @return stdClass|null
426
  */
427
+ public function getUpdateInfo( $sFile ) {
428
  $aU = $this->getUpdates();
429
+ return isset( $aU[ $sFile ] ) ? $aU[ $sFile ] : null;
430
  }
431
 
432
  /**
433
+ * @param string $sFile
434
  * @return string
435
  */
436
+ public function getUpdateNewVersion( $sFile ) {
437
+ $oInfo = $this->getUpdateInfo( $sFile );
438
  return ( !is_null( $oInfo ) && isset( $oInfo->new_version ) ) ? $oInfo->new_version : '';
439
  }
440
 
452
  }
453
 
454
  /**
455
+ * @param string $sFile
456
  * @return bool
457
  */
458
+ public function isActive( $sFile ) {
459
+ return ( $this->isInstalled( $sFile ) && is_plugin_active( $sFile ) );
460
  }
461
 
462
  /**
463
  * @param string $sFile The full plugin file.
464
  * @return bool
465
  */
466
+ public function isInstalled( $sFile ) {
467
  return !empty( $sFile ) && !is_null( $this->getPlugin( $sFile ) );
468
  }
469
 
470
  /**
471
+ * @param string $sFile
472
  * @return boolean|stdClass
473
  */
474
+ public function isUpdateAvailable( $sFile ) {
475
+ return !is_null( $this->getUpdateInfo( $sFile ) );
476
  }
477
 
478
  /**
479
+ * @param string $sFile
480
  * @param int $nDesiredPosition
481
  */
482
+ public function setActivePluginLoadPosition( $sFile, $nDesiredPosition = 0 ) {
483
  $oWp = $this->loadWp();
484
 
485
  $aActive = $this->loadDataProcessor()
486
  ->setArrayValueToPosition(
487
  $oWp->getOption( 'active_plugins' ),
488
+ $sFile,
489
  $nDesiredPosition
490
  );
491
  $oWp->updateOption( 'active_plugins', $aActive );
492
 
493
  if ( $oWp->isMultisite() ) {
494
  $aActive = $this->loadDataProcessor()
495
+ ->setArrayValueToPosition( $oWp->getOption( 'active_sitewide_plugins' ), $sFile, $nDesiredPosition );
496
  $oWp->updateOption( 'active_sitewide_plugins', $aActive );
497
  }
498
  }
499
 
500
  /**
501
+ * @param string $sFile
502
  */
503
+ public function setActivePluginLoadFirst( $sFile ) {
504
+ $this->setActivePluginLoadPosition( $sFile, 0 );
505
  }
506
 
507
  /**
508
+ * @param string $sFile
509
  */
510
+ public function setActivePluginLoadLast( $sFile ) {
511
+ $this->setActivePluginLoadPosition( $sFile, 1000 );
512
  }
513
  }
src/common/icwp-wpfunctions-themes.php CHANGED
@@ -59,12 +59,28 @@ class ICWP_WPSF_WpFunctions_Themes extends ICWP_WPSF_Foundation {
59
  return function_exists( 'delete_theme' ) ? delete_theme( $sStylesheet ) : false;
60
  }
61
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  /**
63
  * @param string $sUrlToInstall
64
  * @param bool $bOverwrite
65
- * @return bool
 
66
  */
67
- public function install( $sUrlToInstall, $bOverwrite = true ) {
68
  $this->loadWpUpgrades();
69
 
70
  $aResult = array(
@@ -76,9 +92,18 @@ class ICWP_WPSF_WpFunctions_Themes extends ICWP_WPSF_Foundation {
76
  $oUpgraderSkin = new ICWP_Upgrader_Skin();
77
  $oUpgrader = new ICWP_Theme_Upgrader( $oUpgraderSkin );
78
  $oUpgrader->setOverwriteMode( $bOverwrite );
 
 
 
 
79
  ob_start();
80
  $sInstallResult = $oUpgrader->install( $sUrlToInstall );
81
  ob_end_clean();
 
 
 
 
 
82
  if ( is_wp_error( $oUpgraderSkin->m_aErrors[ 0 ] ) ) {
83
  $aResult[ 'successful' ] = false;
84
  $aResult[ 'errors' ] = $oUpgraderSkin->m_aErrors[ 0 ]->get_error_messages();
@@ -91,6 +116,43 @@ class ICWP_WPSF_WpFunctions_Themes extends ICWP_WPSF_Foundation {
91
  return $aResult;
92
  }
93
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  /**
95
  * @param string $sFile
96
  * @return array
@@ -190,6 +252,77 @@ class ICWP_WPSF_WpFunctions_Themes extends ICWP_WPSF_Foundation {
190
  return is_array( $aUpdates ) ? $aUpdates : array();
191
  }
192
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  /**
194
  * @return boolean|null
195
  */
59
  return function_exists( 'delete_theme' ) ? delete_theme( $sStylesheet ) : false;
60
  }
61
 
62
+ /**
63
+ * @param $sSlug
64
+ * @return array|bool
65
+ */
66
+ public function installFromWpOrg( $sSlug ) {
67
+ include_once( ABSPATH.'wp-admin/includes/plugin-install.php' );
68
+
69
+ $oApi = $this->getExtendedData( $sSlug );
70
+
71
+ if ( !is_wp_error( $oApi ) ) {
72
+ return $this->install( $oApi->download_link, true, true );
73
+ }
74
+ return false;
75
+ }
76
+
77
  /**
78
  * @param string $sUrlToInstall
79
  * @param bool $bOverwrite
80
+ * @param bool $bMaintenanceMode
81
+ * @return array
82
  */
83
+ public function install( $sUrlToInstall, $bOverwrite = true, $bMaintenanceMode = false ) {
84
  $this->loadWpUpgrades();
85
 
86
  $aResult = array(
92
  $oUpgraderSkin = new ICWP_Upgrader_Skin();
93
  $oUpgrader = new ICWP_Theme_Upgrader( $oUpgraderSkin );
94
  $oUpgrader->setOverwriteMode( $bOverwrite );
95
+ if ( $bMaintenanceMode ) {
96
+ $oUpgrader->maintenance_mode( true );
97
+ }
98
+
99
  ob_start();
100
  $sInstallResult = $oUpgrader->install( $sUrlToInstall );
101
  ob_end_clean();
102
+
103
+ if ( $bMaintenanceMode ) {
104
+ $oUpgrader->maintenance_mode( false );
105
+ }
106
+
107
  if ( is_wp_error( $oUpgraderSkin->m_aErrors[ 0 ] ) ) {
108
  $aResult[ 'successful' ] = false;
109
  $aResult[ 'errors' ] = $oUpgraderSkin->m_aErrors[ 0 ]->get_error_messages();
116
  return $aResult;
117
  }
118
 
119
+ /**
120
+ * @param string $sSlug
121
+ * @param bool $bUseBackup
122
+ * @return bool
123
+ */
124
+ public function reinstall( $sSlug, $bUseBackup = false ) {
125
+ $bSuccess = false;
126
+
127
+ if ( $this->isInstalled( $sSlug ) ) {
128
+ $oFS = $this->loadFS();
129
+
130
+ $oTheme = $this->getTheme( $sSlug );
131
+
132
+ $sDir = $oTheme->get_stylesheet_directory();
133
+ $sBackupDir = dirname( $sDir ).'/../../'.$sSlug.'bak'.time();
134
+ if ( $bUseBackup ) {
135
+ rename( $sDir, $sBackupDir );
136
+ }
137
+
138
+ $aResult = $this->installFromWpOrg( $sSlug );
139
+ $bSuccess = $aResult[ 'successful' ];
140
+ if ( $bSuccess ) {
141
+ wp_update_themes(); //refreshes our update information
142
+ if ( $bUseBackup ) {
143
+ $oFS->deleteDir( $sBackupDir );
144
+ }
145
+ }
146
+ else {
147
+ if ( $bUseBackup ) {
148
+ $oFS->deleteDir( $sDir );
149
+ rename( $sBackupDir, $sDir );
150
+ }
151
+ }
152
+ }
153
+ return $bSuccess;
154
+ }
155
+
156
  /**
157
  * @param string $sFile
158
  * @return array
252
  return is_array( $aUpdates ) ? $aUpdates : array();
253
  }
254
 
255
+ /**
256
+ * @return null|WP_Theme
257
+ */
258
+ public function getCurrentParent() {
259
+ $oTheme = $this->getCurrent();
260
+ return $this->isActiveThemeAChild() ? $this->getTheme( $oTheme->get_template() ) : null;
261
+ }
262
+
263
+ /**
264
+ * @param string $sBase
265
+ * @return object|WP_Error
266
+ */
267
+ public function getExtendedData( $sBase ) {
268
+ include_once( ABSPATH.'wp-admin/includes/theme.php' );
269
+
270
+ $oApi = themes_api( 'theme_information', array(
271
+ 'slug' => $sBase,
272
+ 'fields' => array(
273
+ 'sections' => false,
274
+ ),
275
+ ) );
276
+ return $oApi;
277
+ }
278
+
279
+ /**
280
+ * @param string $sSlug
281
+ * @param bool $bCheckIsActiveParent
282
+ * @return bool
283
+ */
284
+ public function isActive( $sSlug, $bCheckIsActiveParent = false ) {
285
+ return ( $this->isInstalled( $sSlug ) && $this->getCurrent()->get_stylesheet() == $sSlug )
286
+ || ( $bCheckIsActiveParent && $this->isActiveParent( $sSlug ) );
287
+ }
288
+
289
+ /**
290
+ * @return bool
291
+ */
292
+ public function isActiveThemeAChild() {
293
+ $oTheme = $this->getCurrent();
294
+ return ( $oTheme->get_stylesheet() != $oTheme->get_template() );
295
+ }
296
+
297
+ /**
298
+ * @param string $sSlug
299
+ * @return bool - true if this is the Parent of the currently active theme
300
+ */
301
+ public function isActiveParent( $sSlug ) {
302
+ return ( $this->isInstalled( $sSlug ) && $this->getCurrent()->get_template() == $sSlug );
303
+ }
304
+
305
+ /**
306
+ * @param string $sSlug The directory slug.
307
+ * @return bool
308
+ */
309
+ public function isInstalled( $sSlug ) {
310
+ return !empty( $sSlug ) && !is_null( $this->getTheme( $sSlug ) );
311
+ }
312
+
313
+ /**
314
+ * @param string $sBaseName
315
+ * @return bool
316
+ */
317
+ public function isWpOrg( $sBaseName ) {
318
+ $bIsWpOrg = false;
319
+ $oInfo = $this->getExtendedData( $sBaseName );
320
+ if ( !empty( $oInfo ) && !is_wp_error( $oInfo ) && isset( $oInfo->download_link ) ) {
321
+ $bIsWpOrg = strpos( $oInfo->download_link, 'https://downloads.wordpress.org' ) === 0;
322
+ }
323
+ return $bIsWpOrg;
324
+ }
325
+
326
  /**
327
  * @return boolean|null
328
  */
src/common/icwp-wpfunctions.php CHANGED
@@ -121,7 +121,7 @@ class ICWP_WPSF_WpFunctions extends ICWP_WPSF_Foundation {
121
  /**
122
  * @return bool
123
  */
124
- public function getIsPermalinksEnabled() {
125
  return ( $this->getOption( 'permalink_structure' ) ? true : false );
126
  }
127
 
@@ -674,17 +674,53 @@ class ICWP_WPSF_WpFunctions extends ICWP_WPSF_Foundation {
674
  /**
675
  * @return bool
676
  */
677
- public function isRestUrl() {
678
- $bIsRest = false;
679
- if ( function_exists( 'rest_url' ) ) {
 
680
  $sRestUrlBase = get_rest_url( get_current_blog_id(), '/' );
681
  $sRestPath = trim( parse_url( $sRestUrlBase, PHP_URL_PATH ), '/' );
682
- $sRequestPath = trim( $this->loadDataProcessor()->getRequestPath(), '/' );
683
  $bIsRest = ( strpos( $sRequestPath, $sRestPath ) === 0 );
684
  }
685
  return $bIsRest;
686
  }
687
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
688
  /**
689
  * @param string $sKey
690
  * @param string $sValue
@@ -725,13 +761,13 @@ class ICWP_WPSF_WpFunctions extends ICWP_WPSF_Foundation {
725
  */
726
  public function getCurrentWpAdminPage() {
727
 
728
- $oDp = $this->loadDataProcessor();
729
  $sScript = $oDp->FetchServer( 'SCRIPT_NAME' );
730
  if ( empty( $sScript ) ) {
731
  $sScript = $oDp->FetchServer( 'PHP_SELF' );
732
  }
733
  if ( is_admin() && !empty( $sScript ) && basename( $sScript ) == 'admin.php' ) {
734
- $sCurrentPage = $oDp->FetchGet( 'page' );
735
  }
736
  return empty( $sCurrentPage ) ? '' : $sCurrentPage;
737
  }
121
  /**
122
  * @return bool
123
  */
124
+ public function isPermalinksEnabled() {
125
  return ( $this->getOption( 'permalink_structure' ) ? true : false );
126
  }
127
 
674
  /**
675
  * @return bool
676
  */
677
+ public function isRest() {
678
+ $bIsRest = ( defined( 'REST_REQUEST' ) && REST_REQUEST ) || !empty( $_REQUEST[ 'rest_route' ] );
679
+
680
+ if ( !$bIsRest && function_exists( 'rest_url' ) ) {
681
  $sRestUrlBase = get_rest_url( get_current_blog_id(), '/' );
682
  $sRestPath = trim( parse_url( $sRestUrlBase, PHP_URL_PATH ), '/' );
683
+ $sRequestPath = trim( $this->loadDP()->getRequestPath(), '/' );
684
  $bIsRest = ( strpos( $sRequestPath, $sRestPath ) === 0 );
685
  }
686
  return $bIsRest;
687
  }
688
 
689
+ /**
690
+ * @return string|null
691
+ */
692
+ public function getRestNamespace() {
693
+ $sNameSpace = null;
694
+
695
+ $sPath = $this->getRestPath();
696
+
697
+ if ( !empty( $sPath ) ) {
698
+ $aParts = explode( '/', $sPath );
699
+ if ( !empty( $aParts ) ) {
700
+ $sNameSpace = $aParts[ 0 ];
701
+ }
702
+ }
703
+ return $sNameSpace;
704
+ }
705
+
706
+ /**
707
+ * @return string|null
708
+ */
709
+ public function getRestPath() {
710
+ $sPath = null;
711
+
712
+ if ( $this->isRest() ) {
713
+ $oDP = $this->loadDP();
714
+
715
+ $sPath = $oDP->FetchRequest( 'rest_route' );
716
+ if ( empty( $sPath ) && $this->isPermalinksEnabled() ) {
717
+ $sFullUri = $this->loadWp()->getHomeUrl().$oDP->getRequestPath();
718
+ $sPath = substr( $sFullUri, strlen( get_rest_url( get_current_blog_id() ) ) );
719
+ }
720
+ }
721
+ return $sPath;
722
+ }
723
+
724
  /**
725
  * @param string $sKey
726
  * @param string $sValue
761
  */
762
  public function getCurrentWpAdminPage() {
763
 
764
+ $oDp = $this->loadDP();
765
  $sScript = $oDp->FetchServer( 'SCRIPT_NAME' );
766
  if ( empty( $sScript ) ) {
767
  $sScript = $oDp->FetchServer( 'PHP_SELF' );
768
  }
769
  if ( is_admin() && !empty( $sScript ) && basename( $sScript ) == 'admin.php' ) {
770
+ $sCurrentPage = $oDp->query( 'page' );
771
  }
772
  return empty( $sCurrentPage ) ? '' : $sCurrentPage;
773
  }
src/common/icwp-wpupgrades.php CHANGED
@@ -72,30 +72,43 @@ if ( !class_exists( 'ICWP_Plugin_Upgrader', false ) && class_exists( 'Plugin_Upg
72
  $this->init();
73
  $this->install_strings();
74
 
75
- add_filter('upgrader_source_selection', array($this, 'check_package') );
76
-
77
- $this->run( array(
78
- 'package' => $package,
79
- 'destination' => WP_PLUGIN_DIR,
80
- 'clear_destination' => $this->getOverwriteMode(), // this is the key to overwrite and why we're extending the native wordpress class
81
- 'clear_working' => true,
82
- 'hook_extra' => array(
83
- 'type' => 'plugin',
 
84
  'action' => 'install',
85
  )
86
  ) );
87
 
88
- remove_filter('upgrader_source_selection', array($this, 'check_package') );
 
89
 
90
- if ( ! $this->result || is_wp_error($this->result) )
91
  return $this->result;
 
92
 
93
  // Force refresh of plugin update information
94
- wp_clean_plugins_cache( $parsed_args['clear_update_cache'] );
95
 
96
  return true;
97
  }
98
 
 
 
 
 
 
 
 
 
 
 
99
  public function getOverwriteMode() {
100
  return $this->fModeOverwrite;
101
  }
@@ -208,22 +221,24 @@ if ( !class_exists( 'ICWP_Theme_Upgrader', false ) && class_exists( 'Theme_Upgra
208
  $this->init();
209
  $this->install_strings();
210
 
211
- add_filter('upgrader_source_selection', array($this, 'check_package') );
212
- add_filter('upgrader_post_install', array($this, 'check_parent_theme_filter'), 10, 3);
 
213
 
214
  $this->run( array(
215
- 'package' => $package,
216
- 'destination' => get_theme_root(),
217
  'clear_destination' => $this->getOverwriteMode(),
218
- 'clear_working' => true,
219
- 'hook_extra' => array(
220
- 'type' => 'theme',
221
  'action' => 'install',
222
  ),
223
  ) );
224
 
225
- remove_filter('upgrader_source_selection', array($this, 'check_package') );
226
- remove_filter('upgrader_post_install', array($this, 'check_parent_theme_filter'));
 
227
 
228
  if ( ! $this->result || is_wp_error($this->result) )
229
  return $this->result;
@@ -234,6 +249,16 @@ if ( !class_exists( 'ICWP_Theme_Upgrader', false ) && class_exists( 'Theme_Upgra
234
  return true;
235
  }
236
 
 
 
 
 
 
 
 
 
 
 
237
  public function getOverwriteMode() {
238
  return $this->fModeOverwrite;
239
  }
72
  $this->init();
73
  $this->install_strings();
74
 
75
+ add_filter( 'upgrader_source_selection', array( $this, 'check_package' ) );
76
+ add_filter( 'upgrader_clear_destination', array( $this, 'clearStatCache' ) );
77
+
78
+ $oResult = $this->run( array(
79
+ 'package' => $package,
80
+ 'destination' => WP_PLUGIN_DIR,
81
+ 'clear_destination' => $this->getOverwriteMode(), // key to overwrite and why we're extending the native wordpress class
82
+ 'clear_working' => true,
83
+ 'hook_extra' => array(
84
+ 'type' => 'plugin',
85
  'action' => 'install',
86
  )
87
  ) );
88
 
89
+ remove_filter( 'upgrader_source_selection', array( $this, 'check_package' ) );
90
+ remove_filter( 'upgrader_clear_destination', array( $this, 'clearStatCache' ) );
91
 
92
+ if ( !$this->result || is_wp_error( $this->result ) ) {
93
  return $this->result;
94
+ }
95
 
96
  // Force refresh of plugin update information
97
+ wp_clean_plugins_cache( $parsed_args[ 'clear_update_cache' ] );
98
 
99
  return true;
100
  }
101
 
102
+ /**
103
+ * This is inserted right after clearing the target directory. It seems that some systems are slow
104
+ * in updating filesystem "info" because we were receiving permission denied when trying to recreate
105
+ * the install directory.
106
+ */
107
+ public function clearStatCache() {
108
+ clearstatcache();
109
+ sleep( 1 );
110
+ }
111
+
112
  public function getOverwriteMode() {
113
  return $this->fModeOverwrite;
114
  }
221
  $this->init();
222
  $this->install_strings();
223
 
224
+ add_filter( 'upgrader_source_selection', array( $this, 'check_package' ) );
225
+ add_filter( 'upgrader_post_install', array( $this, 'check_parent_theme_filter' ), 10, 3 );
226
+ add_filter( 'upgrader_clear_destination', array( $this, 'clearStatCache' ) );
227
 
228
  $this->run( array(
229
+ 'package' => $package,
230
+ 'destination' => get_theme_root(),
231
  'clear_destination' => $this->getOverwriteMode(),
232
+ 'clear_working' => true,
233
+ 'hook_extra' => array(
234
+ 'type' => 'theme',
235
  'action' => 'install',
236
  ),
237
  ) );
238
 
239
+ remove_filter( 'upgrader_source_selection', array( $this, 'check_package' ) );
240
+ remove_filter( 'upgrader_post_install', array( $this, 'check_parent_theme_filter' ) );
241
+ remove_filter( 'upgrader_clear_destination', array( $this, 'clearStatCache' ) );
242
 
243
  if ( ! $this->result || is_wp_error($this->result) )
244
  return $this->result;
249
  return true;
250
  }
251
 
252
+ /**
253
+ * This is inserted right after clearing the target directory. It seems that some systems are slow
254
+ * in updating filesystem "info" because we were receiving permission denied when trying to recreate
255
+ * the install directory.
256
+ */
257
+ public function clearStatCache() {
258
+ clearstatcache();
259
+ sleep( 1 );
260
+ }
261
+
262
  public function getOverwriteMode() {
263
  return $this->fModeOverwrite;
264
  }
src/common/lib/composer.lock CHANGED
@@ -95,16 +95,16 @@
95
  },
96
  {
97
  "name": "symfony/polyfill-mbstring",
98
- "version": "v1.6.0",
99
  "source": {
100
  "type": "git",
101
  "url": "https://github.com/symfony/polyfill-mbstring.git",
102
- "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296"
103
  },
104
  "dist": {
105
  "type": "zip",
106
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296",
107
- "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296",
108
  "shasum": ""
109
  },
110
  "require": {
@@ -116,7 +116,7 @@
116
  "type": "library",
117
  "extra": {
118
  "branch-alias": {
119
- "dev-master": "1.6-dev"
120
  }
121
  },
122
  "autoload": {
@@ -150,7 +150,7 @@
150
  "portable",
151
  "shim"
152
  ],
153
- "time": "2017-10-11T12:05:26+00:00"
154
  },
155
  {
156
  "name": "symfony/translation",
95
  },
96
  {
97
  "name": "symfony/polyfill-mbstring",
98
+ "version": "v1.7.0",
99
  "source": {
100
  "type": "git",
101
  "url": "https://github.com/symfony/polyfill-mbstring.git",
102
+ "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b"
103
  },
104
  "dist": {
105
  "type": "zip",
106
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/78be803ce01e55d3491c1397cf1c64beb9c1b63b",
107
+ "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b",
108
  "shasum": ""
109
  },
110
  "require": {
116
  "type": "library",
117
  "extra": {
118
  "branch-alias": {
119
+ "dev-master": "1.7-dev"
120
  }
121
  },
122
  "autoload": {
150
  "portable",
151
  "shim"
152
  ],
153
+ "time": "2018-01-30T19:27:44+00:00"
154
  },
155
  {
156
  "name": "symfony/translation",
src/common/lib/vendor/composer/autoload_classmap.php CHANGED
@@ -6,4 +6,445 @@ $vendorDir = dirname(dirname(__FILE__));
6
  $baseDir = dirname($vendorDir);
7
 
8
  return array(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  );
6
  $baseDir = dirname($vendorDir);
7
 
8
  return array(
9
+ 'Carbon\\Carbon' => $vendorDir . '/nesbot/carbon/src/Carbon/Carbon.php',
10
+ 'Carbon\\CarbonInterval' => $vendorDir . '/nesbot/carbon/src/Carbon/CarbonInterval.php',
11
+ 'Carbon\\Exceptions\\InvalidDateException' => $vendorDir . '/nesbot/carbon/src/Carbon/Exceptions/InvalidDateException.php',
12
+ 'FernleafSystems\\Utilities\\Data\\Adapter\\StdClassAdapter' => $vendorDir . '/fernleafsystems/utilities/src/Data/Adapter/StdClassAdapter.php',
13
+ 'FernleafSystems\\Utilities\\Response' => $vendorDir . '/fernleafsystems/utilities/src/Response.php',
14
+ 'Symfony\\Component\\Translation\\Catalogue\\AbstractOperation' => $vendorDir . '/symfony/translation/Catalogue/AbstractOperation.php',
15
+ 'Symfony\\Component\\Translation\\Catalogue\\MergeOperation' => $vendorDir . '/symfony/translation/Catalogue/MergeOperation.php',
16
+ 'Symfony\\Component\\Translation\\Catalogue\\OperationInterface' => $vendorDir . '/symfony/translation/Catalogue/OperationInterface.php',
17
+ 'Symfony\\Component\\Translation\\Catalogue\\TargetOperation' => $vendorDir . '/symfony/translation/Catalogue/TargetOperation.php',
18
+ 'Symfony\\Component\\Translation\\Command\\XliffLintCommand' => $vendorDir . '/symfony/translation/Command/XliffLintCommand.php',
19
+ 'Symfony\\Component\\Translation\\DataCollectorTranslator' => $vendorDir . '/symfony/translation/DataCollectorTranslator.php',
20
+ 'Symfony\\Component\\Translation\\DataCollector\\TranslationDataCollector' => $vendorDir . '/symfony/translation/DataCollector/TranslationDataCollector.php',
21
+ 'Symfony\\Component\\Translation\\DependencyInjection\\TranslationDumperPass' => $vendorDir . '/symfony/translation/DependencyInjection/TranslationDumperPass.php',
22
+ 'Symfony\\Component\\Translation\\DependencyInjection\\TranslationExtractorPass' => $vendorDir . '/symfony/translation/DependencyInjection/TranslationExtractorPass.php',
23
+ 'Symfony\\Component\\Translation\\DependencyInjection\\TranslatorPass' => $vendorDir . '/symfony/translation/DependencyInjection/TranslatorPass.php',
24
+ 'Symfony\\Component\\Translation\\Dumper\\CsvFileDumper' => $vendorDir . '/symfony/translation/Dumper/CsvFileDumper.php',
25
+ 'Symfony\\Component\\Translation\\Dumper\\DumperInterface' => $vendorDir . '/symfony/translation/Dumper/DumperInterface.php',
26
+ 'Symfony\\Component\\Translation\\Dumper\\FileDumper' => $vendorDir . '/symfony/translation/Dumper/FileDumper.php',
27
+ 'Symfony\\Component\\Translation\\Dumper\\IcuResFileDumper' => $vendorDir . '/symfony/translation/Dumper/IcuResFileDumper.php',
28
+ 'Symfony\\Component\\Translation\\Dumper\\IniFileDumper' => $vendorDir . '/symfony/translation/Dumper/IniFileDumper.php',
29
+ 'Symfony\\Component\\Translation\\Dumper\\JsonFileDumper' => $vendorDir . '/symfony/translation/Dumper/JsonFileDumper.php',
30
+ 'Symfony\\Component\\Translation\\Dumper\\MoFileDumper' => $vendorDir . '/symfony/translation/Dumper/MoFileDumper.php',
31
+ 'Symfony\\Component\\Translation\\Dumper\\PhpFileDumper' => $vendorDir . '/symfony/translation/Dumper/PhpFileDumper.php',
32
+ 'Symfony\\Component\\Translation\\Dumper\\PoFileDumper' => $vendorDir . '/symfony/translation/Dumper/PoFileDumper.php',
33
+ 'Symfony\\Component\\Translation\\Dumper\\QtFileDumper' => $vendorDir . '/symfony/translation/Dumper/QtFileDumper.php',
34
+ 'Symfony\\Component\\Translation\\Dumper\\XliffFileDumper' => $vendorDir . '/symfony/translation/Dumper/XliffFileDumper.php',
35
+ 'Symfony\\Component\\Translation\\Dumper\\YamlFileDumper' => $vendorDir . '/symfony/translation/Dumper/YamlFileDumper.php',
36
+ 'Symfony\\Component\\Translation\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/translation/Exception/ExceptionInterface.php',
37
+ 'Symfony\\Component\\Translation\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/translation/Exception/InvalidArgumentException.php',
38
+ 'Symfony\\Component\\Translation\\Exception\\InvalidResourceException' => $vendorDir . '/symfony/translation/Exception/InvalidResourceException.php',
39
+ 'Symfony\\Component\\Translation\\Exception\\LogicException' => $vendorDir . '/symfony/translation/Exception/LogicException.php',
40
+ 'Symfony\\Component\\Translation\\Exception\\NotFoundResourceException' => $vendorDir . '/symfony/translation/Exception/NotFoundResourceException.php',
41
+ 'Symfony\\Component\\Translation\\Exception\\RuntimeException' => $vendorDir . '/symfony/translation/Exception/RuntimeException.php',
42
+ 'Symfony\\Component\\Translation\\Extractor\\AbstractFileExtractor' => $vendorDir . '/symfony/translation/Extractor/AbstractFileExtractor.php',
43
+ 'Symfony\\Component\\Translation\\Extractor\\ChainExtractor' => $vendorDir . '/symfony/translation/Extractor/ChainExtractor.php',
44
+ 'Symfony\\Component\\Translation\\Extractor\\ExtractorInterface' => $vendorDir . '/symfony/translation/Extractor/ExtractorInterface.php',
45
+ 'Symfony\\Component\\Translation\\Extractor\\PhpExtractor' => $vendorDir . '/symfony/translation/Extractor/PhpExtractor.php',
46
+ 'Symfony\\Component\\Translation\\Extractor\\PhpStringTokenParser' => $vendorDir . '/symfony/translation/Extractor/PhpStringTokenParser.php',
47
+ 'Symfony\\Component\\Translation\\Formatter\\ChoiceMessageFormatterInterface' => $vendorDir . '/symfony/translation/Formatter/ChoiceMessageFormatterInterface.php',
48
+ 'Symfony\\Component\\Translation\\Formatter\\MessageFormatter' => $vendorDir . '/symfony/translation/Formatter/MessageFormatter.php',
49
+ 'Symfony\\Component\\Translation\\Formatter\\MessageFormatterInterface' => $vendorDir . '/symfony/translation/Formatter/MessageFormatterInterface.php',
50
+ 'Symfony\\Component\\Translation\\IdentityTranslator' => $vendorDir . '/symfony/translation/IdentityTranslator.php',
51
+ 'Symfony\\Component\\Translation\\Interval' => $vendorDir . '/symfony/translation/Interval.php',
52
+ 'Symfony\\Component\\Translation\\Loader\\ArrayLoader' => $vendorDir . '/symfony/translation/Loader/ArrayLoader.php',
53
+ 'Symfony\\Component\\Translation\\Loader\\CsvFileLoader' => $vendorDir . '/symfony/translation/Loader/CsvFileLoader.php',
54
+ 'Symfony\\Component\\Translation\\Loader\\FileLoader' => $vendorDir . '/symfony/translation/Loader/FileLoader.php',
55
+ 'Symfony\\Component\\Translation\\Loader\\IcuDatFileLoader' => $vendorDir . '/symfony/translation/Loader/IcuDatFileLoader.php',
56
+ 'Symfony\\Component\\Translation\\Loader\\IcuResFileLoader' => $vendorDir . '/symfony/translation/Loader/IcuResFileLoader.php',
57
+ 'Symfony\\Component\\Translation\\Loader\\IniFileLoader' => $vendorDir . '/symfony/translation/Loader/IniFileLoader.php',
58
+ 'Symfony\\Component\\Translation\\Loader\\JsonFileLoader' => $vendorDir . '/symfony/translation/Loader/JsonFileLoader.php',
59
+ 'Symfony\\Component\\Translation\\Loader\\LoaderInterface' => $vendorDir . '/symfony/translation/Loader/LoaderInterface.php',
60
+ 'Symfony\\Component\\Translation\\Loader\\MoFileLoader' => $vendorDir . '/symfony/translation/Loader/MoFileLoader.php',
61
+ 'Symfony\\Component\\Translation\\Loader\\PhpFileLoader' => $vendorDir . '/symfony/translation/Loader/PhpFileLoader.php',
62
+ 'Symfony\\Component\\Translation\\Loader\\PoFileLoader' => $vendorDir . '/symfony/translation/Loader/PoFileLoader.php',
63
+ 'Symfony\\Component\\Translation\\Loader\\QtFileLoader' => $vendorDir . '/symfony/translation/Loader/QtFileLoader.php',
64
+ 'Symfony\\Component\\Translation\\Loader\\XliffFileLoader' => $vendorDir . '/symfony/translation/Loader/XliffFileLoader.php',
65
+ 'Symfony\\Component\\Translation\\Loader\\YamlFileLoader' => $vendorDir . '/symfony/translation/Loader/YamlFileLoader.php',
66
+ 'Symfony\\Component\\Translation\\LoggingTranslator' => $vendorDir . '/symfony/translation/LoggingTranslator.php',
67
+ 'Symfony\\Component\\Translation\\MessageCatalogue' => $vendorDir . '/symfony/translation/MessageCatalogue.php',
68
+ 'Symfony\\Component\\Translation\\MessageCatalogueInterface' => $vendorDir . '/symfony/translation/MessageCatalogueInterface.php',
69
+ 'Symfony\\Component\\Translation\\MessageSelector' => $vendorDir . '/symfony/translation/MessageSelector.php',
70
+ 'Symfony\\Component\\Translation\\MetadataAwareInterface' => $vendorDir . '/symfony/translation/MetadataAwareInterface.php',
71
+ 'Symfony\\Component\\Translation\\PluralizationRules' => $vendorDir . '/symfony/translation/PluralizationRules.php',
72
+ 'Symfony\\Component\\Translation\\Reader\\TranslationReader' => $vendorDir . '/symfony/translation/Reader/TranslationReader.php',
73
+ 'Symfony\\Component\\Translation\\Reader\\TranslationReaderInterface' => $vendorDir . '/symfony/translation/Reader/TranslationReaderInterface.php',
74
+ 'Symfony\\Component\\Translation\\Translator' => $vendorDir . '/symfony/translation/Translator.php',
75
+ 'Symfony\\Component\\Translation\\TranslatorBagInterface' => $vendorDir . '/symfony/translation/TranslatorBagInterface.php',
76
+ 'Symfony\\Component\\Translation\\TranslatorInterface' => $vendorDir . '/symfony/translation/TranslatorInterface.php',
77
+ 'Symfony\\Component\\Translation\\Util\\ArrayConverter' => $vendorDir . '/symfony/translation/Util/ArrayConverter.php',
78
+ 'Symfony\\Component\\Translation\\Writer\\TranslationWriter' => $vendorDir . '/symfony/translation/Writer/TranslationWriter.php',
79
+ 'Symfony\\Component\\Translation\\Writer\\TranslationWriterInterface' => $vendorDir . '/symfony/translation/Writer/TranslationWriterInterface.php',
80
+ 'Symfony\\Polyfill\\Mbstring\\Mbstring' => $vendorDir . '/symfony/polyfill-mbstring/Mbstring.php',
81
+ 'Twig\\Cache\\CacheInterface' => $vendorDir . '/twig/twig/src/Cache/CacheInterface.php',
82
+ 'Twig\\Cache\\FilesystemCache' => $vendorDir . '/twig/twig/src/Cache/FilesystemCache.php',
83
+ 'Twig\\Cache\\NullCache' => $vendorDir . '/twig/twig/src/Cache/NullCache.php',
84
+ 'Twig\\Compiler' => $vendorDir . '/twig/twig/src/Compiler.php',
85
+ 'Twig\\Environment' => $vendorDir . '/twig/twig/src/Environment.php',
86
+ 'Twig\\Error\\Error' => $vendorDir . '/twig/twig/src/Error/Error.php',
87
+ 'Twig\\Error\\LoaderError' => $vendorDir . '/twig/twig/src/Error/LoaderError.php',
88
+ 'Twig\\Error\\RuntimeError' => $vendorDir . '/twig/twig/src/Error/RuntimeError.php',
89
+ 'Twig\\Error\\SyntaxError' => $vendorDir . '/twig/twig/src/Error/SyntaxError.php',
90
+ 'Twig\\ExpressionParser' => $vendorDir . '/twig/twig/src/ExpressionParser.php',
91
+ 'Twig\\Extension\\AbstractExtension' => $vendorDir . '/twig/twig/src/Extension/AbstractExtension.php',
92
+ 'Twig\\Extension\\CoreExtension' => $vendorDir . '/twig/twig/src/Extension/CoreExtension.php',
93
+ 'Twig\\Extension\\DebugExtension' => $vendorDir . '/twig/twig/src/Extension/DebugExtension.php',
94
+ 'Twig\\Extension\\EscaperExtension' => $vendorDir . '/twig/twig/src/Extension/EscaperExtension.php',
95
+ 'Twig\\Extension\\ExtensionInterface' => $vendorDir . '/twig/twig/src/Extension/ExtensionInterface.php',
96
+ 'Twig\\Extension\\GlobalsInterface' => $vendorDir . '/twig/twig/src/Extension/GlobalsInterface.php',
97
+ 'Twig\\Extension\\InitRuntimeInterface' => $vendorDir . '/twig/twig/src/Extension/InitRuntimeInterface.php',
98
+ 'Twig\\Extension\\OptimizerExtension' => $vendorDir . '/twig/twig/src/Extension/OptimizerExtension.php',
99
+ 'Twig\\Extension\\ProfilerExtension' => $vendorDir . '/twig/twig/src/Extension/ProfilerExtension.php',
100
+ 'Twig\\Extension\\RuntimeExtensionInterface' => $vendorDir . '/twig/twig/src/Extension/RuntimeExtensionInterface.php',
101
+ 'Twig\\Extension\\SandboxExtension' => $vendorDir . '/twig/twig/src/Extension/SandboxExtension.php',
102
+ 'Twig\\Extension\\StagingExtension' => $vendorDir . '/twig/twig/src/Extension/StagingExtension.php',
103
+ 'Twig\\Extension\\StringLoaderExtension' => $vendorDir . '/twig/twig/src/Extension/StringLoaderExtension.php',
104
+ 'Twig\\FileExtensionEscapingStrategy' => $vendorDir . '/twig/twig/src/FileExtensionEscapingStrategy.php',
105
+ 'Twig\\Lexer' => $vendorDir . '/twig/twig/src/Lexer.php',
106
+ 'Twig\\Loader\\ArrayLoader' => $vendorDir . '/twig/twig/src/Loader/ArrayLoader.php',
107
+ 'Twig\\Loader\\ChainLoader' => $vendorDir . '/twig/twig/src/Loader/ChainLoader.php',
108
+ 'Twig\\Loader\\ExistsLoaderInterface' => $vendorDir . '/twig/twig/src/Loader/ExistsLoaderInterface.php',
109
+ 'Twig\\Loader\\FilesystemLoader' => $vendorDir . '/twig/twig/src/Loader/FilesystemLoader.php',
110
+ 'Twig\\Loader\\LoaderInterface' => $vendorDir . '/twig/twig/src/Loader/LoaderInterface.php',
111
+ 'Twig\\Loader\\SourceContextLoaderInterface' => $vendorDir . '/twig/twig/src/Loader/SourceContextLoaderInterface.php',
112
+ 'Twig\\Markup' => $vendorDir . '/twig/twig/src/Markup.php',
113
+ 'Twig\\NodeTraverser' => $vendorDir . '/twig/twig/src/NodeTraverser.php',
114
+ 'Twig\\NodeVisitor\\AbstractNodeVisitor' => $vendorDir . '/twig/twig/src/NodeVisitor/AbstractNodeVisitor.php',
115
+ 'Twig\\NodeVisitor\\EscaperNodeVisitor' => $vendorDir . '/twig/twig/src/NodeVisitor/EscaperNodeVisitor.php',
116
+ 'Twig\\NodeVisitor\\NodeVisitorInterface' => $vendorDir . '/twig/twig/src/NodeVisitor/NodeVisitorInterface.php',
117
+ 'Twig\\NodeVisitor\\OptimizerNodeVisitor' => $vendorDir . '/twig/twig/src/NodeVisitor/OptimizerNodeVisitor.php',
118
+ 'Twig\\NodeVisitor\\SafeAnalysisNodeVisitor' => $vendorDir . '/twig/twig/src/NodeVisitor/SafeAnalysisNodeVisitor.php',
119
+ 'Twig\\NodeVisitor\\SandboxNodeVisitor' => $vendorDir . '/twig/twig/src/NodeVisitor/SandboxNodeVisitor.php',
120
+ 'Twig\\Node\\AutoEscapeNode' => $vendorDir . '/twig/twig/src/Node/AutoEscapeNode.php',
121
+ 'Twig\\Node\\BlockNode' => $vendorDir . '/twig/twig/src/Node/BlockNode.php',
122
+ 'Twig\\Node\\BlockReferenceNode' => $vendorDir . '/twig/twig/src/Node/BlockReferenceNode.php',
123
+ 'Twig\\Node\\BodyNode' => $vendorDir . '/twig/twig/src/Node/BodyNode.php',
124
+ 'Twig\\Node\\CheckSecurityNode' => $vendorDir . '/twig/twig/src/Node/CheckSecurityNode.php',
125
+ 'Twig\\Node\\DoNode' => $vendorDir . '/twig/twig/src/Node/DoNode.php',
126
+ 'Twig\\Node\\EmbedNode' => $vendorDir . '/twig/twig/src/Node/EmbedNode.php',
127
+ 'Twig\\Node\\Expression\\AbstractExpression' => $vendorDir . '/twig/twig/src/Node/Expression/AbstractExpression.php',
128
+ 'Twig\\Node\\Expression\\ArrayExpression' => $vendorDir . '/twig/twig/src/Node/Expression/ArrayExpression.php',
129
+ 'Twig\\Node\\Expression\\AssignNameExpression' => $vendorDir . '/twig/twig/src/Node/Expression/AssignNameExpression.php',
130
+ 'Twig\\Node\\Expression\\Binary\\AbstractBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/AbstractBinary.php',
131
+ 'Twig\\Node\\Expression\\Binary\\AddBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/AddBinary.php',
132
+ 'Twig\\Node\\Expression\\Binary\\AndBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/AndBinary.php',
133
+ 'Twig\\Node\\Expression\\Binary\\BitwiseAndBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/BitwiseAndBinary.php',
134
+ 'Twig\\Node\\Expression\\Binary\\BitwiseOrBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/BitwiseOrBinary.php',
135
+ 'Twig\\Node\\Expression\\Binary\\BitwiseXorBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/BitwiseXorBinary.php',
136
+ 'Twig\\Node\\Expression\\Binary\\ConcatBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/ConcatBinary.php',
137
+ 'Twig\\Node\\Expression\\Binary\\DivBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/DivBinary.php',
138
+ 'Twig\\Node\\Expression\\Binary\\EndsWithBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/EndsWithBinary.php',
139
+ 'Twig\\Node\\Expression\\Binary\\EqualBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/EqualBinary.php',
140
+ 'Twig\\Node\\Expression\\Binary\\FloorDivBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/FloorDivBinary.php',
141
+ 'Twig\\Node\\Expression\\Binary\\GreaterBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/GreaterBinary.php',
142
+ 'Twig\\Node\\Expression\\Binary\\GreaterEqualBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/GreaterEqualBinary.php',
143
+ 'Twig\\Node\\Expression\\Binary\\InBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/InBinary.php',
144
+ 'Twig\\Node\\Expression\\Binary\\LessBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/LessBinary.php',
145
+ 'Twig\\Node\\Expression\\Binary\\LessEqualBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/LessEqualBinary.php',
146
+ 'Twig\\Node\\Expression\\Binary\\MatchesBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/MatchesBinary.php',
147
+ 'Twig\\Node\\Expression\\Binary\\ModBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/ModBinary.php',
148
+ 'Twig\\Node\\Expression\\Binary\\MulBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/MulBinary.php',
149
+ 'Twig\\Node\\Expression\\Binary\\NotEqualBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/NotEqualBinary.php',
150
+ 'Twig\\Node\\Expression\\Binary\\NotInBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/NotInBinary.php',
151
+ 'Twig\\Node\\Expression\\Binary\\OrBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/OrBinary.php',
152
+ 'Twig\\Node\\Expression\\Binary\\PowerBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/PowerBinary.php',
153
+ 'Twig\\Node\\Expression\\Binary\\RangeBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/RangeBinary.php',
154
+ 'Twig\\Node\\Expression\\Binary\\StartsWithBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/StartsWithBinary.php',
155
+ 'Twig\\Node\\Expression\\Binary\\SubBinary' => $vendorDir . '/twig/twig/src/Node/Expression/Binary/SubBinary.php',
156
+ 'Twig\\Node\\Expression\\BlockReferenceExpression' => $vendorDir . '/twig/twig/src/Node/Expression/BlockReferenceExpression.php',
157
+ 'Twig\\Node\\Expression\\CallExpression' => $vendorDir . '/twig/twig/src/Node/Expression/CallExpression.php',
158
+ 'Twig\\Node\\Expression\\ConditionalExpression' => $vendorDir . '/twig/twig/src/Node/Expression/ConditionalExpression.php',
159
+ 'Twig\\Node\\Expression\\ConstantExpression' => $vendorDir . '/twig/twig/src/Node/Expression/ConstantExpression.php',
160
+ 'Twig\\Node\\Expression\\FilterExpression' => $vendorDir . '/twig/twig/src/Node/Expression/FilterExpression.php',
161
+ 'Twig\\Node\\Expression\\Filter\\DefaultFilter' => $vendorDir . '/twig/twig/src/Node/Expression/Filter/DefaultFilter.php',
162
+ 'Twig\\Node\\Expression\\FunctionExpression' => $vendorDir . '/twig/twig/src/Node/Expression/FunctionExpression.php',
163
+ 'Twig\\Node\\Expression\\GetAttrExpression' => $vendorDir . '/twig/twig/src/Node/Expression/GetAttrExpression.php',
164
+ 'Twig\\Node\\Expression\\MethodCallExpression' => $vendorDir . '/twig/twig/src/Node/Expression/MethodCallExpression.php',
165
+ 'Twig\\Node\\Expression\\NameExpression' => $vendorDir . '/twig/twig/src/Node/Expression/NameExpression.php',
166
+ 'Twig\\Node\\Expression\\NullCoalesceExpression' => $vendorDir . '/twig/twig/src/Node/Expression/NullCoalesceExpression.php',
167
+ 'Twig\\Node\\Expression\\ParentExpression' => $vendorDir . '/twig/twig/src/Node/Expression/ParentExpression.php',
168
+ 'Twig\\Node\\Expression\\TempNameExpression' => $vendorDir . '/twig/twig/src/Node/Expression/TempNameExpression.php',
169
+ 'Twig\\Node\\Expression\\TestExpression' => $vendorDir . '/twig/twig/src/Node/Expression/TestExpression.php',
170
+ 'Twig\\Node\\Expression\\Test\\ConstantTest' => $vendorDir . '/twig/twig/src/Node/Expression/Test/ConstantTest.php',
171
+ 'Twig\\Node\\Expression\\Test\\DefinedTest' => $vendorDir . '/twig/twig/src/Node/Expression/Test/DefinedTest.php',
172
+ 'Twig\\Node\\Expression\\Test\\DivisiblebyTest' => $vendorDir . '/twig/twig/src/Node/Expression/Test/DivisiblebyTest.php',
173
+ 'Twig\\Node\\Expression\\Test\\EvenTest' => $vendorDir . '/twig/twig/src/Node/Expression/Test/EvenTest.php',
174
+ 'Twig\\Node\\Expression\\Test\\NullTest' => $vendorDir . '/twig/twig/src/Node/Expression/Test/NullTest.php',
175
+ 'Twig\\Node\\Expression\\Test\\OddTest' => $vendorDir . '/twig/twig/src/Node/Expression/Test/OddTest.php',
176
+ 'Twig\\Node\\Expression\\Test\\SameasTest' => $vendorDir . '/twig/twig/src/Node/Expression/Test/SameasTest.php',
177
+ 'Twig\\Node\\Expression\\Unary\\AbstractUnary' => $vendorDir . '/twig/twig/src/Node/Expression/Unary/AbstractUnary.php',
178
+ 'Twig\\Node\\Expression\\Unary\\NegUnary' => $vendorDir . '/twig/twig/src/Node/Expression/Unary/NegUnary.php',
179
+ 'Twig\\Node\\Expression\\Unary\\NotUnary' => $vendorDir . '/twig/twig/src/Node/Expression/Unary/NotUnary.php',
180
+ 'Twig\\Node\\Expression\\Unary\\PosUnary' => $vendorDir . '/twig/twig/src/Node/Expression/Unary/PosUnary.php',
181
+ 'Twig\\Node\\FlushNode' => $vendorDir . '/twig/twig/src/Node/FlushNode.php',
182
+ 'Twig\\Node\\ForLoopNode' => $vendorDir . '/twig/twig/src/Node/ForLoopNode.php',
183
+ 'Twig\\Node\\ForNode' => $vendorDir . '/twig/twig/src/Node/ForNode.php',
184
+ 'Twig\\Node\\IfNode' => $vendorDir . '/twig/twig/src/Node/IfNode.php',
185
+ 'Twig\\Node\\ImportNode' => $vendorDir . '/twig/twig/src/Node/ImportNode.php',
186
+ 'Twig\\Node\\IncludeNode' => $vendorDir . '/twig/twig/src/Node/IncludeNode.php',
187
+ 'Twig\\Node\\MacroNode' => $vendorDir . '/twig/twig/src/Node/MacroNode.php',
188
+ 'Twig\\Node\\ModuleNode' => $vendorDir . '/twig/twig/src/Node/ModuleNode.php',
189
+ 'Twig\\Node\\Node' => $vendorDir . '/twig/twig/src/Node/Node.php',
190
+ 'Twig\\Node\\NodeCaptureInterface' => $vendorDir . '/twig/twig/src/Node/NodeCaptureInterface.php',
191
+ 'Twig\\Node\\NodeOutputInterface' => $vendorDir . '/twig/twig/src/Node/NodeOutputInterface.php',
192
+ 'Twig\\Node\\PrintNode' => $vendorDir . '/twig/twig/src/Node/PrintNode.php',
193
+ 'Twig\\Node\\SandboxNode' => $vendorDir . '/twig/twig/src/Node/SandboxNode.php',
194
+ 'Twig\\Node\\SandboxedPrintNode' => $vendorDir . '/twig/twig/src/Node/SandboxedPrintNode.php',
195
+ 'Twig\\Node\\SetNode' => $vendorDir . '/twig/twig/src/Node/SetNode.php',
196
+ 'Twig\\Node\\SetTempNode' => $vendorDir . '/twig/twig/src/Node/SetTempNode.php',
197
+ 'Twig\\Node\\SpacelessNode' => $vendorDir . '/twig/twig/src/Node/SpacelessNode.php',
198
+ 'Twig\\Node\\TextNode' => $vendorDir . '/twig/twig/src/Node/TextNode.php',
199
+ 'Twig\\Node\\WithNode' => $vendorDir . '/twig/twig/src/Node/WithNode.php',
200
+ 'Twig\\Parser' => $vendorDir . '/twig/twig/src/Parser.php',
201
+ 'Twig\\Profiler\\Dumper\\BaseDumper' => $vendorDir . '/twig/twig/src/Profiler/Dumper/BaseDumper.php',
202
+ 'Twig\\Profiler\\Dumper\\BlackfireDumper' => $vendorDir . '/twig/twig/src/Profiler/Dumper/BlackfireDumper.php',
203
+ 'Twig\\Profiler\\Dumper\\HtmlDumper' => $vendorDir . '/twig/twig/src/Profiler/Dumper/HtmlDumper.php',
204
+ 'Twig\\Profiler\\Dumper\\TextDumper' => $vendorDir . '/twig/twig/src/Profiler/Dumper/TextDumper.php',
205
+ 'Twig\\Profiler\\NodeVisitor\\ProfilerNodeVisitor' => $vendorDir . '/twig/twig/src/Profiler/NodeVisitor/ProfilerNodeVisitor.php',
206
+ 'Twig\\Profiler\\Node\\EnterProfileNode' => $vendorDir . '/twig/twig/src/Profiler/Node/EnterProfileNode.php',
207
+ 'Twig\\Profiler\\Node\\LeaveProfileNode' => $vendorDir . '/twig/twig/src/Profiler/Node/LeaveProfileNode.php',
208
+ 'Twig\\Profiler\\Profile' => $vendorDir . '/twig/twig/src/Profiler/Profile.php',
209
+ 'Twig\\RuntimeLoader\\ContainerRuntimeLoader' => $vendorDir . '/twig/twig/src/RuntimeLoader/ContainerRuntimeLoader.php',
210
+ 'Twig\\RuntimeLoader\\FactoryRuntimeLoader' => $vendorDir . '/twig/twig/src/RuntimeLoader/FactoryRuntimeLoader.php',
211
+ 'Twig\\RuntimeLoader\\RuntimeLoaderInterface' => $vendorDir . '/twig/twig/src/RuntimeLoader/RuntimeLoaderInterface.php',
212
+ 'Twig\\Sandbox\\SecurityError' => $vendorDir . '/twig/twig/src/Sandbox/SecurityError.php',
213
+ 'Twig\\Sandbox\\SecurityNotAllowedFilterError' => $vendorDir . '/twig/twig/src/Sandbox/SecurityNotAllowedFilterError.php',
214
+ 'Twig\\Sandbox\\SecurityNotAllowedFunctionError' => $vendorDir . '/twig/twig/src/Sandbox/SecurityNotAllowedFunctionError.php',
215
+ 'Twig\\Sandbox\\SecurityNotAllowedMethodError' => $vendorDir . '/twig/twig/src/Sandbox/SecurityNotAllowedMethodError.php',
216
+ 'Twig\\Sandbox\\SecurityNotAllowedPropertyError' => $vendorDir . '/twig/twig/src/Sandbox/SecurityNotAllowedPropertyError.php',
217
+ 'Twig\\Sandbox\\SecurityNotAllowedTagError' => $vendorDir . '/twig/twig/src/Sandbox/SecurityNotAllowedTagError.php',
218
+ 'Twig\\Sandbox\\SecurityPolicy' => $vendorDir . '/twig/twig/src/Sandbox/SecurityPolicy.php',
219
+ 'Twig\\Sandbox\\SecurityPolicyInterface' => $vendorDir . '/twig/twig/src/Sandbox/SecurityPolicyInterface.php',
220
+ 'Twig\\Source' => $vendorDir . '/twig/twig/src/Source.php',
221
+ 'Twig\\Template' => $vendorDir . '/twig/twig/src/Template.php',
222
+ 'Twig\\TemplateWrapper' => $vendorDir . '/twig/twig/src/TemplateWrapper.php',
223
+ 'Twig\\Test\\IntegrationTestCase' => $vendorDir . '/twig/twig/src/Test/IntegrationTestCase.php',
224
+ 'Twig\\Test\\NodeTestCase' => $vendorDir . '/twig/twig/src/Test/NodeTestCase.php',
225
+ 'Twig\\Token' => $vendorDir . '/twig/twig/src/Token.php',
226
+ 'Twig\\TokenParser\\AbstractTokenParser' => $vendorDir . '/twig/twig/src/TokenParser/AbstractTokenParser.php',
227
+ 'Twig\\TokenParser\\AutoEscapeTokenParser' => $vendorDir . '/twig/twig/src/TokenParser/AutoEscapeTokenParser.php',
228
+ 'Twig\\TokenParser\\BlockTokenParser' => $vendorDir . '/twig/twig/src/TokenParser/BlockTokenParser.php',
229
+ 'Twig\\TokenParser\\DoTokenParser' => $vendorDir . '/twig/twig/src/TokenParser/DoTokenParser.php',
230
+ 'Twig\\TokenParser\\EmbedTokenParser' => $vendorDir . '/twig/twig/src/TokenParser/EmbedTokenParser.php',
231
+ 'Twig\\TokenParser\\ExtendsTokenParser' => $vendorDir . '/twig/twig/src/TokenParser/ExtendsTokenParser.php',
232
+ 'Twig\\TokenParser\\FilterTokenParser' => $vendorDir . '/twig/twig/src/TokenParser/FilterTokenParser.php',
233
+ 'Twig\\TokenParser\\FlushTokenParser' => $vendorDir . '/twig/twig/src/TokenParser/FlushTokenParser.php',
234
+ 'Twig\\TokenParser\\ForTokenParser' => $vendorDir . '/twig/twig/src/TokenParser/ForTokenParser.php',
235
+ 'Twig\\TokenParser\\FromTokenParser' => $vendorDir . '/twig/twig/src/TokenParser/FromTokenParser.php',
236
+ 'Twig\\TokenParser\\IfTokenParser' => $vendorDir . '/twig/twig/src/TokenParser/IfTokenParser.php',
237
+ 'Twig\\TokenParser\\ImportTokenParser' => $vendorDir . '/twig/twig/src/TokenParser/ImportTokenParser.php',
238
+ 'Twig\\TokenParser\\IncludeTokenParser' => $vendorDir . '/twig/twig/src/TokenParser/IncludeTokenParser.php',
239
+ 'Twig\\TokenParser\\MacroTokenParser' => $vendorDir . '/twig/twig/src/TokenParser/MacroTokenParser.php',
240
+ 'Twig\\TokenParser\\SandboxTokenParser' => $vendorDir . '/twig/twig/src/TokenParser/SandboxTokenParser.php',
241
+ 'Twig\\TokenParser\\SetTokenParser' => $vendorDir . '/twig/twig/src/TokenParser/SetTokenParser.php',
242
+ 'Twig\\TokenParser\\SpacelessTokenParser' => $vendorDir . '/twig/twig/src/TokenParser/SpacelessTokenParser.php',
243
+ 'Twig\\TokenParser\\TokenParserInterface' => $vendorDir . '/twig/twig/src/TokenParser/TokenParserInterface.php',
244
+ 'Twig\\TokenParser\\UseTokenParser' => $vendorDir . '/twig/twig/src/TokenParser/UseTokenParser.php',
245
+ 'Twig\\TokenParser\\WithTokenParser' => $vendorDir . '/twig/twig/src/TokenParser/WithTokenParser.php',
246
+ 'Twig\\TokenStream' => $vendorDir . '/twig/twig/src/TokenStream.php',
247
+ 'Twig\\TwigFilter' => $vendorDir . '/twig/twig/src/TwigFilter.php',
248
+ 'Twig\\TwigFunction' => $vendorDir . '/twig/twig/src/TwigFunction.php',
249
+ 'Twig\\TwigTest' => $vendorDir . '/twig/twig/src/TwigTest.php',
250
+ 'Twig\\Util\\DeprecationCollector' => $vendorDir . '/twig/twig/src/Util/DeprecationCollector.php',
251
+ 'Twig\\Util\\TemplateDirIterator' => $vendorDir . '/twig/twig/src/Util/TemplateDirIterator.php',
252
+ 'Twig_Autoloader' => $vendorDir . '/twig/twig/lib/Twig/Autoloader.php',
253
+ 'Twig_BaseNodeVisitor' => $vendorDir . '/twig/twig/lib/Twig/BaseNodeVisitor.php',
254
+ 'Twig_CacheInterface' => $vendorDir . '/twig/twig/lib/Twig/CacheInterface.php',
255
+ 'Twig_Cache_Filesystem' => $vendorDir . '/twig/twig/lib/Twig/Cache/Filesystem.php',
256
+ 'Twig_Cache_Null' => $vendorDir . '/twig/twig/lib/Twig/Cache/Null.php',
257
+ 'Twig_Compiler' => $vendorDir . '/twig/twig/lib/Twig/Compiler.php',
258
+ 'Twig_CompilerInterface' => $vendorDir . '/twig/twig/lib/Twig/CompilerInterface.php',
259
+ 'Twig_ContainerRuntimeLoader' => $vendorDir . '/twig/twig/lib/Twig/ContainerRuntimeLoader.php',
260
+ 'Twig_Environment' => $vendorDir . '/twig/twig/lib/Twig/Environment.php',
261
+ 'Twig_Error' => $vendorDir . '/twig/twig/lib/Twig/Error.php',
262
+ 'Twig_Error_Loader' => $vendorDir . '/twig/twig/lib/Twig/Error/Loader.php',
263
+ 'Twig_Error_Runtime' => $vendorDir . '/twig/twig/lib/Twig/Error/Runtime.php',
264
+ 'Twig_Error_Syntax' => $vendorDir . '/twig/twig/lib/Twig/Error/Syntax.php',
265
+ 'Twig_ExistsLoaderInterface' => $vendorDir . '/twig/twig/lib/Twig/ExistsLoaderInterface.php',
266
+ 'Twig_ExpressionParser' => $vendorDir . '/twig/twig/lib/Twig/ExpressionParser.php',
267
+ 'Twig_Extension' => $vendorDir . '/twig/twig/lib/Twig/Extension.php',
268
+ 'Twig_ExtensionInterface' => $vendorDir . '/twig/twig/lib/Twig/ExtensionInterface.php',
269
+ 'Twig_Extension_Core' => $vendorDir . '/twig/twig/lib/Twig/Extension/Core.php',
270
+ 'Twig_Extension_Debug' => $vendorDir . '/twig/twig/lib/Twig/Extension/Debug.php',
271
+ 'Twig_Extension_Escaper' => $vendorDir . '/twig/twig/lib/Twig/Extension/Escaper.php',
272
+ 'Twig_Extension_GlobalsInterface' => $vendorDir . '/twig/twig/lib/Twig/Extension/GlobalsInterface.php',
273
+ 'Twig_Extension_InitRuntimeInterface' => $vendorDir . '/twig/twig/lib/Twig/Extension/InitRuntimeInterface.php',
274
+ 'Twig_Extension_Optimizer' => $vendorDir . '/twig/twig/lib/Twig/Extension/Optimizer.php',
275
+ 'Twig_Extension_Profiler' => $vendorDir . '/twig/twig/lib/Twig/Extension/Profiler.php',
276
+ 'Twig_Extension_Sandbox' => $vendorDir . '/twig/twig/lib/Twig/Extension/Sandbox.php',
277
+ 'Twig_Extension_Staging' => $vendorDir . '/twig/twig/lib/Twig/Extension/Staging.php',
278
+ 'Twig_Extension_StringLoader' => $vendorDir . '/twig/twig/lib/Twig/Extension/StringLoader.php',
279
+ 'Twig_FactoryRuntimeLoader' => $vendorDir . '/twig/twig/lib/Twig/FactoryRuntimeLoader.php',
280
+ 'Twig_FileExtensionEscapingStrategy' => $vendorDir . '/twig/twig/lib/Twig/FileExtensionEscapingStrategy.php',
281
+ 'Twig_Filter' => $vendorDir . '/twig/twig/lib/Twig/Filter.php',
282
+ 'Twig_FilterCallableInterface' => $vendorDir . '/twig/twig/lib/Twig/FilterCallableInterface.php',
283
+ 'Twig_FilterInterface' => $vendorDir . '/twig/twig/lib/Twig/FilterInterface.php',
284
+ 'Twig_Filter_Function' => $vendorDir . '/twig/twig/lib/Twig/Filter/Function.php',
285
+ 'Twig_Filter_Method' => $vendorDir . '/twig/twig/lib/Twig/Filter/Method.php',
286
+ 'Twig_Filter_Node' => $vendorDir . '/twig/twig/lib/Twig/Filter/Node.php',
287
+ 'Twig_Function' => $vendorDir . '/twig/twig/lib/Twig/Function.php',
288
+ 'Twig_FunctionCallableInterface' => $vendorDir . '/twig/twig/lib/Twig/FunctionCallableInterface.php',
289
+ 'Twig_FunctionInterface' => $vendorDir . '/twig/twig/lib/Twig/FunctionInterface.php',
290
+ 'Twig_Function_Function' => $vendorDir . '/twig/twig/lib/Twig/Function/Function.php',
291
+ 'Twig_Function_Method' => $vendorDir . '/twig/twig/lib/Twig/Function/Method.php',
292
+ 'Twig_Function_Node' => $vendorDir . '/twig/twig/lib/Twig/Function/Node.php',
293
+ 'Twig_Lexer' => $vendorDir . '/twig/twig/lib/Twig/Lexer.php',
294
+ 'Twig_LexerInterface' => $vendorDir . '/twig/twig/lib/Twig/LexerInterface.php',
295
+ 'Twig_LoaderInterface' => $vendorDir . '/twig/twig/lib/Twig/LoaderInterface.php',
296
+ 'Twig_Loader_Array' => $vendorDir . '/twig/twig/lib/Twig/Loader/Array.php',
297
+ 'Twig_Loader_Chain' => $vendorDir . '/twig/twig/lib/Twig/Loader/Chain.php',
298
+ 'Twig_Loader_Filesystem' => $vendorDir . '/twig/twig/lib/Twig/Loader/Filesystem.php',
299
+ 'Twig_Loader_String' => $vendorDir . '/twig/twig/lib/Twig/Loader/String.php',
300
+ 'Twig_Markup' => $vendorDir . '/twig/twig/lib/Twig/Markup.php',
301
+ 'Twig_Node' => $vendorDir . '/twig/twig/lib/Twig/Node.php',
302
+ 'Twig_NodeCaptureInterface' => $vendorDir . '/twig/twig/lib/Twig/NodeCaptureInterface.php',
303
+ 'Twig_NodeInterface' => $vendorDir . '/twig/twig/lib/Twig/NodeInterface.php',
304
+ 'Twig_NodeOutputInterface' => $vendorDir . '/twig/twig/lib/Twig/NodeOutputInterface.php',
305
+ 'Twig_NodeTraverser' => $vendorDir . '/twig/twig/lib/Twig/NodeTraverser.php',
306
+ 'Twig_NodeVisitorInterface' => $vendorDir . '/twig/twig/lib/Twig/NodeVisitorInterface.php',
307
+ 'Twig_NodeVisitor_Escaper' => $vendorDir . '/twig/twig/lib/Twig/NodeVisitor/Escaper.php',
308
+ 'Twig_NodeVisitor_Optimizer' => $vendorDir . '/twig/twig/lib/Twig/NodeVisitor/Optimizer.php',
309
+ 'Twig_NodeVisitor_SafeAnalysis' => $vendorDir . '/twig/twig/lib/Twig/NodeVisitor/SafeAnalysis.php',
310
+ 'Twig_NodeVisitor_Sandbox' => $vendorDir . '/twig/twig/lib/Twig/NodeVisitor/Sandbox.php',
311
+ 'Twig_Node_AutoEscape' => $vendorDir . '/twig/twig/lib/Twig/Node/AutoEscape.php',
312
+ 'Twig_Node_Block' => $vendorDir . '/twig/twig/lib/Twig/Node/Block.php',
313
+ 'Twig_Node_BlockReference' => $vendorDir . '/twig/twig/lib/Twig/Node/BlockReference.php',
314
+ 'Twig_Node_Body' => $vendorDir . '/twig/twig/lib/Twig/Node/Body.php',
315
+ 'Twig_Node_CheckSecurity' => $vendorDir . '/twig/twig/lib/Twig/Node/CheckSecurity.php',
316
+ 'Twig_Node_Do' => $vendorDir . '/twig/twig/lib/Twig/Node/Do.php',
317
+ 'Twig_Node_Embed' => $vendorDir . '/twig/twig/lib/Twig/Node/Embed.php',
318
+ 'Twig_Node_Expression' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression.php',
319
+ 'Twig_Node_Expression_Array' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Array.php',
320
+ 'Twig_Node_Expression_AssignName' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/AssignName.php',
321
+ 'Twig_Node_Expression_Binary' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Binary.php',
322
+ 'Twig_Node_Expression_Binary_Add' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Binary/Add.php',
323
+ 'Twig_Node_Expression_Binary_And' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Binary/And.php',
324
+ 'Twig_Node_Expression_Binary_BitwiseAnd' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseAnd.php',
325
+ 'Twig_Node_Expression_Binary_BitwiseOr' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseOr.php',
326
+ 'Twig_Node_Expression_Binary_BitwiseXor' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseXor.php',
327
+ 'Twig_Node_Expression_Binary_Concat' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Binary/Concat.php',
328
+ 'Twig_Node_Expression_Binary_Div' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Binary/Div.php',
329
+ 'Twig_Node_Expression_Binary_EndsWith' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Binary/EndsWith.php',
330
+ 'Twig_Node_Expression_Binary_Equal' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Binary/Equal.php',
331
+ 'Twig_Node_Expression_Binary_FloorDiv' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Binary/FloorDiv.php',
332
+ 'Twig_Node_Expression_Binary_Greater' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Binary/Greater.php',
333
+ 'Twig_Node_Expression_Binary_GreaterEqual' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Binary/GreaterEqual.php',
334
+ 'Twig_Node_Expression_Binary_In' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Binary/In.php',
335
+ 'Twig_Node_Expression_Binary_Less' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Binary/Less.php',
336
+ 'Twig_Node_Expression_Binary_LessEqual' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Binary/LessEqual.php',
337
+ 'Twig_Node_Expression_Binary_Matches' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Binary/Matches.php',
338
+ 'Twig_Node_Expression_Binary_Mod' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Binary/Mod.php',
339
+ 'Twig_Node_Expression_Binary_Mul' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Binary/Mul.php',
340
+ 'Twig_Node_Expression_Binary_NotEqual' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Binary/NotEqual.php',
341
+ 'Twig_Node_Expression_Binary_NotIn' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Binary/NotIn.php',
342
+ 'Twig_Node_Expression_Binary_Or' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Binary/Or.php',
343
+ 'Twig_Node_Expression_Binary_Power' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Binary/Power.php',
344
+ 'Twig_Node_Expression_Binary_Range' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Binary/Range.php',
345
+ 'Twig_Node_Expression_Binary_StartsWith' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Binary/StartsWith.php',
346
+ 'Twig_Node_Expression_Binary_Sub' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Binary/Sub.php',
347
+ 'Twig_Node_Expression_BlockReference' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/BlockReference.php',
348
+ 'Twig_Node_Expression_Call' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Call.php',
349
+ 'Twig_Node_Expression_Conditional' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Conditional.php',
350
+ 'Twig_Node_Expression_Constant' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Constant.php',
351
+ 'Twig_Node_Expression_ExtensionReference' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/ExtensionReference.php',
352
+ 'Twig_Node_Expression_Filter' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Filter.php',
353
+ 'Twig_Node_Expression_Filter_Default' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Filter/Default.php',
354
+ 'Twig_Node_Expression_Function' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Function.php',
355
+ 'Twig_Node_Expression_GetAttr' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/GetAttr.php',
356
+ 'Twig_Node_Expression_MethodCall' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/MethodCall.php',
357
+ 'Twig_Node_Expression_Name' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Name.php',
358
+ 'Twig_Node_Expression_NullCoalesce' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/NullCoalesce.php',
359
+ 'Twig_Node_Expression_Parent' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Parent.php',
360
+ 'Twig_Node_Expression_TempName' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/TempName.php',
361
+ 'Twig_Node_Expression_Test' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Test.php',
362
+ 'Twig_Node_Expression_Test_Constant' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Test/Constant.php',
363
+ 'Twig_Node_Expression_Test_Defined' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Test/Defined.php',
364
+ 'Twig_Node_Expression_Test_Divisibleby' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Test/Divisibleby.php',
365
+ 'Twig_Node_Expression_Test_Even' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Test/Even.php',
366
+ 'Twig_Node_Expression_Test_Null' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Test/Null.php',
367
+ 'Twig_Node_Expression_Test_Odd' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Test/Odd.php',
368
+ 'Twig_Node_Expression_Test_Sameas' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Test/Sameas.php',
369
+ 'Twig_Node_Expression_Unary' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Unary.php',
370
+ 'Twig_Node_Expression_Unary_Neg' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Unary/Neg.php',
371
+ 'Twig_Node_Expression_Unary_Not' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Unary/Not.php',
372
+ 'Twig_Node_Expression_Unary_Pos' => $vendorDir . '/twig/twig/lib/Twig/Node/Expression/Unary/Pos.php',
373
+ 'Twig_Node_Flush' => $vendorDir . '/twig/twig/lib/Twig/Node/Flush.php',
374
+ 'Twig_Node_For' => $vendorDir . '/twig/twig/lib/Twig/Node/For.php',
375
+ 'Twig_Node_ForLoop' => $vendorDir . '/twig/twig/lib/Twig/Node/ForLoop.php',
376
+ 'Twig_Node_If' => $vendorDir . '/twig/twig/lib/Twig/Node/If.php',
377
+ 'Twig_Node_Import' => $vendorDir . '/twig/twig/lib/Twig/Node/Import.php',
378
+ 'Twig_Node_Include' => $vendorDir . '/twig/twig/lib/Twig/Node/Include.php',
379
+ 'Twig_Node_Macro' => $vendorDir . '/twig/twig/lib/Twig/Node/Macro.php',
380
+ 'Twig_Node_Module' => $vendorDir . '/twig/twig/lib/Twig/Node/Module.php',
381
+ 'Twig_Node_Print' => $vendorDir . '/twig/twig/lib/Twig/Node/Print.php',
382
+ 'Twig_Node_Sandbox' => $vendorDir . '/twig/twig/lib/Twig/Node/Sandbox.php',
383
+ 'Twig_Node_SandboxedPrint' => $vendorDir . '/twig/twig/lib/Twig/Node/SandboxedPrint.php',
384
+ 'Twig_Node_Set' => $vendorDir . '/twig/twig/lib/Twig/Node/Set.php',
385
+ 'Twig_Node_SetTemp' => $vendorDir . '/twig/twig/lib/Twig/Node/SetTemp.php',
386
+ 'Twig_Node_Spaceless' => $vendorDir . '/twig/twig/lib/Twig/Node/Spaceless.php',
387
+ 'Twig_Node_Text' => $vendorDir . '/twig/twig/lib/Twig/Node/Text.php',
388
+ 'Twig_Node_With' => $vendorDir . '/twig/twig/lib/Twig/Node/With.php',
389
+ 'Twig_Parser' => $vendorDir . '/twig/twig/lib/Twig/Parser.php',
390
+ 'Twig_ParserInterface' => $vendorDir . '/twig/twig/lib/Twig/ParserInterface.php',
391
+ 'Twig_Profiler_Dumper_Base' => $vendorDir . '/twig/twig/lib/Twig/Profiler/Dumper/Base.php',
392
+ 'Twig_Profiler_Dumper_Blackfire' => $vendorDir . '/twig/twig/lib/Twig/Profiler/Dumper/Blackfire.php',
393
+ 'Twig_Profiler_Dumper_Html' => $vendorDir . '/twig/twig/lib/Twig/Profiler/Dumper/Html.php',
394
+ 'Twig_Profiler_Dumper_Text' => $vendorDir . '/twig/twig/lib/Twig/Profiler/Dumper/Text.php',
395
+ 'Twig_Profiler_NodeVisitor_Profiler' => $vendorDir . '/twig/twig/lib/Twig/Profiler/NodeVisitor/Profiler.php',
396
+ 'Twig_Profiler_Node_EnterProfile' => $vendorDir . '/twig/twig/lib/Twig/Profiler/Node/EnterProfile.php',
397
+ 'Twig_Profiler_Node_LeaveProfile' => $vendorDir . '/twig/twig/lib/Twig/Profiler/Node/LeaveProfile.php',
398
+ 'Twig_Profiler_Profile' => $vendorDir . '/twig/twig/lib/Twig/Profiler/Profile.php',
399
+ 'Twig_RuntimeLoaderInterface' => $vendorDir . '/twig/twig/lib/Twig/RuntimeLoaderInterface.php',
400
+ 'Twig_Sandbox_SecurityError' => $vendorDir . '/twig/twig/lib/Twig/Sandbox/SecurityError.php',
401
+ 'Twig_Sandbox_SecurityNotAllowedFilterError' => $vendorDir . '/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedFilterError.php',
402
+ 'Twig_Sandbox_SecurityNotAllowedFunctionError' => $vendorDir . '/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedFunctionError.php',
403
+ 'Twig_Sandbox_SecurityNotAllowedMethodError' => $vendorDir . '/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedMethodError.php',
404
+ 'Twig_Sandbox_SecurityNotAllowedPropertyError' => $vendorDir . '/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedPropertyError.php',
405
+ 'Twig_Sandbox_SecurityNotAllowedTagError' => $vendorDir . '/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedTagError.php',
406
+ 'Twig_Sandbox_SecurityPolicy' => $vendorDir . '/twig/twig/lib/Twig/Sandbox/SecurityPolicy.php',
407
+ 'Twig_Sandbox_SecurityPolicyInterface' => $vendorDir . '/twig/twig/lib/Twig/Sandbox/SecurityPolicyInterface.php',
408
+ 'Twig_SimpleFilter' => $vendorDir . '/twig/twig/lib/Twig/SimpleFilter.php',
409
+ 'Twig_SimpleFunction' => $vendorDir . '/twig/twig/lib/Twig/SimpleFunction.php',
410
+ 'Twig_SimpleTest' => $vendorDir . '/twig/twig/lib/Twig/SimpleTest.php',
411
+ 'Twig_Source' => $vendorDir . '/twig/twig/lib/Twig/Source.php',
412
+ 'Twig_SourceContextLoaderInterface' => $vendorDir . '/twig/twig/lib/Twig/SourceContextLoaderInterface.php',
413
+ 'Twig_Template' => $vendorDir . '/twig/twig/lib/Twig/Template.php',
414
+ 'Twig_TemplateInterface' => $vendorDir . '/twig/twig/lib/Twig/TemplateInterface.php',
415
+ 'Twig_TemplateWrapper' => $vendorDir . '/twig/twig/lib/Twig/TemplateWrapper.php',
416
+ 'Twig_Test' => $vendorDir . '/twig/twig/lib/Twig/Test.php',
417
+ 'Twig_TestCallableInterface' => $vendorDir . '/twig/twig/lib/Twig/TestCallableInterface.php',
418
+ 'Twig_TestInterface' => $vendorDir . '/twig/twig/lib/Twig/TestInterface.php',
419
+ 'Twig_Test_Function' => $vendorDir . '/twig/twig/lib/Twig/Test/Function.php',
420
+ 'Twig_Test_IntegrationTestCase' => $vendorDir . '/twig/twig/lib/Twig/Test/IntegrationTestCase.php',
421
+ 'Twig_Test_Method' => $vendorDir . '/twig/twig/lib/Twig/Test/Method.php',
422
+ 'Twig_Test_Node' => $vendorDir . '/twig/twig/lib/Twig/Test/Node.php',
423
+ 'Twig_Test_NodeTestCase' => $vendorDir . '/twig/twig/lib/Twig/Test/NodeTestCase.php',
424
+ 'Twig_Token' => $vendorDir . '/twig/twig/lib/Twig/Token.php',
425
+ 'Twig_TokenParser' => $vendorDir . '/twig/twig/lib/Twig/TokenParser.php',
426
+ 'Twig_TokenParserBroker' => $vendorDir . '/twig/twig/lib/Twig/TokenParserBroker.php',
427
+ 'Twig_TokenParserBrokerInterface' => $vendorDir . '/twig/twig/lib/Twig/TokenParserBrokerInterface.php',
428
+ 'Twig_TokenParserInterface' => $vendorDir . '/twig/twig/lib/Twig/TokenParserInterface.php',
429
+ 'Twig_TokenParser_AutoEscape' => $vendorDir . '/twig/twig/lib/Twig/TokenParser/AutoEscape.php',
430
+ 'Twig_TokenParser_Block' => $vendorDir . '/twig/twig/lib/Twig/TokenParser/Block.php',
431
+ 'Twig_TokenParser_Do' => $vendorDir . '/twig/twig/lib/Twig/TokenParser/Do.php',
432
+ 'Twig_TokenParser_Embed' => $vendorDir . '/twig/twig/lib/Twig/TokenParser/Embed.php',
433
+ 'Twig_TokenParser_Extends' => $vendorDir . '/twig/twig/lib/Twig/TokenParser/Extends.php',
434
+ 'Twig_TokenParser_Filter' => $vendorDir . '/twig/twig/lib/Twig/TokenParser/Filter.php',
435
+ 'Twig_TokenParser_Flush' => $vendorDir . '/twig/twig/lib/Twig/TokenParser/Flush.php',
436
+ 'Twig_TokenParser_For' => $vendorDir . '/twig/twig/lib/Twig/TokenParser/For.php',
437
+ 'Twig_TokenParser_From' => $vendorDir . '/twig/twig/lib/Twig/TokenParser/From.php',
438
+ 'Twig_TokenParser_If' => $vendorDir . '/twig/twig/lib/Twig/TokenParser/If.php',
439
+ 'Twig_TokenParser_Import' => $vendorDir . '/twig/twig/lib/Twig/TokenParser/Import.php',
440
+ 'Twig_TokenParser_Include' => $vendorDir . '/twig/twig/lib/Twig/TokenParser/Include.php',
441
+ 'Twig_TokenParser_Macro' => $vendorDir . '/twig/twig/lib/Twig/TokenParser/Macro.php',
442
+ 'Twig_TokenParser_Sandbox' => $vendorDir . '/twig/twig/lib/Twig/TokenParser/Sandbox.php',
443
+ 'Twig_TokenParser_Set' => $vendorDir . '/twig/twig/lib/Twig/TokenParser/Set.php',
444
+ 'Twig_TokenParser_Spaceless' => $vendorDir . '/twig/twig/lib/Twig/TokenParser/Spaceless.php',
445
+ 'Twig_TokenParser_Use' => $vendorDir . '/twig/twig/lib/Twig/TokenParser/Use.php',
446
+ 'Twig_TokenParser_With' => $vendorDir . '/twig/twig/lib/Twig/TokenParser/With.php',
447
+ 'Twig_TokenStream' => $vendorDir . '/twig/twig/lib/Twig/TokenStream.php',
448
+ 'Twig_Util_DeprecationCollector' => $vendorDir . '/twig/twig/lib/Twig/Util/DeprecationCollector.php',
449
+ 'Twig_Util_TemplateDirIterator' => $vendorDir . '/twig/twig/lib/Twig/Util/TemplateDirIterator.php',
450
  );
src/common/lib/vendor/composer/autoload_static.php CHANGED
@@ -63,12 +63,457 @@ class ComposerStaticInit18a31866e67f0a0bfffdc031786ecae1
63
  ),
64
  );
65
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  public static function getInitializer(ClassLoader $loader)
67
  {
68
  return \Closure::bind(function () use ($loader) {
69
  $loader->prefixLengthsPsr4 = ComposerStaticInit18a31866e67f0a0bfffdc031786ecae1::$prefixLengthsPsr4;
70
  $loader->prefixDirsPsr4 = ComposerStaticInit18a31866e67f0a0bfffdc031786ecae1::$prefixDirsPsr4;
71
  $loader->prefixesPsr0 = ComposerStaticInit18a31866e67f0a0bfffdc031786ecae1::$prefixesPsr0;
 
72
 
73
  }, null, ClassLoader::class);
74
  }
63
  ),
64
  );
65
 
66
+ public static $classMap = array (
67
+ 'Carbon\\Carbon' => __DIR__ . '/..' . '/nesbot/carbon/src/Carbon/Carbon.php',
68
+ 'Carbon\\CarbonInterval' => __DIR__ . '/..' . '/nesbot/carbon/src/Carbon/CarbonInterval.php',
69
+ 'Carbon\\Exceptions\\InvalidDateException' => __DIR__ . '/..' . '/nesbot/carbon/src/Carbon/Exceptions/InvalidDateException.php',
70
+ 'FernleafSystems\\Utilities\\Data\\Adapter\\StdClassAdapter' => __DIR__ . '/..' . '/fernleafsystems/utilities/src/Data/Adapter/StdClassAdapter.php',
71
+ 'FernleafSystems\\Utilities\\Response' => __DIR__ . '/..' . '/fernleafsystems/utilities/src/Response.php',
72
+ 'Symfony\\Component\\Translation\\Catalogue\\AbstractOperation' => __DIR__ . '/..' . '/symfony/translation/Catalogue/AbstractOperation.php',
73
+ 'Symfony\\Component\\Translation\\Catalogue\\MergeOperation' => __DIR__ . '/..' . '/symfony/translation/Catalogue/MergeOperation.php',
74
+ 'Symfony\\Component\\Translation\\Catalogue\\OperationInterface' => __DIR__ . '/..' . '/symfony/translation/Catalogue/OperationInterface.php',
75
+ 'Symfony\\Component\\Translation\\Catalogue\\TargetOperation' => __DIR__ . '/..' . '/symfony/translation/Catalogue/TargetOperation.php',
76
+ 'Symfony\\Component\\Translation\\Command\\XliffLintCommand' => __DIR__ . '/..' . '/symfony/translation/Command/XliffLintCommand.php',
77
+ 'Symfony\\Component\\Translation\\DataCollectorTranslator' => __DIR__ . '/..' . '/symfony/translation/DataCollectorTranslator.php',
78
+ 'Symfony\\Component\\Translation\\DataCollector\\TranslationDataCollector' => __DIR__ . '/..' . '/symfony/translation/DataCollector/TranslationDataCollector.php',
79
+ 'Symfony\\Component\\Translation\\DependencyInjection\\TranslationDumperPass' => __DIR__ . '/..' . '/symfony/translation/DependencyInjection/TranslationDumperPass.php',
80
+ 'Symfony\\Component\\Translation\\DependencyInjection\\TranslationExtractorPass' => __DIR__ . '/..' . '/symfony/translation/DependencyInjection/TranslationExtractorPass.php',
81
+ 'Symfony\\Component\\Translation\\DependencyInjection\\TranslatorPass' => __DIR__ . '/..' . '/symfony/translation/DependencyInjection/TranslatorPass.php',
82
+ 'Symfony\\Component\\Translation\\Dumper\\CsvFileDumper' => __DIR__ . '/..' . '/symfony/translation/Dumper/CsvFileDumper.php',
83
+ 'Symfony\\Component\\Translation\\Dumper\\DumperInterface' => __DIR__ . '/..' . '/symfony/translation/Dumper/DumperInterface.php',
84
+ 'Symfony\\Component\\Translation\\Dumper\\FileDumper' => __DIR__ . '/..' . '/symfony/translation/Dumper/FileDumper.php',
85
+ 'Symfony\\Component\\Translation\\Dumper\\IcuResFileDumper' => __DIR__ . '/..' . '/symfony/translation/Dumper/IcuResFileDumper.php',
86
+ 'Symfony\\Component\\Translation\\Dumper\\IniFileDumper' => __DIR__ . '/..' . '/symfony/translation/Dumper/IniFileDumper.php',
87
+ 'Symfony\\Component\\Translation\\Dumper\\JsonFileDumper' => __DIR__ . '/..' . '/symfony/translation/Dumper/JsonFileDumper.php',
88
+ 'Symfony\\Component\\Translation\\Dumper\\MoFileDumper' => __DIR__ . '/..' . '/symfony/translation/Dumper/MoFileDumper.php',
89
+ 'Symfony\\Component\\Translation\\Dumper\\PhpFileDumper' => __DIR__ . '/..' . '/symfony/translation/Dumper/PhpFileDumper.php',
90
+ 'Symfony\\Component\\Translation\\Dumper\\PoFileDumper' => __DIR__ . '/..' . '/symfony/translation/Dumper/PoFileDumper.php',
91
+ 'Symfony\\Component\\Translation\\Dumper\\QtFileDumper' => __DIR__ . '/..' . '/symfony/translation/Dumper/QtFileDumper.php',
92
+ 'Symfony\\Component\\Translation\\Dumper\\XliffFileDumper' => __DIR__ . '/..' . '/symfony/translation/Dumper/XliffFileDumper.php',
93
+ 'Symfony\\Component\\Translation\\Dumper\\YamlFileDumper' => __DIR__ . '/..' . '/symfony/translation/Dumper/YamlFileDumper.php',
94
+ 'Symfony\\Component\\Translation\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/translation/Exception/ExceptionInterface.php',
95
+ 'Symfony\\Component\\Translation\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/translation/Exception/InvalidArgumentException.php',
96
+ 'Symfony\\Component\\Translation\\Exception\\InvalidResourceException' => __DIR__ . '/..' . '/symfony/translation/Exception/InvalidResourceException.php',
97
+ 'Symfony\\Component\\Translation\\Exception\\LogicException' => __DIR__ . '/..' . '/symfony/translation/Exception/LogicException.php',
98
+ 'Symfony\\Component\\Translation\\Exception\\NotFoundResourceException' => __DIR__ . '/..' . '/symfony/translation/Exception/NotFoundResourceException.php',
99
+ 'Symfony\\Component\\Translation\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/translation/Exception/RuntimeException.php',
100
+ 'Symfony\\Component\\Translation\\Extractor\\AbstractFileExtractor' => __DIR__ . '/..' . '/symfony/translation/Extractor/AbstractFileExtractor.php',
101
+ 'Symfony\\Component\\Translation\\Extractor\\ChainExtractor' => __DIR__ . '/..' . '/symfony/translation/Extractor/ChainExtractor.php',
102
+ 'Symfony\\Component\\Translation\\Extractor\\ExtractorInterface' => __DIR__ . '/..' . '/symfony/translation/Extractor/ExtractorInterface.php',
103
+ 'Symfony\\Component\\Translation\\Extractor\\PhpExtractor' => __DIR__ . '/..' . '/symfony/translation/Extractor/PhpExtractor.php',
104
+ 'Symfony\\Component\\Translation\\Extractor\\PhpStringTokenParser' => __DIR__ . '/..' . '/symfony/translation/Extractor/PhpStringTokenParser.php',
105
+ 'Symfony\\Component\\Translation\\Formatter\\ChoiceMessageFormatterInterface' => __DIR__ . '/..' . '/symfony/translation/Formatter/ChoiceMessageFormatterInterface.php',
106
+ 'Symfony\\Component\\Translation\\Formatter\\MessageFormatter' => __DIR__ . '/..' . '/symfony/translation/Formatter/MessageFormatter.php',
107
+ 'Symfony\\Component\\Translation\\Formatter\\MessageFormatterInterface' => __DIR__ . '/..' . '/symfony/translation/Formatter/MessageFormatterInterface.php',
108
+ 'Symfony\\Component\\Translation\\IdentityTranslator' => __DIR__ . '/..' . '/symfony/translation/IdentityTranslator.php',
109
+ 'Symfony\\Component\\Translation\\Interval' => __DIR__ . '/..' . '/symfony/translation/Interval.php',
110
+ 'Symfony\\Component\\Translation\\Loader\\ArrayLoader' => __DIR__ . '/..' . '/symfony/translation/Loader/ArrayLoader.php',
111
+ 'Symfony\\Component\\Translation\\Loader\\CsvFileLoader' => __DIR__ . '/..' . '/symfony/translation/Loader/CsvFileLoader.php',
112
+ 'Symfony\\Component\\Translation\\Loader\\FileLoader' => __DIR__ . '/..' . '/symfony/translation/Loader/FileLoader.php',
113
+ 'Symfony\\Component\\Translation\\Loader\\IcuDatFileLoader' => __DIR__ . '/..' . '/symfony/translation/Loader/IcuDatFileLoader.php',
114
+ 'Symfony\\Component\\Translation\\Loader\\IcuResFileLoader' => __DIR__ . '/..' . '/symfony/translation/Loader/IcuResFileLoader.php',
115
+ 'Symfony\\Component\\Translation\\Loader\\IniFileLoader' => __DIR__ . '/..' . '/symfony/translation/Loader/IniFileLoader.php',
116
+ 'Symfony\\Component\\Translation\\Loader\\JsonFileLoader' => __DIR__ . '/..' . '/symfony/translation/Loader/JsonFileLoader.php',
117
+ 'Symfony\\Component\\Translation\\Loader\\LoaderInterface' => __DIR__ . '/..' . '/symfony/translation/Loader/LoaderInterface.php',
118
+ 'Symfony\\Component\\Translation\\Loader\\MoFileLoader' => __DIR__ . '/..' . '/symfony/translation/Loader/MoFileLoader.php',
119
+ 'Symfony\\Component\\Translation\\Loader\\PhpFileLoader' => __DIR__ . '/..' . '/symfony/translation/Loader/PhpFileLoader.php',
120
+ 'Symfony\\Component\\Translation\\Loader\\PoFileLoader' => __DIR__ . '/..' . '/symfony/translation/Loader/PoFileLoader.php',
121
+ 'Symfony\\Component\\Translation\\Loader\\QtFileLoader' => __DIR__ . '/..' . '/symfony/translation/Loader/QtFileLoader.php',
122
+ 'Symfony\\Component\\Translation\\Loader\\XliffFileLoader' => __DIR__ . '/..' . '/symfony/translation/Loader/XliffFileLoader.php',
123
+ 'Symfony\\Component\\Translation\\Loader\\YamlFileLoader' => __DIR__ . '/..' . '/symfony/translation/Loader/YamlFileLoader.php',
124
+ 'Symfony\\Component\\Translation\\LoggingTranslator' => __DIR__ . '/..' . '/symfony/translation/LoggingTranslator.php',
125
+ 'Symfony\\Component\\Translation\\MessageCatalogue' => __DIR__ . '/..' . '/symfony/translation/MessageCatalogue.php',
126
+ 'Symfony\\Component\\Translation\\MessageCatalogueInterface' => __DIR__ . '/..' . '/symfony/translation/MessageCatalogueInterface.php',
127
+ 'Symfony\\Component\\Translation\\MessageSelector' => __DIR__ . '/..' . '/symfony/translation/MessageSelector.php',
128
+ 'Symfony\\Component\\Translation\\MetadataAwareInterface' => __DIR__ . '/..' . '/symfony/translation/MetadataAwareInterface.php',
129
+ 'Symfony\\Component\\Translation\\PluralizationRules' => __DIR__ . '/..' . '/symfony/translation/PluralizationRules.php',
130
+ 'Symfony\\Component\\Translation\\Reader\\TranslationReader' => __DIR__ . '/..' . '/symfony/translation/Reader/TranslationReader.php',
131
+ 'Symfony\\Component\\Translation\\Reader\\TranslationReaderInterface' => __DIR__ . '/..' . '/symfony/translation/Reader/TranslationReaderInterface.php',
132
+ 'Symfony\\Component\\Translation\\Translator' => __DIR__ . '/..' . '/symfony/translation/Translator.php',
133
+ 'Symfony\\Component\\Translation\\TranslatorBagInterface' => __DIR__ . '/..' . '/symfony/translation/TranslatorBagInterface.php',
134
+ 'Symfony\\Component\\Translation\\TranslatorInterface' => __DIR__ . '/..' . '/symfony/translation/TranslatorInterface.php',
135
+ 'Symfony\\Component\\Translation\\Util\\ArrayConverter' => __DIR__ . '/..' . '/symfony/translation/Util/ArrayConverter.php',
136
+ 'Symfony\\Component\\Translation\\Writer\\TranslationWriter' => __DIR__ . '/..' . '/symfony/translation/Writer/TranslationWriter.php',
137
+ 'Symfony\\Component\\Translation\\Writer\\TranslationWriterInterface' => __DIR__ . '/..' . '/symfony/translation/Writer/TranslationWriterInterface.php',
138
+ 'Symfony\\Polyfill\\Mbstring\\Mbstring' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/Mbstring.php',
139
+ 'Twig\\Cache\\CacheInterface' => __DIR__ . '/..' . '/twig/twig/src/Cache/CacheInterface.php',
140
+ 'Twig\\Cache\\FilesystemCache' => __DIR__ . '/..' . '/twig/twig/src/Cache/FilesystemCache.php',
141
+ 'Twig\\Cache\\NullCache' => __DIR__ . '/..' . '/twig/twig/src/Cache/NullCache.php',
142
+ 'Twig\\Compiler' => __DIR__ . '/..' . '/twig/twig/src/Compiler.php',
143
+ 'Twig\\Environment' => __DIR__ . '/..' . '/twig/twig/src/Environment.php',
144
+ 'Twig\\Error\\Error' => __DIR__ . '/..' . '/twig/twig/src/Error/Error.php',
145
+ 'Twig\\Error\\LoaderError' => __DIR__ . '/..' . '/twig/twig/src/Error/LoaderError.php',
146
+ 'Twig\\Error\\RuntimeError' => __DIR__ . '/..' . '/twig/twig/src/Error/RuntimeError.php',
147
+ 'Twig\\Error\\SyntaxError' => __DIR__ . '/..' . '/twig/twig/src/Error/SyntaxError.php',
148
+ 'Twig\\ExpressionParser' => __DIR__ . '/..' . '/twig/twig/src/ExpressionParser.php',
149
+ 'Twig\\Extension\\AbstractExtension' => __DIR__ . '/..' . '/twig/twig/src/Extension/AbstractExtension.php',
150
+ 'Twig\\Extension\\CoreExtension' => __DIR__ . '/..' . '/twig/twig/src/Extension/CoreExtension.php',
151
+ 'Twig\\Extension\\DebugExtension' => __DIR__ . '/..' . '/twig/twig/src/Extension/DebugExtension.php',
152
+ 'Twig\\Extension\\EscaperExtension' => __DIR__ . '/..' . '/twig/twig/src/Extension/EscaperExtension.php',
153
+ 'Twig\\Extension\\ExtensionInterface' => __DIR__ . '/..' . '/twig/twig/src/Extension/ExtensionInterface.php',
154
+ 'Twig\\Extension\\GlobalsInterface' => __DIR__ . '/..' . '/twig/twig/src/Extension/GlobalsInterface.php',
155
+ 'Twig\\Extension\\InitRuntimeInterface' => __DIR__ . '/..' . '/twig/twig/src/Extension/InitRuntimeInterface.php',
156
+ 'Twig\\Extension\\OptimizerExtension' => __DIR__ . '/..' . '/twig/twig/src/Extension/OptimizerExtension.php',
157
+ 'Twig\\Extension\\ProfilerExtension' => __DIR__ . '/..' . '/twig/twig/src/Extension/ProfilerExtension.php',
158
+ 'Twig\\Extension\\RuntimeExtensionInterface' => __DIR__ . '/..' . '/twig/twig/src/Extension/RuntimeExtensionInterface.php',
159
+ 'Twig\\Extension\\SandboxExtension' => __DIR__ . '/..' . '/twig/twig/src/Extension/SandboxExtension.php',
160
+ 'Twig\\Extension\\StagingExtension' => __DIR__ . '/..' . '/twig/twig/src/Extension/StagingExtension.php',
161
+ 'Twig\\Extension\\StringLoaderExtension' => __DIR__ . '/..' . '/twig/twig/src/Extension/StringLoaderExtension.php',
162
+ 'Twig\\FileExtensionEscapingStrategy' => __DIR__ . '/..' . '/twig/twig/src/FileExtensionEscapingStrategy.php',
163
+ 'Twig\\Lexer' => __DIR__ . '/..' . '/twig/twig/src/Lexer.php',
164
+ 'Twig\\Loader\\ArrayLoader' => __DIR__ . '/..' . '/twig/twig/src/Loader/ArrayLoader.php',
165
+ 'Twig\\Loader\\ChainLoader' => __DIR__ . '/..' . '/twig/twig/src/Loader/ChainLoader.php',
166
+ 'Twig\\Loader\\ExistsLoaderInterface' => __DIR__ . '/..' . '/twig/twig/src/Loader/ExistsLoaderInterface.php',
167
+ 'Twig\\Loader\\FilesystemLoader' => __DIR__ . '/..' . '/twig/twig/src/Loader/FilesystemLoader.php',
168
+ 'Twig\\Loader\\LoaderInterface' => __DIR__ . '/..' . '/twig/twig/src/Loader/LoaderInterface.php',
169
+ 'Twig\\Loader\\SourceContextLoaderInterface' => __DIR__ . '/..' . '/twig/twig/src/Loader/SourceContextLoaderInterface.php',
170
+ 'Twig\\Markup' => __DIR__ . '/..' . '/twig/twig/src/Markup.php',
171
+ 'Twig\\NodeTraverser' => __DIR__ . '/..' . '/twig/twig/src/NodeTraverser.php',
172
+ 'Twig\\NodeVisitor\\AbstractNodeVisitor' => __DIR__ . '/..' . '/twig/twig/src/NodeVisitor/AbstractNodeVisitor.php',
173
+ 'Twig\\NodeVisitor\\EscaperNodeVisitor' => __DIR__ . '/..' . '/twig/twig/src/NodeVisitor/EscaperNodeVisitor.php',
174
+ 'Twig\\NodeVisitor\\NodeVisitorInterface' => __DIR__ . '/..' . '/twig/twig/src/NodeVisitor/NodeVisitorInterface.php',
175
+ 'Twig\\NodeVisitor\\OptimizerNodeVisitor' => __DIR__ . '/..' . '/twig/twig/src/NodeVisitor/OptimizerNodeVisitor.php',
176
+ 'Twig\\NodeVisitor\\SafeAnalysisNodeVisitor' => __DIR__ . '/..' . '/twig/twig/src/NodeVisitor/SafeAnalysisNodeVisitor.php',
177
+ 'Twig\\NodeVisitor\\SandboxNodeVisitor' => __DIR__ . '/..' . '/twig/twig/src/NodeVisitor/SandboxNodeVisitor.php',
178
+ 'Twig\\Node\\AutoEscapeNode' => __DIR__ . '/..' . '/twig/twig/src/Node/AutoEscapeNode.php',
179
+ 'Twig\\Node\\BlockNode' => __DIR__ . '/..' . '/twig/twig/src/Node/BlockNode.php',
180
+ 'Twig\\Node\\BlockReferenceNode' => __DIR__ . '/..' . '/twig/twig/src/Node/BlockReferenceNode.php',
181
+ 'Twig\\Node\\BodyNode' => __DIR__ . '/..' . '/twig/twig/src/Node/BodyNode.php',
182
+ 'Twig\\Node\\CheckSecurityNode' => __DIR__ . '/..' . '/twig/twig/src/Node/CheckSecurityNode.php',
183
+ 'Twig\\Node\\DoNode' => __DIR__ . '/..' . '/twig/twig/src/Node/DoNode.php',
184
+ 'Twig\\Node\\EmbedNode' => __DIR__ . '/..' . '/twig/twig/src/Node/EmbedNode.php',
185
+ 'Twig\\Node\\Expression\\AbstractExpression' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/AbstractExpression.php',
186
+ 'Twig\\Node\\Expression\\ArrayExpression' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/ArrayExpression.php',
187
+ 'Twig\\Node\\Expression\\AssignNameExpression' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/AssignNameExpression.php',
188
+ 'Twig\\Node\\Expression\\Binary\\AbstractBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/AbstractBinary.php',
189
+ 'Twig\\Node\\Expression\\Binary\\AddBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/AddBinary.php',
190
+ 'Twig\\Node\\Expression\\Binary\\AndBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/AndBinary.php',
191
+ 'Twig\\Node\\Expression\\Binary\\BitwiseAndBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/BitwiseAndBinary.php',
192
+ 'Twig\\Node\\Expression\\Binary\\BitwiseOrBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/BitwiseOrBinary.php',
193
+ 'Twig\\Node\\Expression\\Binary\\BitwiseXorBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/BitwiseXorBinary.php',
194
+ 'Twig\\Node\\Expression\\Binary\\ConcatBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/ConcatBinary.php',
195
+ 'Twig\\Node\\Expression\\Binary\\DivBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/DivBinary.php',
196
+ 'Twig\\Node\\Expression\\Binary\\EndsWithBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/EndsWithBinary.php',
197
+ 'Twig\\Node\\Expression\\Binary\\EqualBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/EqualBinary.php',
198
+ 'Twig\\Node\\Expression\\Binary\\FloorDivBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/FloorDivBinary.php',
199
+ 'Twig\\Node\\Expression\\Binary\\GreaterBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/GreaterBinary.php',
200
+ 'Twig\\Node\\Expression\\Binary\\GreaterEqualBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/GreaterEqualBinary.php',
201
+ 'Twig\\Node\\Expression\\Binary\\InBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/InBinary.php',
202
+ 'Twig\\Node\\Expression\\Binary\\LessBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/LessBinary.php',
203
+ 'Twig\\Node\\Expression\\Binary\\LessEqualBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/LessEqualBinary.php',
204
+ 'Twig\\Node\\Expression\\Binary\\MatchesBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/MatchesBinary.php',
205
+ 'Twig\\Node\\Expression\\Binary\\ModBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/ModBinary.php',
206
+ 'Twig\\Node\\Expression\\Binary\\MulBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/MulBinary.php',
207
+ 'Twig\\Node\\Expression\\Binary\\NotEqualBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/NotEqualBinary.php',
208
+ 'Twig\\Node\\Expression\\Binary\\NotInBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/NotInBinary.php',
209
+ 'Twig\\Node\\Expression\\Binary\\OrBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/OrBinary.php',
210
+ 'Twig\\Node\\Expression\\Binary\\PowerBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/PowerBinary.php',
211
+ 'Twig\\Node\\Expression\\Binary\\RangeBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/RangeBinary.php',
212
+ 'Twig\\Node\\Expression\\Binary\\StartsWithBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/StartsWithBinary.php',
213
+ 'Twig\\Node\\Expression\\Binary\\SubBinary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Binary/SubBinary.php',
214
+ 'Twig\\Node\\Expression\\BlockReferenceExpression' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/BlockReferenceExpression.php',
215
+ 'Twig\\Node\\Expression\\CallExpression' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/CallExpression.php',
216
+ 'Twig\\Node\\Expression\\ConditionalExpression' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/ConditionalExpression.php',
217
+ 'Twig\\Node\\Expression\\ConstantExpression' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/ConstantExpression.php',
218
+ 'Twig\\Node\\Expression\\FilterExpression' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/FilterExpression.php',
219
+ 'Twig\\Node\\Expression\\Filter\\DefaultFilter' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Filter/DefaultFilter.php',
220
+ 'Twig\\Node\\Expression\\FunctionExpression' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/FunctionExpression.php',
221
+ 'Twig\\Node\\Expression\\GetAttrExpression' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/GetAttrExpression.php',
222
+ 'Twig\\Node\\Expression\\MethodCallExpression' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/MethodCallExpression.php',
223
+ 'Twig\\Node\\Expression\\NameExpression' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/NameExpression.php',
224
+ 'Twig\\Node\\Expression\\NullCoalesceExpression' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/NullCoalesceExpression.php',
225
+ 'Twig\\Node\\Expression\\ParentExpression' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/ParentExpression.php',
226
+ 'Twig\\Node\\Expression\\TempNameExpression' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/TempNameExpression.php',
227
+ 'Twig\\Node\\Expression\\TestExpression' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/TestExpression.php',
228
+ 'Twig\\Node\\Expression\\Test\\ConstantTest' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Test/ConstantTest.php',
229
+ 'Twig\\Node\\Expression\\Test\\DefinedTest' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Test/DefinedTest.php',
230
+ 'Twig\\Node\\Expression\\Test\\DivisiblebyTest' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Test/DivisiblebyTest.php',
231
+ 'Twig\\Node\\Expression\\Test\\EvenTest' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Test/EvenTest.php',
232
+ 'Twig\\Node\\Expression\\Test\\NullTest' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Test/NullTest.php',
233
+ 'Twig\\Node\\Expression\\Test\\OddTest' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Test/OddTest.php',
234
+ 'Twig\\Node\\Expression\\Test\\SameasTest' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Test/SameasTest.php',
235
+ 'Twig\\Node\\Expression\\Unary\\AbstractUnary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Unary/AbstractUnary.php',
236
+ 'Twig\\Node\\Expression\\Unary\\NegUnary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Unary/NegUnary.php',
237
+ 'Twig\\Node\\Expression\\Unary\\NotUnary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Unary/NotUnary.php',
238
+ 'Twig\\Node\\Expression\\Unary\\PosUnary' => __DIR__ . '/..' . '/twig/twig/src/Node/Expression/Unary/PosUnary.php',
239
+ 'Twig\\Node\\FlushNode' => __DIR__ . '/..' . '/twig/twig/src/Node/FlushNode.php',
240
+ 'Twig\\Node\\ForLoopNode' => __DIR__ . '/..' . '/twig/twig/src/Node/ForLoopNode.php',
241
+ 'Twig\\Node\\ForNode' => __DIR__ . '/..' . '/twig/twig/src/Node/ForNode.php',
242
+ 'Twig\\Node\\IfNode' => __DIR__ . '/..' . '/twig/twig/src/Node/IfNode.php',
243
+ 'Twig\\Node\\ImportNode' => __DIR__ . '/..' . '/twig/twig/src/Node/ImportNode.php',
244
+ 'Twig\\Node\\IncludeNode' => __DIR__ . '/..' . '/twig/twig/src/Node/IncludeNode.php',
245
+ 'Twig\\Node\\MacroNode' => __DIR__ . '/..' . '/twig/twig/src/Node/MacroNode.php',
246
+ 'Twig\\Node\\ModuleNode' => __DIR__ . '/..' . '/twig/twig/src/Node/ModuleNode.php',
247
+ 'Twig\\Node\\Node' => __DIR__ . '/..' . '/twig/twig/src/Node/Node.php',
248
+ 'Twig\\Node\\NodeCaptureInterface' => __DIR__ . '/..' . '/twig/twig/src/Node/NodeCaptureInterface.php',
249
+ 'Twig\\Node\\NodeOutputInterface' => __DIR__ . '/..' . '/twig/twig/src/Node/NodeOutputInterface.php',
250
+ 'Twig\\Node\\PrintNode' => __DIR__ . '/..' . '/twig/twig/src/Node/PrintNode.php',
251
+ 'Twig\\Node\\SandboxNode' => __DIR__ . '/..' . '/twig/twig/src/Node/SandboxNode.php',
252
+ 'Twig\\Node\\SandboxedPrintNode' => __DIR__ . '/..' . '/twig/twig/src/Node/SandboxedPrintNode.php',
253
+ 'Twig\\Node\\SetNode' => __DIR__ . '/..' . '/twig/twig/src/Node/SetNode.php',
254
+ 'Twig\\Node\\SetTempNode' => __DIR__ . '/..' . '/twig/twig/src/Node/SetTempNode.php',
255
+ 'Twig\\Node\\SpacelessNode' => __DIR__ . '/..' . '/twig/twig/src/Node/SpacelessNode.php',
256
+ 'Twig\\Node\\TextNode' => __DIR__ . '/..' . '/twig/twig/src/Node/TextNode.php',
257
+ 'Twig\\Node\\WithNode' => __DIR__ . '/..' . '/twig/twig/src/Node/WithNode.php',
258
+ 'Twig\\Parser' => __DIR__ . '/..' . '/twig/twig/src/Parser.php',
259
+ 'Twig\\Profiler\\Dumper\\BaseDumper' => __DIR__ . '/..' . '/twig/twig/src/Profiler/Dumper/BaseDumper.php',
260
+ 'Twig\\Profiler\\Dumper\\BlackfireDumper' => __DIR__ . '/..' . '/twig/twig/src/Profiler/Dumper/BlackfireDumper.php',
261
+ 'Twig\\Profiler\\Dumper\\HtmlDumper' => __DIR__ . '/..' . '/twig/twig/src/Profiler/Dumper/HtmlDumper.php',
262
+ 'Twig\\Profiler\\Dumper\\TextDumper' => __DIR__ . '/..' . '/twig/twig/src/Profiler/Dumper/TextDumper.php',
263
+ 'Twig\\Profiler\\NodeVisitor\\ProfilerNodeVisitor' => __DIR__ . '/..' . '/twig/twig/src/Profiler/NodeVisitor/ProfilerNodeVisitor.php',
264
+ 'Twig\\Profiler\\Node\\EnterProfileNode' => __DIR__ . '/..' . '/twig/twig/src/Profiler/Node/EnterProfileNode.php',
265
+ 'Twig\\Profiler\\Node\\LeaveProfileNode' => __DIR__ . '/..' . '/twig/twig/src/Profiler/Node/LeaveProfileNode.php',
266
+ 'Twig\\Profiler\\Profile' => __DIR__ . '/..' . '/twig/twig/src/Profiler/Profile.php',
267
+ 'Twig\\RuntimeLoader\\ContainerRuntimeLoader' => __DIR__ . '/..' . '/twig/twig/src/RuntimeLoader/ContainerRuntimeLoader.php',
268
+ 'Twig\\RuntimeLoader\\FactoryRuntimeLoader' => __DIR__ . '/..' . '/twig/twig/src/RuntimeLoader/FactoryRuntimeLoader.php',
269
+ 'Twig\\RuntimeLoader\\RuntimeLoaderInterface' => __DIR__ . '/..' . '/twig/twig/src/RuntimeLoader/RuntimeLoaderInterface.php',
270
+ 'Twig\\Sandbox\\SecurityError' => __DIR__ . '/..' . '/twig/twig/src/Sandbox/SecurityError.php',
271
+ 'Twig\\Sandbox\\SecurityNotAllowedFilterError' => __DIR__ . '/..' . '/twig/twig/src/Sandbox/SecurityNotAllowedFilterError.php',
272
+ 'Twig\\Sandbox\\SecurityNotAllowedFunctionError' => __DIR__ . '/..' . '/twig/twig/src/Sandbox/SecurityNotAllowedFunctionError.php',
273
+ 'Twig\\Sandbox\\SecurityNotAllowedMethodError' => __DIR__ . '/..' . '/twig/twig/src/Sandbox/SecurityNotAllowedMethodError.php',
274
+ 'Twig\\Sandbox\\SecurityNotAllowedPropertyError' => __DIR__ . '/..' . '/twig/twig/src/Sandbox/SecurityNotAllowedPropertyError.php',
275
+ 'Twig\\Sandbox\\SecurityNotAllowedTagError' => __DIR__ . '/..' . '/twig/twig/src/Sandbox/SecurityNotAllowedTagError.php',
276
+ 'Twig\\Sandbox\\SecurityPolicy' => __DIR__ . '/..' . '/twig/twig/src/Sandbox/SecurityPolicy.php',
277
+ 'Twig\\Sandbox\\SecurityPolicyInterface' => __DIR__ . '/..' . '/twig/twig/src/Sandbox/SecurityPolicyInterface.php',
278
+ 'Twig\\Source' => __DIR__ . '/..' . '/twig/twig/src/Source.php',
279
+ 'Twig\\Template' => __DIR__ . '/..' . '/twig/twig/src/Template.php',
280
+ 'Twig\\TemplateWrapper' => __DIR__ . '/..' . '/twig/twig/src/TemplateWrapper.php',
281
+ 'Twig\\Test\\IntegrationTestCase' => __DIR__ . '/..' . '/twig/twig/src/Test/IntegrationTestCase.php',
282
+ 'Twig\\Test\\NodeTestCase' => __DIR__ . '/..' . '/twig/twig/src/Test/NodeTestCase.php',
283
+ 'Twig\\Token' => __DIR__ . '/..' . '/twig/twig/src/Token.php',
284
+ 'Twig\\TokenParser\\AbstractTokenParser' => __DIR__ . '/..' . '/twig/twig/src/TokenParser/AbstractTokenParser.php',
285
+ 'Twig\\TokenParser\\AutoEscapeTokenParser' => __DIR__ . '/..' . '/twig/twig/src/TokenParser/AutoEscapeTokenParser.php',
286
+ 'Twig\\TokenParser\\BlockTokenParser' => __DIR__ . '/..' . '/twig/twig/src/TokenParser/BlockTokenParser.php',
287
+ 'Twig\\TokenParser\\DoTokenParser' => __DIR__ . '/..' . '/twig/twig/src/TokenParser/DoTokenParser.php',
288
+ 'Twig\\TokenParser\\EmbedTokenParser' => __DIR__ . '/..' . '/twig/twig/src/TokenParser/EmbedTokenParser.php',
289
+ 'Twig\\TokenParser\\ExtendsTokenParser' => __DIR__ . '/..' . '/twig/twig/src/TokenParser/ExtendsTokenParser.php',
290
+ 'Twig\\TokenParser\\FilterTokenParser' => __DIR__ . '/..' . '/twig/twig/src/TokenParser/FilterTokenParser.php',
291
+ 'Twig\\TokenParser\\FlushTokenParser' => __DIR__ . '/..' . '/twig/twig/src/TokenParser/FlushTokenParser.php',
292
+ 'Twig\\TokenParser\\ForTokenParser' => __DIR__ . '/..' . '/twig/twig/src/TokenParser/ForTokenParser.php',
293
+ 'Twig\\TokenParser\\FromTokenParser' => __DIR__ . '/..' . '/twig/twig/src/TokenParser/FromTokenParser.php',
294
+ 'Twig\\TokenParser\\IfTokenParser' => __DIR__ . '/..' . '/twig/twig/src/TokenParser/IfTokenParser.php',
295
+ 'Twig\\TokenParser\\ImportTokenParser' => __DIR__ . '/..' . '/twig/twig/src/TokenParser/ImportTokenParser.php',
296
+ 'Twig\\TokenParser\\IncludeTokenParser' => __DIR__ . '/..' . '/twig/twig/src/TokenParser/IncludeTokenParser.php',
297
+ 'Twig\\TokenParser\\MacroTokenParser' => __DIR__ . '/..' . '/twig/twig/src/TokenParser/MacroTokenParser.php',
298
+ 'Twig\\TokenParser\\SandboxTokenParser' => __DIR__ . '/..' . '/twig/twig/src/TokenParser/SandboxTokenParser.php',
299
+ 'Twig\\TokenParser\\SetTokenParser' => __DIR__ . '/..' . '/twig/twig/src/TokenParser/SetTokenParser.php',
300
+ 'Twig\\TokenParser\\SpacelessTokenParser' => __DIR__ . '/..' . '/twig/twig/src/TokenParser/SpacelessTokenParser.php',
301
+ 'Twig\\TokenParser\\TokenParserInterface' => __DIR__ . '/..' . '/twig/twig/src/TokenParser/TokenParserInterface.php',
302
+ 'Twig\\TokenParser\\UseTokenParser' => __DIR__ . '/..' . '/twig/twig/src/TokenParser/UseTokenParser.php',
303
+ 'Twig\\TokenParser\\WithTokenParser' => __DIR__ . '/..' . '/twig/twig/src/TokenParser/WithTokenParser.php',
304
+ 'Twig\\TokenStream' => __DIR__ . '/..' . '/twig/twig/src/TokenStream.php',
305
+ 'Twig\\TwigFilter' => __DIR__ . '/..' . '/twig/twig/src/TwigFilter.php',
306
+ 'Twig\\TwigFunction' => __DIR__ . '/..' . '/twig/twig/src/TwigFunction.php',
307
+ 'Twig\\TwigTest' => __DIR__ . '/..' . '/twig/twig/src/TwigTest.php',
308
+ 'Twig\\Util\\DeprecationCollector' => __DIR__ . '/..' . '/twig/twig/src/Util/DeprecationCollector.php',
309
+ 'Twig\\Util\\TemplateDirIterator' => __DIR__ . '/..' . '/twig/twig/src/Util/TemplateDirIterator.php',
310
+ 'Twig_Autoloader' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Autoloader.php',
311
+ 'Twig_BaseNodeVisitor' => __DIR__ . '/..' . '/twig/twig/lib/Twig/BaseNodeVisitor.php',
312
+ 'Twig_CacheInterface' => __DIR__ . '/..' . '/twig/twig/lib/Twig/CacheInterface.php',
313
+ 'Twig_Cache_Filesystem' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Cache/Filesystem.php',
314
+ 'Twig_Cache_Null' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Cache/Null.php',
315
+ 'Twig_Compiler' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Compiler.php',
316
+ 'Twig_CompilerInterface' => __DIR__ . '/..' . '/twig/twig/lib/Twig/CompilerInterface.php',
317
+ 'Twig_ContainerRuntimeLoader' => __DIR__ . '/..' . '/twig/twig/lib/Twig/ContainerRuntimeLoader.php',
318
+ 'Twig_Environment' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Environment.php',
319
+ 'Twig_Error' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Error.php',
320
+ 'Twig_Error_Loader' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Error/Loader.php',
321
+ 'Twig_Error_Runtime' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Error/Runtime.php',
322
+ 'Twig_Error_Syntax' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Error/Syntax.php',
323
+ 'Twig_ExistsLoaderInterface' => __DIR__ . '/..' . '/twig/twig/lib/Twig/ExistsLoaderInterface.php',
324
+ 'Twig_ExpressionParser' => __DIR__ . '/..' . '/twig/twig/lib/Twig/ExpressionParser.php',
325
+ 'Twig_Extension' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Extension.php',
326
+ 'Twig_ExtensionInterface' => __DIR__ . '/..' . '/twig/twig/lib/Twig/ExtensionInterface.php',
327
+ 'Twig_Extension_Core' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Extension/Core.php',
328
+ 'Twig_Extension_Debug' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Extension/Debug.php',
329
+ 'Twig_Extension_Escaper' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Extension/Escaper.php',
330
+ 'Twig_Extension_GlobalsInterface' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Extension/GlobalsInterface.php',
331
+ 'Twig_Extension_InitRuntimeInterface' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Extension/InitRuntimeInterface.php',
332
+ 'Twig_Extension_Optimizer' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Extension/Optimizer.php',
333
+ 'Twig_Extension_Profiler' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Extension/Profiler.php',
334
+ 'Twig_Extension_Sandbox' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Extension/Sandbox.php',
335
+ 'Twig_Extension_Staging' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Extension/Staging.php',
336
+ 'Twig_Extension_StringLoader' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Extension/StringLoader.php',
337
+ 'Twig_FactoryRuntimeLoader' => __DIR__ . '/..' . '/twig/twig/lib/Twig/FactoryRuntimeLoader.php',
338
+ 'Twig_FileExtensionEscapingStrategy' => __DIR__ . '/..' . '/twig/twig/lib/Twig/FileExtensionEscapingStrategy.php',
339
+ 'Twig_Filter' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Filter.php',
340
+ 'Twig_FilterCallableInterface' => __DIR__ . '/..' . '/twig/twig/lib/Twig/FilterCallableInterface.php',
341
+ 'Twig_FilterInterface' => __DIR__ . '/..' . '/twig/twig/lib/Twig/FilterInterface.php',
342
+ 'Twig_Filter_Function' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Filter/Function.php',
343
+ 'Twig_Filter_Method' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Filter/Method.php',
344
+ 'Twig_Filter_Node' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Filter/Node.php',
345
+ 'Twig_Function' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Function.php',
346
+ 'Twig_FunctionCallableInterface' => __DIR__ . '/..' . '/twig/twig/lib/Twig/FunctionCallableInterface.php',
347
+ 'Twig_FunctionInterface' => __DIR__ . '/..' . '/twig/twig/lib/Twig/FunctionInterface.php',
348
+ 'Twig_Function_Function' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Function/Function.php',
349
+ 'Twig_Function_Method' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Function/Method.php',
350
+ 'Twig_Function_Node' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Function/Node.php',
351
+ 'Twig_Lexer' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Lexer.php',
352
+ 'Twig_LexerInterface' => __DIR__ . '/..' . '/twig/twig/lib/Twig/LexerInterface.php',
353
+ 'Twig_LoaderInterface' => __DIR__ . '/..' . '/twig/twig/lib/Twig/LoaderInterface.php',
354
+ 'Twig_Loader_Array' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Loader/Array.php',
355
+ 'Twig_Loader_Chain' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Loader/Chain.php',
356
+ 'Twig_Loader_Filesystem' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Loader/Filesystem.php',
357
+ 'Twig_Loader_String' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Loader/String.php',
358
+ 'Twig_Markup' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Markup.php',
359
+ 'Twig_Node' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node.php',
360
+ 'Twig_NodeCaptureInterface' => __DIR__ . '/..' . '/twig/twig/lib/Twig/NodeCaptureInterface.php',
361
+ 'Twig_NodeInterface' => __DIR__ . '/..' . '/twig/twig/lib/Twig/NodeInterface.php',
362
+ 'Twig_NodeOutputInterface' => __DIR__ . '/..' . '/twig/twig/lib/Twig/NodeOutputInterface.php',
363
+ 'Twig_NodeTraverser' => __DIR__ . '/..' . '/twig/twig/lib/Twig/NodeTraverser.php',
364
+ 'Twig_NodeVisitorInterface' => __DIR__ . '/..' . '/twig/twig/lib/Twig/NodeVisitorInterface.php',
365
+ 'Twig_NodeVisitor_Escaper' => __DIR__ . '/..' . '/twig/twig/lib/Twig/NodeVisitor/Escaper.php',
366
+ 'Twig_NodeVisitor_Optimizer' => __DIR__ . '/..' . '/twig/twig/lib/Twig/NodeVisitor/Optimizer.php',
367
+ 'Twig_NodeVisitor_SafeAnalysis' => __DIR__ . '/..' . '/twig/twig/lib/Twig/NodeVisitor/SafeAnalysis.php',
368
+ 'Twig_NodeVisitor_Sandbox' => __DIR__ . '/..' . '/twig/twig/lib/Twig/NodeVisitor/Sandbox.php',
369
+ 'Twig_Node_AutoEscape' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/AutoEscape.php',
370
+ 'Twig_Node_Block' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Block.php',
371
+ 'Twig_Node_BlockReference' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/BlockReference.php',
372
+ 'Twig_Node_Body' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Body.php',
373
+ 'Twig_Node_CheckSecurity' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/CheckSecurity.php',
374
+ 'Twig_Node_Do' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Do.php',
375
+ 'Twig_Node_Embed' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Embed.php',
376
+ 'Twig_Node_Expression' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression.php',
377
+ 'Twig_Node_Expression_Array' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Array.php',
378
+ 'Twig_Node_Expression_AssignName' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/AssignName.php',
379
+ 'Twig_Node_Expression_Binary' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Binary.php',
380
+ 'Twig_Node_Expression_Binary_Add' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Binary/Add.php',
381
+ 'Twig_Node_Expression_Binary_And' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Binary/And.php',
382
+ 'Twig_Node_Expression_Binary_BitwiseAnd' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseAnd.php',
383
+ 'Twig_Node_Expression_Binary_BitwiseOr' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseOr.php',
384
+ 'Twig_Node_Expression_Binary_BitwiseXor' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Binary/BitwiseXor.php',
385
+ 'Twig_Node_Expression_Binary_Concat' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Binary/Concat.php',
386
+ 'Twig_Node_Expression_Binary_Div' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Binary/Div.php',
387
+ 'Twig_Node_Expression_Binary_EndsWith' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Binary/EndsWith.php',
388
+ 'Twig_Node_Expression_Binary_Equal' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Binary/Equal.php',
389
+ 'Twig_Node_Expression_Binary_FloorDiv' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Binary/FloorDiv.php',
390
+ 'Twig_Node_Expression_Binary_Greater' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Binary/Greater.php',
391
+ 'Twig_Node_Expression_Binary_GreaterEqual' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Binary/GreaterEqual.php',
392
+ 'Twig_Node_Expression_Binary_In' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Binary/In.php',
393
+ 'Twig_Node_Expression_Binary_Less' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Binary/Less.php',
394
+ 'Twig_Node_Expression_Binary_LessEqual' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Binary/LessEqual.php',
395
+ 'Twig_Node_Expression_Binary_Matches' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Binary/Matches.php',
396
+ 'Twig_Node_Expression_Binary_Mod' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Binary/Mod.php',
397
+ 'Twig_Node_Expression_Binary_Mul' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Binary/Mul.php',
398
+ 'Twig_Node_Expression_Binary_NotEqual' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Binary/NotEqual.php',
399
+ 'Twig_Node_Expression_Binary_NotIn' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Binary/NotIn.php',
400
+ 'Twig_Node_Expression_Binary_Or' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Binary/Or.php',
401
+ 'Twig_Node_Expression_Binary_Power' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Binary/Power.php',
402
+ 'Twig_Node_Expression_Binary_Range' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Binary/Range.php',
403
+ 'Twig_Node_Expression_Binary_StartsWith' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Binary/StartsWith.php',
404
+ 'Twig_Node_Expression_Binary_Sub' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Binary/Sub.php',
405
+ 'Twig_Node_Expression_BlockReference' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/BlockReference.php',
406
+ 'Twig_Node_Expression_Call' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Call.php',
407
+ 'Twig_Node_Expression_Conditional' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Conditional.php',
408
+ 'Twig_Node_Expression_Constant' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Constant.php',
409
+ 'Twig_Node_Expression_ExtensionReference' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/ExtensionReference.php',
410
+ 'Twig_Node_Expression_Filter' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Filter.php',
411
+ 'Twig_Node_Expression_Filter_Default' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Filter/Default.php',
412
+ 'Twig_Node_Expression_Function' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Function.php',
413
+ 'Twig_Node_Expression_GetAttr' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/GetAttr.php',
414
+ 'Twig_Node_Expression_MethodCall' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/MethodCall.php',
415
+ 'Twig_Node_Expression_Name' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Name.php',
416
+ 'Twig_Node_Expression_NullCoalesce' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/NullCoalesce.php',
417
+ 'Twig_Node_Expression_Parent' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Parent.php',
418
+ 'Twig_Node_Expression_TempName' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/TempName.php',
419
+ 'Twig_Node_Expression_Test' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Test.php',
420
+ 'Twig_Node_Expression_Test_Constant' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Test/Constant.php',
421
+ 'Twig_Node_Expression_Test_Defined' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Test/Defined.php',
422
+ 'Twig_Node_Expression_Test_Divisibleby' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Test/Divisibleby.php',
423
+ 'Twig_Node_Expression_Test_Even' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Test/Even.php',
424
+ 'Twig_Node_Expression_Test_Null' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Test/Null.php',
425
+ 'Twig_Node_Expression_Test_Odd' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Test/Odd.php',
426
+ 'Twig_Node_Expression_Test_Sameas' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Test/Sameas.php',
427
+ 'Twig_Node_Expression_Unary' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Unary.php',
428
+ 'Twig_Node_Expression_Unary_Neg' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Unary/Neg.php',
429
+ 'Twig_Node_Expression_Unary_Not' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Unary/Not.php',
430
+ 'Twig_Node_Expression_Unary_Pos' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Expression/Unary/Pos.php',
431
+ 'Twig_Node_Flush' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Flush.php',
432
+ 'Twig_Node_For' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/For.php',
433
+ 'Twig_Node_ForLoop' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/ForLoop.php',
434
+ 'Twig_Node_If' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/If.php',
435
+ 'Twig_Node_Import' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Import.php',
436
+ 'Twig_Node_Include' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Include.php',
437
+ 'Twig_Node_Macro' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Macro.php',
438
+ 'Twig_Node_Module' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Module.php',
439
+ 'Twig_Node_Print' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Print.php',
440
+ 'Twig_Node_Sandbox' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Sandbox.php',
441
+ 'Twig_Node_SandboxedPrint' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/SandboxedPrint.php',
442
+ 'Twig_Node_Set' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Set.php',
443
+ 'Twig_Node_SetTemp' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/SetTemp.php',
444
+ 'Twig_Node_Spaceless' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Spaceless.php',
445
+ 'Twig_Node_Text' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/Text.php',
446
+ 'Twig_Node_With' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Node/With.php',
447
+ 'Twig_Parser' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Parser.php',
448
+ 'Twig_ParserInterface' => __DIR__ . '/..' . '/twig/twig/lib/Twig/ParserInterface.php',
449
+ 'Twig_Profiler_Dumper_Base' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Profiler/Dumper/Base.php',
450
+ 'Twig_Profiler_Dumper_Blackfire' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Profiler/Dumper/Blackfire.php',
451
+ 'Twig_Profiler_Dumper_Html' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Profiler/Dumper/Html.php',
452
+ 'Twig_Profiler_Dumper_Text' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Profiler/Dumper/Text.php',
453
+ 'Twig_Profiler_NodeVisitor_Profiler' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Profiler/NodeVisitor/Profiler.php',
454
+ 'Twig_Profiler_Node_EnterProfile' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Profiler/Node/EnterProfile.php',
455
+ 'Twig_Profiler_Node_LeaveProfile' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Profiler/Node/LeaveProfile.php',
456
+ 'Twig_Profiler_Profile' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Profiler/Profile.php',
457
+ 'Twig_RuntimeLoaderInterface' => __DIR__ . '/..' . '/twig/twig/lib/Twig/RuntimeLoaderInterface.php',
458
+ 'Twig_Sandbox_SecurityError' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Sandbox/SecurityError.php',
459
+ 'Twig_Sandbox_SecurityNotAllowedFilterError' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedFilterError.php',
460
+ 'Twig_Sandbox_SecurityNotAllowedFunctionError' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedFunctionError.php',
461
+ 'Twig_Sandbox_SecurityNotAllowedMethodError' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedMethodError.php',
462
+ 'Twig_Sandbox_SecurityNotAllowedPropertyError' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedPropertyError.php',
463
+ 'Twig_Sandbox_SecurityNotAllowedTagError' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Sandbox/SecurityNotAllowedTagError.php',
464
+ 'Twig_Sandbox_SecurityPolicy' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Sandbox/SecurityPolicy.php',
465
+ 'Twig_Sandbox_SecurityPolicyInterface' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Sandbox/SecurityPolicyInterface.php',
466
+ 'Twig_SimpleFilter' => __DIR__ . '/..' . '/twig/twig/lib/Twig/SimpleFilter.php',
467
+ 'Twig_SimpleFunction' => __DIR__ . '/..' . '/twig/twig/lib/Twig/SimpleFunction.php',
468
+ 'Twig_SimpleTest' => __DIR__ . '/..' . '/twig/twig/lib/Twig/SimpleTest.php',
469
+ 'Twig_Source' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Source.php',
470
+ 'Twig_SourceContextLoaderInterface' => __DIR__ . '/..' . '/twig/twig/lib/Twig/SourceContextLoaderInterface.php',
471
+ 'Twig_Template' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Template.php',
472
+ 'Twig_TemplateInterface' => __DIR__ . '/..' . '/twig/twig/lib/Twig/TemplateInterface.php',
473
+ 'Twig_TemplateWrapper' => __DIR__ . '/..' . '/twig/twig/lib/Twig/TemplateWrapper.php',
474
+ 'Twig_Test' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Test.php',
475
+ 'Twig_TestCallableInterface' => __DIR__ . '/..' . '/twig/twig/lib/Twig/TestCallableInterface.php',
476
+ 'Twig_TestInterface' => __DIR__ . '/..' . '/twig/twig/lib/Twig/TestInterface.php',
477
+ 'Twig_Test_Function' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Test/Function.php',
478
+ 'Twig_Test_IntegrationTestCase' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Test/IntegrationTestCase.php',
479
+ 'Twig_Test_Method' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Test/Method.php',
480
+ 'Twig_Test_Node' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Test/Node.php',
481
+ 'Twig_Test_NodeTestCase' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Test/NodeTestCase.php',
482
+ 'Twig_Token' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Token.php',
483
+ 'Twig_TokenParser' => __DIR__ . '/..' . '/twig/twig/lib/Twig/TokenParser.php',
484
+ 'Twig_TokenParserBroker' => __DIR__ . '/..' . '/twig/twig/lib/Twig/TokenParserBroker.php',
485
+ 'Twig_TokenParserBrokerInterface' => __DIR__ . '/..' . '/twig/twig/lib/Twig/TokenParserBrokerInterface.php',
486
+ 'Twig_TokenParserInterface' => __DIR__ . '/..' . '/twig/twig/lib/Twig/TokenParserInterface.php',
487
+ 'Twig_TokenParser_AutoEscape' => __DIR__ . '/..' . '/twig/twig/lib/Twig/TokenParser/AutoEscape.php',
488
+ 'Twig_TokenParser_Block' => __DIR__ . '/..' . '/twig/twig/lib/Twig/TokenParser/Block.php',
489
+ 'Twig_TokenParser_Do' => __DIR__ . '/..' . '/twig/twig/lib/Twig/TokenParser/Do.php',
490
+ 'Twig_TokenParser_Embed' => __DIR__ . '/..' . '/twig/twig/lib/Twig/TokenParser/Embed.php',
491
+ 'Twig_TokenParser_Extends' => __DIR__ . '/..' . '/twig/twig/lib/Twig/TokenParser/Extends.php',
492
+ 'Twig_TokenParser_Filter' => __DIR__ . '/..' . '/twig/twig/lib/Twig/TokenParser/Filter.php',
493
+ 'Twig_TokenParser_Flush' => __DIR__ . '/..' . '/twig/twig/lib/Twig/TokenParser/Flush.php',
494
+ 'Twig_TokenParser_For' => __DIR__ . '/..' . '/twig/twig/lib/Twig/TokenParser/For.php',
495
+ 'Twig_TokenParser_From' => __DIR__ . '/..' . '/twig/twig/lib/Twig/TokenParser/From.php',
496
+ 'Twig_TokenParser_If' => __DIR__ . '/..' . '/twig/twig/lib/Twig/TokenParser/If.php',
497
+ 'Twig_TokenParser_Import' => __DIR__ . '/..' . '/twig/twig/lib/Twig/TokenParser/Import.php',
498
+ 'Twig_TokenParser_Include' => __DIR__ . '/..' . '/twig/twig/lib/Twig/TokenParser/Include.php',
499
+ 'Twig_TokenParser_Macro' => __DIR__ . '/..' . '/twig/twig/lib/Twig/TokenParser/Macro.php',
500
+ 'Twig_TokenParser_Sandbox' => __DIR__ . '/..' . '/twig/twig/lib/Twig/TokenParser/Sandbox.php',
501
+ 'Twig_TokenParser_Set' => __DIR__ . '/..' . '/twig/twig/lib/Twig/TokenParser/Set.php',
502
+ 'Twig_TokenParser_Spaceless' => __DIR__ . '/..' . '/twig/twig/lib/Twig/TokenParser/Spaceless.php',
503
+ 'Twig_TokenParser_Use' => __DIR__ . '/..' . '/twig/twig/lib/Twig/TokenParser/Use.php',
504
+ 'Twig_TokenParser_With' => __DIR__ . '/..' . '/twig/twig/lib/Twig/TokenParser/With.php',
505
+ 'Twig_TokenStream' => __DIR__ . '/..' . '/twig/twig/lib/Twig/TokenStream.php',
506
+ 'Twig_Util_DeprecationCollector' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Util/DeprecationCollector.php',
507
+ 'Twig_Util_TemplateDirIterator' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Util/TemplateDirIterator.php',
508
+ );
509
+
510
  public static function getInitializer(ClassLoader $loader)
511
  {
512
  return \Closure::bind(function () use ($loader) {
513
  $loader->prefixLengthsPsr4 = ComposerStaticInit18a31866e67f0a0bfffdc031786ecae1::$prefixLengthsPsr4;
514
  $loader->prefixDirsPsr4 = ComposerStaticInit18a31866e67f0a0bfffdc031786ecae1::$prefixDirsPsr4;
515
  $loader->prefixesPsr0 = ComposerStaticInit18a31866e67f0a0bfffdc031786ecae1::$prefixesPsr0;
516
+ $loader->classMap = ComposerStaticInit18a31866e67f0a0bfffdc031786ecae1::$classMap;
517
 
518
  }, null, ClassLoader::class);
519
  }
src/common/lib/vendor/composer/installed.json CHANGED
@@ -1,65 +1,4 @@
1
  [
2
- {
3
- "name": "symfony/polyfill-mbstring",
4
- "version": "v1.6.0",
5
- "version_normalized": "1.6.0.0",
6
- "source": {
7
- "type": "git",
8
- "url": "https://github.com/symfony/polyfill-mbstring.git",
9
- "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296"
10
- },
11
- "dist": {
12
- "type": "zip",
13
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296",
14
- "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296",
15
- "shasum": ""
16
- },
17
- "require": {
18
- "php": ">=5.3.3"
19
- },
20
- "suggest": {
21
- "ext-mbstring": "For best performance"
22
- },
23
- "time": "2017-10-11T12:05:26+00:00",
24
- "type": "library",
25
- "extra": {
26
- "branch-alias": {
27
- "dev-master": "1.6-dev"
28
- }
29
- },
30
- "installation-source": "dist",
31
- "autoload": {
32
- "psr-4": {
33
- "Symfony\\Polyfill\\Mbstring\\": ""
34
- },
35
- "files": [
36
- "bootstrap.php"
37
- ]
38
- },
39
- "notification-url": "https://packagist.org/downloads/",
40
- "license": [
41
- "MIT"
42
- ],
43
- "authors": [
44
- {
45
- "name": "Nicolas Grekas",
46
- "email": "p@tchwork.com"
47
- },
48
- {
49
- "name": "Symfony Community",
50
- "homepage": "https://symfony.com/contributors"
51
- }
52
- ],
53
- "description": "Symfony polyfill for the Mbstring extension",
54
- "homepage": "https://symfony.com",
55
- "keywords": [
56
- "compatibility",
57
- "mbstring",
58
- "polyfill",
59
- "portable",
60
- "shim"
61
- ]
62
- },
63
  {
64
  "name": "nesbot/carbon",
65
  "version": "1.22.1",
@@ -287,5 +226,66 @@
287
  ],
288
  "description": "Symfony Translation Component",
289
  "homepage": "https://symfony.com"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
290
  }
291
  ]
1
  [
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  {
3
  "name": "nesbot/carbon",
4
  "version": "1.22.1",
226
  ],
227
  "description": "Symfony Translation Component",
228
  "homepage": "https://symfony.com"
229
+ },
230
+ {
231
+ "name": "symfony/polyfill-mbstring",
232
+ "version": "v1.7.0",
233
+ "version_normalized": "1.7.0.0",
234
+ "source": {
235
+ "type": "git",
236
+ "url": "https://github.com/symfony/polyfill-mbstring.git",
237
+ "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b"
238
+ },
239
+ "dist": {
240
+ "type": "zip",
241
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/78be803ce01e55d3491c1397cf1c64beb9c1b63b",
242
+ "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b",
243
+ "shasum": ""
244
+ },
245
+ "require": {
246
+ "php": ">=5.3.3"
247
+ },
248
+ "suggest": {
249
+ "ext-mbstring": "For best performance"
250
+ },
251
+ "time": "2018-01-30T19:27:44+00:00",
252
+ "type": "library",
253
+ "extra": {
254
+ "branch-alias": {
255
+ "dev-master": "1.7-dev"
256
+ }
257
+ },
258
+ "installation-source": "dist",
259
+ "autoload": {
260
+ "psr-4": {
261
+ "Symfony\\Polyfill\\Mbstring\\": ""
262
+ },
263
+ "files": [
264
+ "bootstrap.php"
265
+ ]
266
+ },
267
+ "notification-url": "https://packagist.org/downloads/",
268
+ "license": [
269
+ "MIT"
270
+ ],
271
+ "authors": [
272
+ {
273
+ "name": "Nicolas Grekas",
274
+ "email": "p@tchwork.com"
275
+ },
276
+ {
277
+ "name": "Symfony Community",
278
+ "homepage": "https://symfony.com/contributors"
279
+ }
280
+ ],
281
+ "description": "Symfony polyfill for the Mbstring extension",
282
+ "homepage": "https://symfony.com",
283
+ "keywords": [
284
+ "compatibility",
285
+ "mbstring",
286
+ "polyfill",
287
+ "portable",
288
+ "shim"
289
+ ]
290
  }
291
  ]
src/common/lib/vendor/symfony/polyfill-mbstring/Mbstring.php CHANGED
@@ -20,7 +20,10 @@ namespace Symfony\Polyfill\Mbstring;
20
  * - mb_convert_variables - Convert character code in variable(s)
21
  * - mb_decode_mimeheader - Decode string in MIME header field
22
  * - mb_encode_mimeheader - Encode string for MIME header XXX NATIVE IMPLEMENTATION IS REALLY BUGGED
 
 
23
  * - mb_convert_case - Perform case folding on a string
 
24
  * - mb_get_info - Get internal settings of mbstring
25
  * - mb_http_input - Detect HTTP input character encoding
26
  * - mb_http_output - Set/Get HTTP output character encoding
@@ -47,8 +50,6 @@ namespace Symfony\Polyfill\Mbstring;
47
  *
48
  * Not implemented:
49
  * - mb_convert_kana - Convert "kana" one from another ("zen-kaku", "han-kaku" and more)
50
- * - mb_decode_numericentity - Decode HTML numeric string reference to character
51
- * - mb_encode_numericentity - Encode character to HTML numeric string reference
52
  * - mb_ereg_* - Regular expression with multibyte support
53
  * - mb_parse_str - Parse GET/POST/COOKIE data and set global variable
54
  * - mb_preferred_mime_name - Get MIME charset string
@@ -137,9 +138,134 @@ final class Mbstring
137
  trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', E_USER_WARNING);
138
  }
139
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  public static function mb_convert_case($s, $mode, $encoding = null)
141
  {
142
- if ('' === $s .= '') {
 
143
  return '';
144
  }
145
 
@@ -354,7 +480,8 @@ final class Mbstring
354
  return strpos($haystack, $needle, $offset);
355
  }
356
 
357
- if ('' === $needle .= '') {
 
358
  trigger_error(__METHOD__.': Empty delimiter', E_USER_WARNING);
359
 
360
  return false;
@@ -428,7 +555,7 @@ final class Mbstring
428
  }
429
  }
430
 
431
- return iconv_substr($s, $start, $length, $encoding).'';
432
  }
433
 
434
  public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null)
@@ -600,7 +727,7 @@ final class Mbstring
600
  return self::mb_substr($haystack, $pos, null, $encoding);
601
  }
602
 
603
- private static function html_encoding_callback($m)
604
  {
605
  $i = 1;
606
  $entities = '';
@@ -625,12 +752,12 @@ final class Mbstring
625
  return $entities;
626
  }
627
 
628
- private static function title_case_lower($s)
629
  {
630
  return self::mb_convert_case($s[0], MB_CASE_LOWER, 'UTF-8');
631
  }
632
 
633
- private static function title_case_upper($s)
634
  {
635
  return self::mb_convert_case($s[0], MB_CASE_UPPER, 'UTF-8');
636
  }
20
  * - mb_convert_variables - Convert character code in variable(s)
21
  * - mb_decode_mimeheader - Decode string in MIME header field
22
  * - mb_encode_mimeheader - Encode string for MIME header XXX NATIVE IMPLEMENTATION IS REALLY BUGGED
23
+ * - mb_decode_numericentity - Decode HTML numeric string reference to character
24
+ * - mb_encode_numericentity - Encode character to HTML numeric string reference
25
  * - mb_convert_case - Perform case folding on a string
26
+ * - mb_detect_encoding - Detect character encoding
27
  * - mb_get_info - Get internal settings of mbstring
28
  * - mb_http_input - Detect HTTP input character encoding
29
  * - mb_http_output - Set/Get HTTP output character encoding
50
  *
51
  * Not implemented:
52
  * - mb_convert_kana - Convert "kana" one from another ("zen-kaku", "han-kaku" and more)
 
 
53
  * - mb_ereg_* - Regular expression with multibyte support
54
  * - mb_parse_str - Parse GET/POST/COOKIE data and set global variable
55
  * - mb_preferred_mime_name - Get MIME charset string
138
  trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', E_USER_WARNING);
139
  }
140
 
141
+ public static function mb_decode_numericentity($s, $convmap, $encoding = null)
142
+ {
143
+ if (null !== $s && !is_scalar($s) && !(is_object($s) && method_exists($s, '__toString'))) {
144
+ trigger_error('mb_decode_numericentity() expects parameter 1 to be string, '.gettype($s).' given', E_USER_WARNING);
145
+ return null;
146
+ }
147
+
148
+ if (!is_array($convmap) || !$convmap) {
149
+ return false;
150
+ }
151
+
152
+ if (null !== $encoding && !is_scalar($encoding)) {
153
+ trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.gettype($s).' given', E_USER_WARNING);
154
+ return ''; // Instead of null (cf. mb_encode_numericentity).
155
+ }
156
+
157
+ $s = (string) $s;
158
+ if ('' === $s) {
159
+ return '';
160
+ }
161
+
162
+ $encoding = self::getEncoding($encoding);
163
+
164
+ if ('UTF-8' === $encoding) {
165
+ $encoding = null;
166
+ if (!preg_match('//u', $s)) {
167
+ $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
168
+ }
169
+ } else {
170
+ $s = iconv($encoding, 'UTF-8//IGNORE', $s);
171
+ }
172
+
173
+ $cnt = floor(count($convmap) / 4) * 4;
174
+
175
+ for ($i = 0; $i < $cnt; $i += 4) {
176
+ // collector_decode_htmlnumericentity ignores $convmap[$i + 3]
177
+ $convmap[$i] += $convmap[$i + 2];
178
+ $convmap[$i + 1] += $convmap[$i + 2];
179
+ }
180
+
181
+ $s = preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))(?!&);?/', function (array $m) use ($cnt, $convmap) {
182
+ $c = isset($m[2]) ? (int) hexdec($m[2]) : $m[1];
183
+ for ($i = 0; $i < $cnt; $i += 4) {
184
+ if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) {
185
+ return Mbstring::mb_chr($c - $convmap[$i + 2]);
186
+ }
187
+ }
188
+ return $m[0];
189
+ }, $s);
190
+
191
+ if (null === $encoding) {
192
+ return $s;
193
+ }
194
+
195
+ return iconv('UTF-8', $encoding.'//IGNORE', $s);
196
+ }
197
+
198
+ public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = false)
199
+ {
200
+ if (null !== $s && !is_scalar($s) && !(is_object($s) && method_exists($s, '__toString'))) {
201
+ trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.gettype($s).' given', E_USER_WARNING);
202
+ return null;
203
+ }
204
+
205
+ if (!is_array($convmap) || !$convmap) {
206
+ return false;
207
+ }
208
+
209
+ if (null !== $encoding && !is_scalar($encoding)) {
210
+ trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.gettype($s).' given', E_USER_WARNING);
211
+ return null; // Instead of '' (cf. mb_decode_numericentity).
212
+ }
213
+
214
+ if (null !== $is_hex && !is_scalar($is_hex)) {
215
+ trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.gettype($s).' given', E_USER_WARNING);
216
+ return null;
217
+ }
218
+
219
+ $s = (string) $s;
220
+ if ('' === $s) {
221
+ return '';
222
+ }
223
+
224
+ $encoding = self::getEncoding($encoding);
225
+
226
+ if ('UTF-8' === $encoding) {
227
+ $encoding = null;
228
+ if (!preg_match('//u', $s)) {
229
+ $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
230
+ }
231
+ } else {
232
+ $s = iconv($encoding, 'UTF-8//IGNORE', $s);
233
+ }
234
+
235
+ static $ulenMask = array("\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4);
236
+
237
+ $cnt = floor(count($convmap) / 4) * 4;
238
+ $i = 0;
239
+ $len = strlen($s);
240
+ $result = '';
241
+
242
+ while ($i < $len) {
243
+ $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
244
+ $uchr = substr($s, $i, $ulen);
245
+ $i += $ulen;
246
+ $c = self::mb_ord($uchr);
247
+
248
+ for ($j = 0; $j < $cnt; $j += 4) {
249
+ if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) {
250
+ $cOffset = ($c + $convmap[$j + 2]) & $convmap[$j + 3];
251
+ $result .= $is_hex ? sprintf('&#x%X;', $cOffset) : '&#'.$cOffset.';';
252
+ continue 2;
253
+ }
254
+ }
255
+ $result .= $uchr;
256
+ }
257
+
258
+ if (null === $encoding) {
259
+ return $result;
260
+ }
261
+
262
+ return iconv('UTF-8', $encoding.'//IGNORE', $result);
263
+ }
264
+
265
  public static function mb_convert_case($s, $mode, $encoding = null)
266
  {
267
+ $s = (string) $s;
268
+ if ('' === $s) {
269
  return '';
270
  }
271
 
480
  return strpos($haystack, $needle, $offset);
481
  }
482
 
483
+ $needle = (string) $needle;
484
+ if ('' === $needle) {
485
  trigger_error(__METHOD__.': Empty delimiter', E_USER_WARNING);
486
 
487
  return false;
555
  }
556
  }
557
 
558
+ return (string) iconv_substr($s, $start, $length, $encoding);
559
  }
560
 
561
  public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null)
727
  return self::mb_substr($haystack, $pos, null, $encoding);
728
  }
729
 
730
+ private static function html_encoding_callback(array $m)
731
  {
732
  $i = 1;
733
  $entities = '';
752
  return $entities;
753
  }
754
 
755
+ private static function title_case_lower(array $s)
756
  {
757
  return self::mb_convert_case($s[0], MB_CASE_LOWER, 'UTF-8');
758
  }
759
 
760
+ private static function title_case_upper(array $s)
761
  {
762
  return self::mb_convert_case($s[0], MB_CASE_UPPER, 'UTF-8');
763
  }
src/common/lib/vendor/symfony/polyfill-mbstring/bootstrap.php CHANGED
@@ -19,6 +19,8 @@ if (!function_exists('mb_strlen')) {
19
  function mb_convert_encoding($s, $to, $from = null) { return p\Mbstring::mb_convert_encoding($s, $to, $from); }
20
  function mb_decode_mimeheader($s) { return p\Mbstring::mb_decode_mimeheader($s); }
21
  function mb_encode_mimeheader($s, $charset = null, $transferEnc = null, $lf = null, $indent = null) { return p\Mbstring::mb_encode_mimeheader($s, $charset, $transferEnc, $lf, $indent); }
 
 
22
  function mb_convert_case($s, $mode, $enc = null) { return p\Mbstring::mb_convert_case($s, $mode, $enc); }
23
  function mb_internal_encoding($enc = null) { return p\Mbstring::mb_internal_encoding($enc); }
24
  function mb_language($lang = null) { return p\Mbstring::mb_language($lang); }
19
  function mb_convert_encoding($s, $to, $from = null) { return p\Mbstring::mb_convert_encoding($s, $to, $from); }
20
  function mb_decode_mimeheader($s) { return p\Mbstring::mb_decode_mimeheader($s); }
21
  function mb_encode_mimeheader($s, $charset = null, $transferEnc = null, $lf = null, $indent = null) { return p\Mbstring::mb_encode_mimeheader($s, $charset, $transferEnc, $lf, $indent); }
22
+ function mb_decode_numericentity($s, $convmap, $enc = null) { return p\Mbstring::mb_decode_numericentity($s, $convmap, $enc); }
23
+ function mb_encode_numericentity($s, $convmap, $enc = null, $is_hex = false) { return p\Mbstring::mb_encode_numericentity($s, $convmap, $enc, $is_hex); }
24
  function mb_convert_case($s, $mode, $enc = null) { return p\Mbstring::mb_convert_case($s, $mode, $enc); }
25
  function mb_internal_encoding($enc = null) { return p\Mbstring::mb_internal_encoding($enc); }
26
  function mb_language($lang = null) { return p\Mbstring::mb_language($lang); }
src/config/feature-hack_protect.php CHANGED
@@ -39,6 +39,23 @@
39
  "Recommendation - Keep the Unrecognised Files Scanner feature turned on."
40
  ]
41
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  {
43
  "slug": "section_wpvuln_scan",
44
  "title": "Vulnerability Scanner",
@@ -296,6 +313,91 @@
296
  "summary": "Scans For Critical Changes Made To User Accounts",
297
  "description": "Detects changes made to critical user account information that were made directly on the database and outside of the WordPress system."
298
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
299
  {
300
  "key": "snapshot_users",
301
  "transferable": false,
@@ -316,6 +418,7 @@
316
  "wpvulnscan_cron_name": "wpvulnscan-notification",
317
  "corechecksum_cron_name": "core-checksum-notification",
318
  "unrecognisedscan_cron_name": "unrecognised-scan-notification",
 
319
  "url_checksum_api": "https://api.wordpress.org/core/checksums/1.0/",
320
  "url_wordress_core_svn": "https://core.svn.wordpress.org/",
321
  "url_wordress_core_svn_il8n": "https://svn.automattic.com/wordpress-i18n/",
@@ -337,6 +440,30 @@
337
  "wp-content/themes/index.php"
338
  ],
339
  "wizards": {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
340
  "ufc": {
341
  "title": "Manually Run Unrecognised File Scanner",
342
  "desc": "Walks you through the scanning for unrecognised files present in your WordPress core installation.",
39
  "Recommendation - Keep the Unrecognised Files Scanner feature turned on."
40
  ]
41
  },
42
+ {
43
+ "slug": "section_pluginthemes_guard",
44
+ "reqs" : {
45
+ "php_min": "5.4"
46
+ },
47
+ "help_video" : {
48
+ "provider": "vimeo",
49
+ "embed_url": "https://player.vimeo.com/video/256755089?color=3fde23&byline=0",
50
+ "id": "256755089"
51
+ },
52
+ "title": "Plugins/Themes Guard",
53
+ "title_short": "Plugins/Themes Guard",
54
+ "summary": [
55
+ "Purpose - Detect malicious changes to your themes and plugins.",
56
+ "Recommendation - Keep the Plugins/Theme Guard feature turned on."
57
+ ]
58
+ },
59
  {
60
  "slug": "section_wpvuln_scan",
61
  "title": "Vulnerability Scanner",
313
  "summary": "Scans For Critical Changes Made To User Accounts",
314
  "description": "Detects changes made to critical user account information that were made directly on the database and outside of the WordPress system."
315
  },
316
+ {
317
+ "key": "ptg_enable",
318
+ "section": "section_pluginthemes_guard",
319
+ "premium": true,
320
+ "default": "disabled",
321
+ "type": "select",
322
+ "value_options": [
323
+ {
324
+ "value_key": "disabled",
325
+ "text": "Scan Disabled"
326
+ },
327
+ {
328
+ "value_key": "enabled",
329
+ "text": "Scan Enabled"
330
+ }
331
+ ],
332
+ "link_info": "http://icwp.io/bl",
333
+ "link_blog": "http://icwp.io/bm",
334
+ "name": "Enable/Disable Guard",
335
+ "summary": "Enable The Guard For Plugin And Theme Files",
336
+ "description": "When enabled the Guard will automatically scan for changes to your Plugin and Theme files."
337
+ },
338
+ {
339
+ "key": "ptg_depth",
340
+ "section": "section_pluginthemes_guard",
341
+ "type": "integer",
342
+ "default": 1,
343
+ "min": 0,
344
+ "link_info": "http://icwp.io/bn",
345
+ "link_blog": "http://icwp.io/bm",
346
+ "name": "Guard/Scan Depth",
347
+ "summary": "How Deep Into The Plugin Directories To Scan And Guard",
348
+ "description": "The Guard normally operates scan only the top level of a plugin folder. Increasing depth increases scan times."
349
+ },
350
+ {
351
+ "key": "ptg_extensions",
352
+ "section": "section_pluginthemes_guard",
353
+ "default": [
354
+ "php",
355
+ "php5",
356
+ "js",
357
+ "htaccess"
358
+ ],
359
+ "type": "array",
360
+ "link_info": "http://icwp.io/bo",
361
+ "link_blog": "",
362
+ "name": "File Types",
363
+ "summary": "The File Types Included In The Scan",
364
+ "description": "Take a new line for each file extension. No commas(,) or periods(.) necessary."
365
+ },
366
+ {
367
+ "key": "ptg_reinstall_links",
368
+ "section": "section_pluginthemes_guard",
369
+ "type": "checkbox",
370
+ "default": "Y",
371
+ "link_info": "http://icwp.io/bp",
372
+ "link_blog": "",
373
+ "name": "Show Re-Install Links",
374
+ "summary": "Show Re-Install Links For Plugins",
375
+ "description": "Show links to re-install plugins and offer re-install when activating plugins."
376
+ },
377
+ {
378
+ "key": "ptg_last_build_at",
379
+ "transferable": false,
380
+ "section": "section_non_ui",
381
+ "value": 0
382
+ },
383
+ {
384
+ "key": "ptg_candiskwrite",
385
+ "transferable": false,
386
+ "section": "section_non_ui",
387
+ "value": false
388
+ },
389
+ {
390
+ "key": "ptg_candiskwrite_at",
391
+ "transferable": false,
392
+ "section": "section_non_ui",
393
+ "value": false
394
+ },
395
+ {
396
+ "key": "ptg_email_track",
397
+ "transferable": false,
398
+ "section": "section_non_ui",
399
+ "value": []
400
+ },
401
  {
402
  "key": "snapshot_users",
403
  "transferable": false,
418
  "wpvulnscan_cron_name": "wpvulnscan-notification",
419
  "corechecksum_cron_name": "core-checksum-notification",
420
  "unrecognisedscan_cron_name": "unrecognised-scan-notification",
421
+ "ptg_cronname": "cron-pluginthemesguard",
422
  "url_checksum_api": "https://api.wordpress.org/core/checksums/1.0/",
423
  "url_wordress_core_svn": "https://core.svn.wordpress.org/",
424
  "url_wordress_core_svn_il8n": "https://svn.automattic.com/wordpress-i18n/",
440
  "wp-content/themes/index.php"
441
  ],
442
  "wizards": {
443
+ "ptg": {
444
+ "title": "Manually Run Plugin/Theme Guard Scanner",
445
+ "desc": "Walks you through the scanning for any changes to your plugins and themes.",
446
+ "min_user_permissions": "manage_options",
447
+ "steps": {
448
+ "start": {
449
+ "security_admin": false,
450
+ "title": "Start: Plugin/Theme Guard"
451
+ },
452
+ "scanresult_plugins": {
453
+ "title": "Scan Results - Plugins"
454
+ },
455
+ "scanresult_themes": {
456
+ "title": "Scan Results - Themes"
457
+ },
458
+ "config": {
459
+ "title": "Setup Scan Automation"
460
+ },
461
+ "finished": {
462
+ "security_admin": false,
463
+ "title": "Finished: Plugin/Theme Guard Scanner"
464
+ }
465
+ }
466
+ },
467
  "ufc": {
468
  "title": "Manually Run Unrecognised File Scanner",
469
  "desc": "Walks you through the scanning for unrecognised files present in your WordPress core installation.",
src/config/feature-lockdown.php CHANGED
@@ -13,7 +13,7 @@
13
  },
14
  "sections": [
15
  {
16
- "slug": "section_system_lockdown",
17
  "primary": true,
18
  "title": "WordPress System Lockdown",
19
  "title_short": "System",
@@ -68,7 +68,7 @@
68
  },
69
  {
70
  "key": "disable_xmlrpc",
71
- "section": "section_system_lockdown",
72
  "default": "N",
73
  "type": "checkbox",
74
  "link_info": "",
@@ -79,15 +79,30 @@
79
  },
80
  {
81
  "key": "disable_anonymous_restapi",
82
- "section": "section_system_lockdown",
83
  "default": "N",
84
  "type": "checkbox",
85
  "link_info": "",
86
  "link_blog": "",
87
- "name": "Disable Anonymous Rest API",
88
  "summary": "Disable The Anonymous Rest API",
89
  "description": "Checking this option will completely turn off the whole Anonymous Rest API system."
90
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  {
92
  "key": "disable_file_editing",
93
  "section": "section_permission_access_options",
13
  },
14
  "sections": [
15
  {
16
+ "slug": "section_apixml",
17
  "primary": true,
18
  "title": "WordPress System Lockdown",
19
  "title_short": "System",
68
  },
69
  {
70
  "key": "disable_xmlrpc",
71
+ "section": "section_apixml",
72
  "default": "N",
73
  "type": "checkbox",
74
  "link_info": "",
79
  },
80
  {
81
  "key": "disable_anonymous_restapi",
82
+ "section": "section_apixml",
83
  "default": "N",
84
  "type": "checkbox",
85
  "link_info": "",
86
  "link_blog": "",
87
+ "name": "Anonymous Rest API",
88
  "summary": "Disable The Anonymous Rest API",
89
  "description": "Checking this option will completely turn off the whole Anonymous Rest API system."
90
  },
91
+ {
92
+ "key": "api_namespace_exclusions",
93
+ "section": "section_non_ui",
94
+ "default": [
95
+ "contact-form-7",
96
+ "jetpack",
97
+ "woocommerce"
98
+ ],
99
+ "type": "array",
100
+ "link_info": "",
101
+ "link_blog": "",
102
+ "name": "Rest API Exclusions",
103
+ "summary": "Anonymous REST API Exclusions",
104
+ "description": "Any namespaces provided here will be excluded from the Anonymous API restriction."
105
+ },
106
  {
107
  "key": "disable_file_editing",
108
  "section": "section_permission_access_options",
src/features/autoupdates.php CHANGED
@@ -109,7 +109,7 @@ class ICWP_WPSF_FeatureHandler_Autoupdates extends ICWP_WPSF_FeatureHandler_Base
109
 
110
  $oWpPlugins = $this->loadWpPlugins();
111
  $sFile = $this->loadDataProcessor()->FetchPost( 'pluginfile' );
112
- if ( $oWpPlugins->isPluginInstalled( $sFile ) ) {
113
  $this->setPluginToAutoUpdate( $sFile );
114
 
115
  $aPlugin = $oWpPlugins->getPlugin( $sFile );
109
 
110
  $oWpPlugins = $this->loadWpPlugins();
111
  $sFile = $this->loadDataProcessor()->FetchPost( 'pluginfile' );
112
+ if ( $oWpPlugins->isInstalled( $sFile ) ) {
113
  $this->setPluginToAutoUpdate( $sFile );
114
 
115
  $aPlugin = $oWpPlugins->getPlugin( $sFile );
src/features/base.php CHANGED
@@ -121,6 +121,8 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_Foundation {
121
  add_filter( $this->prefix( 'register_admin_notices' ), array( $this, 'fRegisterAdminNotices' ) );
122
  add_filter( $this->prefix( 'gather_options_for_export' ), array( $this, 'exportTransferableOptions' ) );
123
 
 
 
124
  $this->doPostConstruction();
125
  }
126
  }
@@ -911,7 +913,8 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_Foundation {
911
 
912
  $bPremiumEnabled = self::getConn()->isPremiumExtensionsEnabled();
913
 
914
- $aOptions = $this->getOptionsVo()->getOptionsForPluginUse();
 
915
  foreach ( $aOptions as $nSectionKey => $aSection ) {
916
 
917
  if ( !empty( $aSection[ 'options' ] ) ) {
@@ -937,12 +940,29 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_Foundation {
937
  else {
938
  $aOptions[ $nSectionKey ] = $this->loadStrings_SectionTitles( $aSection );
939
  }
 
 
 
 
 
 
 
 
 
940
  }
941
  }
942
 
943
  return $aOptions;
944
  }
945
 
 
 
 
 
 
 
 
 
946
  /**
947
  * @param array $aOptParams
948
  * @return array
@@ -1594,6 +1614,12 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_Foundation {
1594
  return $this->loadDP()->getPhpVersionIsAtLeast( '5.4.0' );
1595
  }
1596
 
 
 
 
 
 
 
1597
  /**
1598
  * @param array $aData
1599
  * @param string $sSubView
121
  add_filter( $this->prefix( 'register_admin_notices' ), array( $this, 'fRegisterAdminNotices' ) );
122
  add_filter( $this->prefix( 'gather_options_for_export' ), array( $this, 'exportTransferableOptions' ) );
123
 
124
+ add_action( 'admin_enqueue_scripts', array( $this, 'insertCustomJsVars' ), 100 );
125
+
126
  $this->doPostConstruction();
127
  }
128
  }
913
 
914
  $bPremiumEnabled = self::getConn()->isPremiumExtensionsEnabled();
915
 
916
+ $oOptsVo = $this->getOptionsVo();
917
+ $aOptions = $oOptsVo->getOptionsForPluginUse();
918
  foreach ( $aOptions as $nSectionKey => $aSection ) {
919
 
920
  if ( !empty( $aSection[ 'options' ] ) ) {
940
  else {
941
  $aOptions[ $nSectionKey ] = $this->loadStrings_SectionTitles( $aSection );
942
  }
943
+
944
+ $aWarnings = array();
945
+ if ( !$oOptsVo->isSectionReqsMet( $aSection[ 'slug' ] ) ) {
946
+ $aWarnings[] = _wpsf__( 'Unfortunately your PHP version is too low to support this feature.' );
947
+ }
948
+ $aOptions[ $nSectionKey ][ 'warnings' ] = array_merge(
949
+ $aWarnings,
950
+ $this->getSectionWarnings( $aSection[ 'slug' ] )
951
+ );
952
  }
953
  }
954
 
955
  return $aOptions;
956
  }
957
 
958
+ /**
959
+ * @param string $sSectionSlug
960
+ * @return array
961
+ */
962
+ protected function getSectionWarnings( $sSectionSlug ) {
963
+ return array();
964
+ }
965
+
966
  /**
967
  * @param array $aOptParams
968
  * @return array
1614
  return $this->loadDP()->getPhpVersionIsAtLeast( '5.4.0' );
1615
  }
1616
 
1617
+ /**
1618
+ * Override this with custom JS vars for your particular module.
1619
+ */
1620
+ public function insertCustomJsVars() {
1621
+ }
1622
+
1623
  /**
1624
  * @param array $aData
1625
  * @param string $sSubView
src/features/base_wpsf.php CHANGED
@@ -185,6 +185,26 @@ class ICWP_WPSF_FeatureHandler_BaseWpsf extends ICWP_WPSF_FeatureHandler_Base {
185
  ->isXmlrpcBypass();
186
  }
187
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  /**
189
  * @param array $aOptionsParams
190
  * @return array
185
  ->isXmlrpcBypass();
186
  }
187
 
188
+ /**
189
+ * @param string[] $aArray
190
+ * @param string $sPregReplacePattern
191
+ * @return string[]
192
+ */
193
+ protected function cleanStringArray( $aArray, $sPregReplacePattern ) {
194
+ $aCleaned = array();
195
+ if ( !is_array( $aArray ) ) {
196
+ return $aCleaned;
197
+ }
198
+
199
+ foreach ( $aArray as $nKey => $sVal ) {
200
+ $sVal = preg_replace( $sPregReplacePattern, '', $sVal );
201
+ if ( !empty( $sVal ) ) {
202
+ $aCleaned[] = $sVal;
203
+ }
204
+ }
205
+ return array_unique( array_filter( $aCleaned ) );
206
+ }
207
+
208
  /**
209
  * @param array $aOptionsParams
210
  * @return array
src/features/hack_protect.php CHANGED
@@ -12,19 +12,43 @@ class ICWP_WPSF_FeatureHandler_HackProtect extends ICWP_WPSF_FeatureHandler_Base
12
  $this->setCustomCronSchedules();
13
  }
14
 
 
 
 
 
 
 
 
 
 
15
  /**
16
  */
17
  protected function doExtraSubmitProcessing() {
18
- $this->clearIcSnapshots();
19
- $this->clearCrons();
20
- $this->cleanFileExclusions();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  }
22
 
23
  protected function clearCrons() {
24
  $aCrons = array(
25
  $this->getIcCronName(),
26
  $this->getUfcCronName(),
27
- $this->getWcfCronName()
 
28
  );
29
  $oCron = $this->loadWpCronProcessor();
30
  foreach ( $aCrons as $sCron ) {
@@ -297,6 +321,215 @@ class ICWP_WPSF_FeatureHandler_HackProtect extends ICWP_WPSF_FeatureHandler_Base
297
  && ( ( $sOpt != 'enabled_securityadmin' ) || $this->getConn()->getHasPermissionToManage() );
298
  }
299
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
300
  /**
301
  * @param array $aOptionsParams
302
  * @return array
@@ -361,6 +594,16 @@ class ICWP_WPSF_FeatureHandler_HackProtect extends ICWP_WPSF_FeatureHandler_Base
361
  $sTitleShort = _wpsf__( 'Unrecognised Files Scanner' );
362
  break;
363
 
 
 
 
 
 
 
 
 
 
 
364
  case 'section_integrity_checking' :
365
  $sTitle = _wpsf__( 'Integrity Checks' );
366
  $sTitleShort = _wpsf__( 'Integrity Checks' );
@@ -474,6 +717,33 @@ class ICWP_WPSF_FeatureHandler_HackProtect extends ICWP_WPSF_FeatureHandler_Base
474
  .'<br />'.sprintf( _wpsf__( 'Warning: %s' ), _wpsf__( 'This option may cause critial problem with 3rd party plugins that manage user accounts.' ) );
475
  break;
476
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
477
  default:
478
  throw new Exception( sprintf( 'An option has been defined but without strings assigned to it. Option key: "%s".', $sKey ) );
479
  }
12
  $this->setCustomCronSchedules();
13
  }
14
 
15
+ public function doPrePluginOptionsSave() {
16
+ $this->setOpt( 'ptg_candiskwrite_at', 0 );
17
+ }
18
+
19
+ protected function adminAjaxHandlers() {
20
+ parent::adminAjaxHandlers();
21
+ add_action( $this->prefixWpAjax( 'PluginReinstall' ), array( $this, 'ajaxPluginReinstall' ) );
22
+ }
23
+
24
  /**
25
  */
26
  protected function doExtraSubmitProcessing() {
27
+
28
+ if ( $this->isModuleOptionsRequest() ) { // Move this IF to base
29
+
30
+ $this->clearIcSnapshots();
31
+ $this->clearCrons();
32
+ $this->cleanFileExclusions();
33
+ $this->cleanPtgFileExtensions();
34
+
35
+ $oOpts = $this->getOptionsVo();
36
+ if ( !$this->isPtgEnabled() || $oOpts->isOptChanged( 'ptg_depth' ) || $oOpts->isOptChanged( 'ptg_extensions' ) ) {
37
+ /** @var ICWP_WPSF_Processor_HackProtect $oP */
38
+ $oP = $this->getProcessor();
39
+ $oP->getSubProcessorGuard()
40
+ ->deleteStores();
41
+ $this->setPtgLastBuildAt( 0 );
42
+ }
43
+ }
44
  }
45
 
46
  protected function clearCrons() {
47
  $aCrons = array(
48
  $this->getIcCronName(),
49
  $this->getUfcCronName(),
50
+ $this->getWcfCronName(),
51
+ $this->getPtgCronName()
52
  );
53
  $oCron = $this->loadWpCronProcessor();
54
  foreach ( $aCrons as $sCron ) {
321
  && ( ( $sOpt != 'enabled_securityadmin' ) || $this->getConn()->getHasPermissionToManage() );
322
  }
323
 
324
+ /**
325
+ * @return bool
326
+ */
327
+ public function canPtgWriteToDisk() {
328
+ $bCan = (bool)$this->getOpt( 'ptg_candiskwrite' );
329
+ $nNow = $this->loadDP()->time();
330
+
331
+ $bLastCheckExpired = ( $nNow - $this->getOpt( 'ptg_candiskwrite_at', 0 ) ) > DAY_IN_SECONDS;
332
+ if ( !$bCan && $bLastCheckExpired ) {
333
+ $oFS = $this->loadFS();
334
+ $sDir = $this->getPtgSnapsBaseDir();
335
+
336
+ if ( $oFS->mkdir( $sDir ) ) {
337
+ $sTestFile = path_join( $sDir, 'test.txt' );
338
+ $oFS->putFileContent( $sTestFile, $nNow );
339
+ $sContents = $oFS->exists( $sTestFile ) ? $oFS->getFileContent( $sTestFile ) : '';
340
+
341
+ if ( $sContents === $nNow ) {
342
+ $oFS->deleteFile( $sTestFile );
343
+ $this->setOpt( 'ptg_candiskwrite', !$oFS->exists( $sTestFile ) );
344
+ }
345
+ }
346
+ $this->setOpt( 'ptg_candiskwrite_at', $nNow );
347
+ }
348
+
349
+ return $bCan;
350
+ }
351
+
352
+ /**
353
+ * @return $this
354
+ */
355
+ protected function cleanPtgFileExtensions() {
356
+ return $this->setOpt(
357
+ 'ptg_extensions',
358
+ $this->cleanStringArray( $this->getPtgFileExtensions(), '#[^a-z0-9_-]#i' )
359
+ );
360
+ }
361
+
362
+ /**
363
+ * @return bool
364
+ */
365
+ public function getPtgCronName() {
366
+ return $this->prefixOptionKey( $this->getDef( 'ptg_cronname' ) );
367
+ }
368
+
369
+ /**
370
+ * @return string[]
371
+ */
372
+ public function getPtgFileExtensions() {
373
+ return $this->getOpt( 'ptg_extensions' );
374
+ }
375
+
376
+ /**
377
+ * @return bool
378
+ */
379
+ public function getPtgDepth() {
380
+ return $this->getOpt( 'ptg_depth' );
381
+ }
382
+
383
+ /**
384
+ * @return array
385
+ */
386
+ public function getPtgEmailTrackData() {
387
+ $aData = $this->getOpt( 'ptg_email_track' );
388
+ return is_array( $aData ) ? $aData : array();
389
+ }
390
+
391
+ /**
392
+ * @return string
393
+ */
394
+ public function getPtgEnabledOption() {
395
+ return $this->getOpt( 'ptg_enable' );
396
+ }
397
+
398
+ /**
399
+ * @return int
400
+ */
401
+ public function getPtgLastBuildAt() {
402
+ return $this->getOpt( 'ptg_last_build_at' );
403
+ }
404
+
405
+ /**
406
+ * @return string
407
+ */
408
+ public function getPtgSnapsBaseDir() {
409
+ return path_join( WP_CONTENT_DIR, 'shield/ptguard' );
410
+ }
411
+
412
+ /**
413
+ * @return bool
414
+ */
415
+ public function isPtgBuildRequired() {
416
+ return $this->isPtgEnabled() && ( $this->getPtgLastBuildAt() == 0 );
417
+ }
418
+
419
+ /**
420
+ * @return bool
421
+ */
422
+ public function isPtgEnabled() {
423
+ return $this->isPremium() && $this->getOptIs( 'ptg_enable', 'enabled' )
424
+ && $this->getOptionsVo()->isOptReqsMet( 'ptg_enable' )
425
+ && $this->canPtgWriteToDisk();
426
+ }
427
+
428
+ /**
429
+ * @return bool
430
+ */
431
+ public function isPtgReadyToScan() {
432
+ return $this->isPtgEnabled() && !$this->isPtgBuildRequired();
433
+ }
434
+
435
+ /**
436
+ * @return bool
437
+ */
438
+ public function isPtgReinstallLinks() {
439
+ return $this->getOptIs( 'ptg_reinstall_links', 'Y' );
440
+ }
441
+
442
+ /**
443
+ * @param array $aData
444
+ * @return $this
445
+ */
446
+ public function setPtgEmailTrackData( $aData ) {
447
+ return $this->setOpt( 'ptg_email_track', $aData );
448
+ }
449
+
450
+ /**
451
+ * @param int $nTime
452
+ * @return $this
453
+ */
454
+ public function setPtgLastBuildAt( $nTime = null ) {
455
+ return $this->setOpt( 'ptg_last_build_at', is_null( $nTime ) ? $this->loadDP()->time() : $nTime );
456
+ }
457
+
458
+ /**
459
+ * @param string $sValue
460
+ * @return $this
461
+ */
462
+ public function setPtgEnabledOption( $sValue ) {
463
+ return $this->setOpt( 'ptg_enable', $sValue );
464
+ }
465
+
466
+ public function ajaxPluginReinstall() {
467
+ $oDP = $this->loadDP();
468
+ $bReinstall = (bool)$oDP->post( 'reinstall' );
469
+ $bActivate = (bool)$oDP->post( 'activate' );
470
+ $sFile = sanitize_text_field( wp_unslash( $oDP->post( 'file' ) ) );
471
+ $oWpP = $this->loadWpPlugins();
472
+
473
+ if ( $bReinstall ) {
474
+ /** @var ICWP_WPSF_Processor_HackProtect $oP */
475
+ $oP = $this->getProcessor();
476
+ $bActivate = $oP->getSubProcessorGuard()
477
+ ->reinstall( $sFile, ICWP_WPSF_Processor_HackProtect_PTGuard::CONTEXT_PLUGINS )
478
+ && $bActivate;
479
+ }
480
+ if ( $bActivate ) {
481
+ $oWpP->activate( $sFile );
482
+ }
483
+
484
+ $this->sendAjaxResponse( true );
485
+ }
486
+
487
+ public function insertCustomJsVars() {
488
+
489
+ if ( $this->loadWp()->getCurrentPage() == 'plugins.php' && $this->isPtgReinstallLinks() ) {
490
+ wp_localize_script(
491
+ $this->prefix( 'global-plugin' ),
492
+ 'icwp_wpsf_vars_hp',
493
+ array(
494
+ 'ajax_reinstall' => $this->getBaseAjaxActionRenderData( 'PluginReinstall' ),
495
+ 'reinstallable' => $this->getReinstallablePlugins()
496
+ )
497
+ );
498
+ wp_enqueue_script( 'jquery-ui-dialog' ); // jquery and jquery-ui should be dependencies, didn't check though...
499
+ wp_enqueue_style( 'wp-jquery-ui-dialog' );
500
+ }
501
+ }
502
+
503
+ /**
504
+ * @return string[]
505
+ */
506
+ protected function getReinstallablePlugins() {
507
+ $oWPP = $this->loadWpPlugins();
508
+ $aP = array();
509
+ foreach ( $oWPP->getPlugins() as $sPluginFile => $aData ) {
510
+ if ( $oWPP->isWpOrg( $sPluginFile ) ) {
511
+ $aP[] = $sPluginFile;
512
+ }
513
+ }
514
+ return $aP;
515
+ }
516
+
517
+ /**
518
+ * @param string $sSectionSlug
519
+ * @return array
520
+ */
521
+ protected function getSectionWarnings( $sSectionSlug ) {
522
+ $aWarnings = array();
523
+
524
+ if ( $sSectionSlug == 'section_pluginthemes_guard' ) {
525
+ if ( !$this->canPtgWriteToDisk() ) {
526
+ $aWarnings[] = sprintf( _wpsf__( 'Sorry, this feature is not available because we cannot write to disk at this location: "%s"' ), $this->getPtgSnapsBaseDir() );
527
+ }
528
+ }
529
+
530
+ return $aWarnings;
531
+ }
532
+
533
  /**
534
  * @param array $aOptionsParams
535
  * @return array
594
  $sTitleShort = _wpsf__( 'Unrecognised Files Scanner' );
595
  break;
596
 
597
+ case 'section_pluginthemes_guard' :
598
+ $sTitle = _wpsf__( 'Plugins and Themes Guard' );
599
+ $sTitleShort = _wpsf__( 'Plugins/Themes Guard' );
600
+ $aSummary = array(
601
+ sprintf( _wpsf__( 'Purpose - %s' ), _wpsf__( 'Detect malicious changes to your themes and plugins.' ) ),
602
+ sprintf( _wpsf__( 'Recommendation - %s' ), _wpsf__( 'Keep the Plugins/Theme Guard feature turned on.' ) ),
603
+ sprintf( _wpsf__( 'Note - %s' ), _wpsf__( 'Requires PHP v5.4 and above.' ) )
604
+ );
605
+ break;
606
+
607
  case 'section_integrity_checking' :
608
  $sTitle = _wpsf__( 'Integrity Checks' );
609
  $sTitleShort = _wpsf__( 'Integrity Checks' );
717
  .'<br />'.sprintf( _wpsf__( 'Warning: %s' ), _wpsf__( 'This option may cause critial problem with 3rd party plugins that manage user accounts.' ) );
718
  break;
719
 
720
+ case 'ptg_enable' :
721
+ $sName = sprintf( _wpsf__( 'Enable %s' ), _wpsf__( 'Guard' ) );
722
+ $sSummary = _wpsf__( 'Enable The Guard For Plugin And Theme Files' );
723
+ $sDescription = _wpsf__( 'When enabled the Guard will automatically scan for changes to your Plugin and Theme files.' );
724
+ break;
725
+
726
+ case 'ptg_depth' :
727
+ $sName = _wpsf__( 'Guard/Scan Depth' );
728
+ $sSummary = _wpsf__( 'How Deep Into The Plugin Directories To Scan And Guard' );
729
+ $sDescription = _wpsf__( 'The Guard normally scans only the top level of a folder. Increasing depth will increase scan times.' )
730
+ .'<br/>'.sprintf( _wpsf__( 'Setting it to %s will remove this limit and all sub-folders will be scanned - not recommended' ), 0 );
731
+ break;
732
+
733
+ case 'ptg_extensions' :
734
+ $sName = _wpsf__( 'Included File Types' );
735
+ $sSummary = _wpsf__( 'The File Types (by File Extension) Included In The Scan' );
736
+ $sDescription = _wpsf__( 'Take a new line for each file extension.' )
737
+ .'<br/>'._wpsf__( 'No commas(,) or periods(.) necessary.' )
738
+ .'<br/>'._wpsf__( 'Remove all extensions to scan all file type (not recommended).' );
739
+ break;
740
+
741
+ case 'ptg_reinstall_links' :
742
+ $sName = _wpsf__( 'Show Re-Install Links' );
743
+ $sSummary = _wpsf__( 'Show Re-Install Links For Plugins' );
744
+ $sDescription = _wpsf__( "Show links to re-install plugins and offer re-install when activating plugins." );
745
+ break;
746
+
747
  default:
748
  throw new Exception( sprintf( 'An option has been defined but without strings assigned to it. Option key: "%s".', $sKey ) );
749
  }
src/features/lockdown.php CHANGED
@@ -8,17 +8,38 @@ require_once( dirname( __FILE__ ).'/base_wpsf.php' );
8
 
9
  class ICWP_WPSF_FeatureHandler_Lockdown extends ICWP_WPSF_FeatureHandler_BaseWpsf {
10
 
 
 
 
 
 
 
 
11
  /**
12
  * @return bool
13
  */
14
- public function getIfRestApiDisabled() {
15
- return $this->getOptIs( 'disable_anonymous_restapi', 'Y' );
 
 
 
 
 
 
 
 
16
  }
17
 
18
  protected function doExtraSubmitProcessing() {
19
- $sMask = $this->getOpt( 'mask_wordpress_version' );
20
- if ( !empty( $sMask ) ) {
21
- $this->setOpt( 'mask_wordpress_version', preg_replace( '/[^a-z0-9_.-]/i', '', $sMask ) );
 
 
 
 
 
 
22
  }
23
  }
24
 
@@ -48,13 +69,13 @@ class ICWP_WPSF_FeatureHandler_Lockdown extends ICWP_WPSF_FeatureHandler_BaseWps
48
  $sTitleShort = sprintf( _wpsf__( '%s/%s Module' ), _wpsf__( 'Enable' ), _wpsf__( 'Disable' ) );
49
  break;
50
 
51
- case 'section_system_lockdown' :
52
- $sTitle = _wpsf__( 'WordPress System Lockdown' );
53
  $aSummary = array(
54
  sprintf( _wpsf__( 'Purpose - %s' ), _wpsf__( 'Lockdown certain core WordPress system features.' ) ),
55
  sprintf( _wpsf__( 'Recommendation - %s' ), _wpsf__( 'This depends on your usage and needs for certain WordPress functions and features.' ) )
56
  );
57
- $sTitleShort = _wpsf__( 'System' );
58
  break;
59
 
60
  case 'section_permission_access_options' :
@@ -107,9 +128,15 @@ class ICWP_WPSF_FeatureHandler_Lockdown extends ICWP_WPSF_FeatureHandler_BaseWps
107
  break;
108
 
109
  case 'disable_anonymous_restapi' :
110
- $sName = sprintf( _wpsf__( 'Disable %s' ), _wpsf__( 'Anonymous Rest API' ) );
111
  $sSummary = sprintf( _wpsf__( 'Disable The %s System' ), _wpsf__( 'Anonymous Rest API' ) );
112
- $sDescription = sprintf( _wpsf__( 'Checking this option will disable anonymous access to the REST API.' ), 'XML-RPC' );
 
 
 
 
 
 
113
  break;
114
 
115
  case 'disable_file_editing' :
8
 
9
  class ICWP_WPSF_FeatureHandler_Lockdown extends ICWP_WPSF_FeatureHandler_BaseWpsf {
10
 
11
+ /**
12
+ * @return array
13
+ */
14
+ public function getRestApiAnonymousExclusions() {
15
+ return array();//$this->getOpt( 'api_namespace_exclusions' ); TODO: reenabled for next release
16
+ }
17
+
18
  /**
19
  * @return bool
20
  */
21
+ public function isRestApiAnonymousAccessAllowed() {
22
+ return $this->getOptIs( 'disable_anonymous_restapi', 'N' );
23
+ }
24
+
25
+ /**
26
+ * @return $this
27
+ */
28
+ protected function cleanApiExclusions() {
29
+ $aExt = $this->cleanStringArray( $this->getRestApiAnonymousExclusions(), '#[^a-z0-9_-]#i' );
30
+ return $this->setOpt( 'api_namespace_exclusions', $aExt );
31
  }
32
 
33
  protected function doExtraSubmitProcessing() {
34
+
35
+ if ( $this->isModuleOptionsRequest() ) { // Move this IF to base
36
+
37
+ $sMask = $this->getOpt( 'mask_wordpress_version' );
38
+ if ( !empty( $sMask ) ) {
39
+ $this->setOpt( 'mask_wordpress_version', preg_replace( '/[^a-z0-9_.-]/i', '', $sMask ) );
40
+ }
41
+
42
+ $this->cleanApiExclusions();
43
  }
44
  }
45
 
69
  $sTitleShort = sprintf( _wpsf__( '%s/%s Module' ), _wpsf__( 'Enable' ), _wpsf__( 'Disable' ) );
70
  break;
71
 
72
+ case 'section_apixml' :
73
+ $sTitle = _wpsf__( 'API & XML-RPC' );
74
  $aSummary = array(
75
  sprintf( _wpsf__( 'Purpose - %s' ), _wpsf__( 'Lockdown certain core WordPress system features.' ) ),
76
  sprintf( _wpsf__( 'Recommendation - %s' ), _wpsf__( 'This depends on your usage and needs for certain WordPress functions and features.' ) )
77
  );
78
+ $sTitleShort = _wpsf__( 'API & XML-RPC' );
79
  break;
80
 
81
  case 'section_permission_access_options' :
128
  break;
129
 
130
  case 'disable_anonymous_restapi' :
131
+ $sName = _wpsf__( 'Anonymous Rest API' );
132
  $sSummary = sprintf( _wpsf__( 'Disable The %s System' ), _wpsf__( 'Anonymous Rest API' ) );
133
+ $sDescription = _wpsf__( 'You can choose to completely disable anonymous access to the REST API.' );
134
+ break;
135
+
136
+ case 'api_namespace_exclusions' :
137
+ $sName = _wpsf__( 'Rest API Exclusions' );
138
+ $sSummary = _wpsf__( 'Anonymous REST API Exclusions' );
139
+ $sDescription = _wpsf__( 'Any namespaces provided here will be excluded from the Anonymous API restriction.' );
140
  break;
141
 
142
  case 'disable_file_editing' :
src/features/login_protect.php CHANGED
@@ -126,7 +126,7 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
126
  $aMessage[] = sprintf( _wpsf__( "Here's your code for the guided wizard: %s" ), $this->getCanEmailVerifyCode() );
127
  }
128
 
129
- $sEmailSubject = sprintf( _wpsf__( 'Email Sending Verification For %s' ), $this->loadWp()->getHomeUrl() );
130
  return $this->getEmailProcessor()
131
  ->sendEmailTo( $sEmail, $sEmailSubject, $aMessage );
132
  }
126
  $aMessage[] = sprintf( _wpsf__( "Here's your code for the guided wizard: %s" ), $this->getCanEmailVerifyCode() );
127
  }
128
 
129
+ $sEmailSubject = _wpsf__( 'Email Sending Verification' );
130
  return $this->getEmailProcessor()
131
  ->sendEmailTo( $sEmail, $sEmailSubject, $aMessage );
132
  }
src/processors/autoupdates.php CHANGED
@@ -390,7 +390,7 @@ class ICWP_WPSF_Processor_Autoupdates extends ICWP_WPSF_Processor_BaseWpsf {
390
  $aColumns[ 'icwp_autoupdate' ] = 'Auto Update';
391
  add_action( 'manage_plugins_custom_column',
392
  array( $this, 'aPrintPluginsListAutoUpdateColumnContent' ),
393
- PHP_INT_MAX, 2
394
  );
395
  }
396
  return $aColumns;
@@ -488,10 +488,7 @@ class ICWP_WPSF_Processor_Autoupdates extends ICWP_WPSF_Processor_BaseWpsf {
488
 
489
  $aEmailContent[] = _wpsf__( 'Thank you.' );
490
 
491
- $sTitle = sprintf(
492
- _wpsf__( "Notice - %s" ),
493
- sprintf( "Automatic Updates Completed For %s", $this->loadWp()->getSiteName() )
494
- );
495
  $this->getEmailProcessor()
496
  ->sendEmailTo( $this->getOption( 'override_email_address' ), $sTitle, $aEmailContent );
497
  }
390
  $aColumns[ 'icwp_autoupdate' ] = 'Auto Update';
391
  add_action( 'manage_plugins_custom_column',
392
  array( $this, 'aPrintPluginsListAutoUpdateColumnContent' ),
393
+ 100, 2
394
  );
395
  }
396
  return $aColumns;
488
 
489
  $aEmailContent[] = _wpsf__( 'Thank you.' );
490
 
491
+ $sTitle = sprintf( _wpsf__( "Notice: %s" ), _wpsf__( "Automatic Updates Completed" ) );
 
 
 
492
  $this->getEmailProcessor()
493
  ->sendEmailTo( $this->getOption( 'override_email_address' ), $sTitle, $aEmailContent );
494
  }
src/processors/comments_filter.php CHANGED
@@ -56,7 +56,7 @@ class ICWP_WPSF_Processor_CommentsFilter extends ICWP_WPSF_Processor_BaseWpsf {
56
 
57
  $oWpPlugins = $this->loadWpPlugins();
58
  $sPluginFile = $oWpPlugins->findPluginBy( 'Akismet', 'Name' );
59
- if ( !is_null( $sPluginFile ) && $oWpPlugins->isPluginActive( $sPluginFile ) ) {
60
  $aRenderData = array(
61
  'notice_attributes' => $aNoticeAttributes,
62
  'strings' => array(
56
 
57
  $oWpPlugins = $this->loadWpPlugins();
58
  $sPluginFile = $oWpPlugins->findPluginBy( 'Akismet', 'Name' );
59
+ if ( $oWpPlugins->isActive( $sPluginFile ) ) {
60
  $aRenderData = array(
61
  'notice_attributes' => $aNoticeAttributes,
62
  'strings' => array(
src/processors/email.php CHANGED
@@ -109,6 +109,8 @@ class ICWP_WPSF_Processor_Email extends ICWP_WPSF_Processor_BaseWpsf {
109
 
110
  $aMessage = array_merge( $this->getEmailHeader(), $aMessage, $this->getEmailFooter() );
111
 
 
 
112
  add_filter( 'wp_mail_content_type', array( $this, 'setMailContentType' ), 100, 0 );
113
  $bSuccess = wp_mail( $sEmailTo, $sEmailSubject, '<html>'.implode( "<br />", $aMessage ).'</html>' );
114
 
109
 
110
  $aMessage = array_merge( $this->getEmailHeader(), $aMessage, $this->getEmailFooter() );
111
 
112
+ $sEmailSubject = sprintf( '[%s] %s', $this->loadWp()->getSiteName(), $sEmailSubject );
113
+
114
  add_filter( 'wp_mail_content_type', array( $this, 'setMailContentType' ), 100, 0 );
115
  $bSuccess = wp_mail( $sEmailTo, $sEmailSubject, '<html>'.implode( "<br />", $aMessage ).'</html>' );
116
 
src/processors/firewall.php CHANGED
@@ -4,7 +4,7 @@ if ( class_exists( 'ICWP_WPSF_Processor_Firewall', false ) ) {
4
  return;
5
  }
6
 
7
- require_once( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'base_wpsf.php' );
8
 
9
  class ICWP_WPSF_Processor_Firewall extends ICWP_WPSF_Processor_BaseWpsf {
10
 
@@ -162,7 +162,7 @@ class ICWP_WPSF_Processor_Firewall extends ICWP_WPSF_Processor_BaseWpsf {
162
  if ( $bFAIL ) {
163
  $sAuditMessage = sprintf( _wpsf__( 'Firewall Trigger: %s.' ), _wpsf__( 'EXE File Uploads' ) );
164
  $this->addToAuditEntry( $sAuditMessage, 3, 'firewall_block' );
165
- $this->doStatIncrement( 'firewall.blocked.' . $sKey );
166
  $this->setFirewallTrip_Class( $sKey );
167
  }
168
  }
@@ -213,14 +213,14 @@ class ICWP_WPSF_Processor_Firewall extends ICWP_WPSF_Processor_BaseWpsf {
213
  if ( $bFAIL ) {
214
  $this->addToFirewallDieMessage( _wpsf__( "Something in the URL, Form or Cookie data wasn't appropriate." ) );
215
  $sAuditMessage = _wpsf__( 'Page parameter failed firewall check.' )
216
- . ' ' . sprintf( _wpsf__( 'The offending parameter was "%s" with a value of "%s".' ), $sParam, $mValue );
217
  $this->addToAuditEntry( $sAuditMessage, 3 );
218
  $this->setFirewallTrip_Parameter( $sParam );
219
  $this->setFirewallTrip_Value( $mValue );
220
 
221
  $sAuditMessage = sprintf( _wpsf__( 'Firewall Trigger: %s.' ), $this->getFirewallBlockKeyName( $sTermsKey ) );
222
  $this->addToAuditEntry( $sAuditMessage, 3, 'firewall_block' );
223
- $this->doStatIncrement( 'firewall.blocked.' . $sTermsKey );
224
  $this->setFirewallTrip_Class( $sTermsKey );
225
  }
226
 
@@ -246,7 +246,7 @@ class ICWP_WPSF_Processor_Firewall extends ICWP_WPSF_Processor_BaseWpsf {
246
  * @return string
247
  */
248
  private function prepRegexTerms( $sTerm ) {
249
- return '/' . $sTerm . '/i';
250
  }
251
 
252
  /**
@@ -308,10 +308,10 @@ class ICWP_WPSF_Processor_Firewall extends ICWP_WPSF_Processor_BaseWpsf {
308
  $oWp->wpDie( $this->getFirewallDieMessageForDisplay() );
309
  break;
310
  case 'redirect_home':
311
- header( "Location: " . $oWp->getHomeUrl() );
312
  break;
313
  case 'redirect_404':
314
- header( "Location: " . $oWp->getHomeUrl() . '/404' );
315
  break;
316
  default:
317
  break;
@@ -468,15 +468,15 @@ class ICWP_WPSF_Processor_Firewall extends ICWP_WPSF_Processor_BaseWpsf {
468
  $aMessage = array(
469
  sprintf( _wpsf__( '%s has blocked a page visit to your site.' ), $this->getController()->getHumanName() ),
470
  _wpsf__( 'Log details for this visitor are below:' ),
471
- '- ' . sprintf( _wpsf__( 'IP Address: %s' ), $sIp )
472
  );
473
  $aMessage = array_merge( $aMessage, $this->getRawAuditMessage( '- ' ) );
474
  // TODO: Get audit trail messages
475
- $aMessage[] = sprintf( _wpsf__( 'You can look up the offending IP Address here: %s' ), 'http://ip-lookup.net/?ip=' . $sIp );
476
- $sEmailSubject = sprintf( _wpsf__( 'Firewall Block Email Alert for %s' ), $this->loadWp()->getHomeUrl() );
477
 
478
- $fSendSuccess = $this->getEmailProcessor()->sendEmailTo( $sRecipient, $sEmailSubject, $aMessage );
479
- return $fSendSuccess;
480
  }
481
 
482
  /**
4
  return;
5
  }
6
 
7
+ require_once( dirname( __FILE__ ).DIRECTORY_SEPARATOR.'base_wpsf.php' );
8
 
9
  class ICWP_WPSF_Processor_Firewall extends ICWP_WPSF_Processor_BaseWpsf {
10
 
162
  if ( $bFAIL ) {
163
  $sAuditMessage = sprintf( _wpsf__( 'Firewall Trigger: %s.' ), _wpsf__( 'EXE File Uploads' ) );
164
  $this->addToAuditEntry( $sAuditMessage, 3, 'firewall_block' );
165
+ $this->doStatIncrement( 'firewall.blocked.'.$sKey );
166
  $this->setFirewallTrip_Class( $sKey );
167
  }
168
  }
213
  if ( $bFAIL ) {
214
  $this->addToFirewallDieMessage( _wpsf__( "Something in the URL, Form or Cookie data wasn't appropriate." ) );
215
  $sAuditMessage = _wpsf__( 'Page parameter failed firewall check.' )
216
+ .' '.sprintf( _wpsf__( 'The offending parameter was "%s" with a value of "%s".' ), $sParam, $mValue );
217
  $this->addToAuditEntry( $sAuditMessage, 3 );
218
  $this->setFirewallTrip_Parameter( $sParam );
219
  $this->setFirewallTrip_Value( $mValue );
220
 
221
  $sAuditMessage = sprintf( _wpsf__( 'Firewall Trigger: %s.' ), $this->getFirewallBlockKeyName( $sTermsKey ) );
222
  $this->addToAuditEntry( $sAuditMessage, 3, 'firewall_block' );
223
+ $this->doStatIncrement( 'firewall.blocked.'.$sTermsKey );
224
  $this->setFirewallTrip_Class( $sTermsKey );
225
  }
226
 
246
  * @return string
247
  */
248
  private function prepRegexTerms( $sTerm ) {
249
+ return '/'.$sTerm.'/i';
250
  }
251
 
252
  /**
308
  $oWp->wpDie( $this->getFirewallDieMessageForDisplay() );
309
  break;
310
  case 'redirect_home':
311
+ header( "Location: ".$oWp->getHomeUrl() );
312
  break;
313
  case 'redirect_404':
314
+ header( "Location: ".$oWp->getHomeUrl().'/404' );
315
  break;
316
  default:
317
  break;
468
  $aMessage = array(
469
  sprintf( _wpsf__( '%s has blocked a page visit to your site.' ), $this->getController()->getHumanName() ),
470
  _wpsf__( 'Log details for this visitor are below:' ),
471
+ '- '.sprintf( _wpsf__( 'IP Address: %s' ), $sIp )
472
  );
473
  $aMessage = array_merge( $aMessage, $this->getRawAuditMessage( '- ' ) );
474
  // TODO: Get audit trail messages
475
+ $aMessage[] = sprintf( _wpsf__( 'You can look up the offending IP Address here: %s' ), 'http://ip-lookup.net/?ip='.$sIp );
476
+ $sEmailSubject = _wpsf__( 'Firewall Block Alert' );
477
 
478
+ return $this->getEmailProcessor()
479
+ ->sendEmailTo( $sRecipient, $sEmailSubject, $aMessage );
480
  }
481
 
482
  /**
src/processors/hack_protect.php CHANGED
@@ -35,6 +35,9 @@ class ICWP_WPSF_Processor_HackProtect extends ICWP_WPSF_Processor_BaseWpsf {
35
  if ( $oFO->isIcEnabled() ) {
36
  $this->getSubProcessorIntegrity()->run();
37
  }
 
 
 
38
  }
39
 
40
  /**
@@ -75,6 +78,12 @@ class ICWP_WPSF_Processor_HackProtect extends ICWP_WPSF_Processor_BaseWpsf {
75
  ->run();
76
  }
77
 
 
 
 
 
 
 
78
  /**
79
  * @return ICWP_WPSF_Processor_HackProtect_CoreChecksumScan
80
  */
@@ -110,6 +119,19 @@ class ICWP_WPSF_Processor_HackProtect extends ICWP_WPSF_Processor_BaseWpsf {
110
  return $oProc;
111
  }
112
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  /**
114
  * @return ICWP_WPSF_Processor_HackProtect_WpVulnScan
115
  */
35
  if ( $oFO->isIcEnabled() ) {
36
  $this->getSubProcessorIntegrity()->run();
37
  }
38
+ if ( $oFO->isPtgEnabled() ) {
39
+ $this->runPTGuard();
40
+ }
41
  }
42
 
43
  /**
78
  ->run();
79
  }
80
 
81
+ /**
82
+ */
83
+ protected function runPTGuard() {
84
+ $this->getSubProcessorGuard()->run();
85
+ }
86
+
87
  /**
88
  * @return ICWP_WPSF_Processor_HackProtect_CoreChecksumScan
89
  */
119
  return $oProc;
120
  }
121
 
122
+ /**
123
+ * @return ICWP_WPSF_Processor_HackProtect_PTGuard
124
+ */
125
+ public function getSubProcessorGuard() {
126
+ $oProc = $this->getSubProcessor( 'ptguard' );
127
+ if ( is_null( $oProc ) ) {
128
+ require_once( dirname( __FILE__ ).'/hackprotect_ptguard.php' );
129
+ $oProc = new ICWP_WPSF_Processor_HackProtect_PTGuard( $this->getFeature() );
130
+ $this->aSubProcessors[ 'ptguard' ] = $oProc;
131
+ }
132
+ return $oProc;
133
+ }
134
+
135
  /**
136
  * @return ICWP_WPSF_Processor_HackProtect_WpVulnScan
137
  */
src/processors/hackprotect_corechecksumscan.php CHANGED
@@ -14,13 +14,13 @@ class ICWP_WPSF_Processor_HackProtect_CoreChecksumScan extends ICWP_WPSF_Process
14
  $this->setupChecksumCron();
15
 
16
  if ( $this->loadWpUsers()->isUserAdmin() ) {
17
- $oDp = $this->loadDataProcessor();
18
 
19
- if ( $oDp->FetchGet( 'force_checksumscan' ) == 1 ) {
20
  $this->cron_dailyChecksumScan();
21
  }
22
  else {
23
- $sAction = $oDp->FetchGet( 'shield_action' );
24
  switch ( $sAction ) {
25
 
26
  case 'repair_file':
@@ -139,7 +139,6 @@ class ICWP_WPSF_Processor_HackProtect_CoreChecksumScan extends ICWP_WPSF_Process
139
  }
140
 
141
  public function cron_dailyChecksumScan() {
142
-
143
  if ( doing_action( 'wp_maybe_auto_update' ) || did_action( 'wp_maybe_auto_update' ) ) {
144
  return;
145
  }
@@ -147,9 +146,9 @@ class ICWP_WPSF_Processor_HackProtect_CoreChecksumScan extends ICWP_WPSF_Process
147
  $bOptionRepair = $this->getIsOption( 'attempt_auto_file_repair', 'Y' )
148
  || ( $this->loadDP()->query( 'checksum_repair' ) == 1 );
149
 
150
- $aDiscoveredFiles = $this->doChecksumScan( $bOptionRepair );
151
- if ( !empty( $aDiscoveredFiles[ 'checksum_mismatch' ] ) || !empty( $aDiscoveredFiles[ 'missing' ] ) ) {
152
- $this->sendChecksumErrorNotification( $aDiscoveredFiles );
153
  }
154
  }
155
 
@@ -157,7 +156,7 @@ class ICWP_WPSF_Processor_HackProtect_CoreChecksumScan extends ICWP_WPSF_Process
157
  * @return array
158
  */
159
  protected function getFullExclusions() {
160
- $aExclusions = $this->getFeature()->getDefinition( 'corechecksum_exclusions' );
161
  if ( empty( $aExclusions ) || !is_array( $aExclusions ) ) {
162
  $aExclusions = array();
163
  }
@@ -178,7 +177,7 @@ class ICWP_WPSF_Processor_HackProtect_CoreChecksumScan extends ICWP_WPSF_Process
178
  * @return array
179
  */
180
  protected function getMissingOnlyExclusions() {
181
- $aExclusions = $this->getFeature()->getDefinition( 'corechecksum_exclusions_missing_only' );
182
  if ( empty( $aExclusions ) || !is_array( $aExclusions ) ) {
183
  $aExclusions = array();
184
  }
@@ -197,10 +196,10 @@ class ICWP_WPSF_Processor_HackProtect_CoreChecksumScan extends ICWP_WPSF_Process
197
  $sLocale = $this->loadWp()->getLocale( true );
198
  $bUseInternational = $bUseLocale && ( $sLocale != 'en_US' );
199
  if ( $bUseInternational ) {
200
- $sRootUrl = $this->getFeature()->getDefinition( 'url_wordress_core_svn_il8n' ).$sLocale;
201
  }
202
  else {
203
- $sRootUrl = $this->getFeature()->getDefinition( 'url_wordress_core_svn' );
204
  }
205
  $sFileUrl = sprintf(
206
  '%s/tags/%s/%s',
@@ -232,36 +231,97 @@ class ICWP_WPSF_Processor_HackProtect_CoreChecksumScan extends ICWP_WPSF_Process
232
  return false;
233
  }
234
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
  /**
236
  * @param array $aFiles
237
- * @return bool
238
  */
239
- protected function sendChecksumErrorNotification( $aFiles ) {
240
- if ( empty( $aFiles ) && empty( $aFiles[ 'missing' ] ) && empty( $aFiles[ 'checksum_mismatch' ] ) ) {
241
- return true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
  }
243
 
244
- $sHomeUrl = $this->loadWp()->getHomeUrl();
245
- $aContent = array(
246
- sprintf( _wpsf__( '%s has detected files on your site with potential problems.' ), $this->getController()
247
- ->getHumanName() ),
248
- _wpsf__( 'This is sent from the WordPress Core File Scanner, part of the Hack Guard module.' )
249
- .' [<a href="http://icwp.io/moreinfochecksum">'._wpsf__( 'More Info' ).']</a>',
250
- sprintf( _wpsf__( 'Site Home URL - %s' ), sprintf( '<a href="%s" target="_blank">%s</a>', $sHomeUrl, $sHomeUrl ) ),
251
- '',
252
- _wpsf__( 'Details for the problem files are below:' ),
253
  );
254
 
 
 
 
 
 
 
 
 
 
 
 
255
  if ( !empty( $aFiles[ 'checksum_mismatch' ] ) ) {
256
- $aContent[] = '';
257
- $aContent[] = _wpsf__( 'The MD5 Checksum Hashes for following core files do not match the official WordPress.org Checksum Hashes:' );
258
  foreach ( $aFiles[ 'checksum_mismatch' ] as $sFile ) {
259
  $aContent[] = ' - '.$sFile.$this->getFileRepairLink( $sFile );
260
  }
261
  }
262
  if ( !empty( $aFiles[ 'missing' ] ) ) {
263
- $aContent[] = '';
264
- $aContent[] = _wpsf__( 'The following official WordPress core files are missing from your site:' );
265
  foreach ( $aFiles[ 'missing' ] as $sFile ) {
266
  $aContent[] = ' - '.$sFile.$this->getFileRepairLink( $sFile );
267
  }
@@ -278,30 +338,7 @@ class ICWP_WPSF_Processor_HackProtect_CoreChecksumScan extends ICWP_WPSF_Process
278
  .' [<a href="http://icwp.io/moreinfochecksum">'._wpsf__( 'More Info' ).']</a>';
279
  }
280
 
281
- $aContent[] = '';
282
-
283
- /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
284
- $oFO = $this->getFeature();
285
- if ( $oFO->canRunWizards() ) {
286
- $aContent[] = sprintf( '<a href="%s" target="_blank" style="%s">%s →</a>',
287
- $oFO->getUrl_Wizard( 'wcf' ),
288
- 'border:1px solid;padding:20px;line-height:19px;margin:10px 20px;display:inline-block;text-align:center;width:290px;font-size:18px;',
289
- _wpsf__( 'Run the scanner manually' )
290
- );
291
- $aContent[] = '';
292
- }
293
-
294
- $sRecipient = $this->getPluginDefaultRecipientAddress();
295
- $sEmailSubject = sprintf( _wpsf__( 'Warning - %s' ), _wpsf__( 'Core WordPress Files(s) Discovered That May Have Been Modified.' ) );
296
- $bSendSuccess = $this->getEmailProcessor()->sendEmailTo( $sRecipient, $sEmailSubject, $aContent );
297
-
298
- if ( $bSendSuccess ) {
299
- $this->addToAuditEntry( sprintf( _wpsf__( 'Successfully sent Checksum Scan Notification email alert to: %s' ), $sRecipient ) );
300
- }
301
- else {
302
- $this->addToAuditEntry( sprintf( _wpsf__( 'Failed to send Checksum Scan Notification email alert to: %s' ), $sRecipient ) );
303
- }
304
- return $bSendSuccess;
305
  }
306
 
307
  /**
@@ -318,8 +355,8 @@ class ICWP_WPSF_Processor_HackProtect_CoreChecksumScan extends ICWP_WPSF_Process
318
  $this->loadWp()->getUrl_WpAdmin()
319
  ),
320
  _wpsf__( 'Repair file now' ),
321
- $this->getFeature()->getDefinition( 'url_wordress_core_svn' ).'tags/'.$this->loadWp()
322
- ->getVersion().'/'.$sFile,
323
  _wpsf__( 'WordPress.org source file' )
324
  );
325
  }
@@ -329,7 +366,7 @@ class ICWP_WPSF_Processor_HackProtect_CoreChecksumScan extends ICWP_WPSF_Process
329
  */
330
  protected function getCronName() {
331
  $oFO = $this->getFeature();
332
- return $oFO->prefixOptionKey( $oFO->getDefinition( 'corechecksum_cron_name' ) );
333
  }
334
 
335
  private function convertMd5FilePathToActual( $sMd5FilePath ) {
14
  $this->setupChecksumCron();
15
 
16
  if ( $this->loadWpUsers()->isUserAdmin() ) {
17
+ $oDp = $this->loadDP();
18
 
19
+ if ( $oDp->query( 'force_checksumscan' ) == 1 ) {
20
  $this->cron_dailyChecksumScan();
21
  }
22
  else {
23
+ $sAction = $oDp->query( 'shield_action' );
24
  switch ( $sAction ) {
25
 
26
  case 'repair_file':
139
  }
140
 
141
  public function cron_dailyChecksumScan() {
 
142
  if ( doing_action( 'wp_maybe_auto_update' ) || did_action( 'wp_maybe_auto_update' ) ) {
143
  return;
144
  }
146
  $bOptionRepair = $this->getIsOption( 'attempt_auto_file_repair', 'Y' )
147
  || ( $this->loadDP()->query( 'checksum_repair' ) == 1 );
148
 
149
+ $aFiles = $this->doChecksumScan( $bOptionRepair );
150
+ if ( !empty( $aFiles[ 'checksum_mismatch' ] ) || !empty( $aFiles[ 'missing' ] ) ) {
151
+ $this->emailResults( $aFiles );
152
  }
153
  }
154
 
156
  * @return array
157
  */
158
  protected function getFullExclusions() {
159
+ $aExclusions = $this->getFeature()->getDef( 'corechecksum_exclusions' );
160
  if ( empty( $aExclusions ) || !is_array( $aExclusions ) ) {
161
  $aExclusions = array();
162
  }
177
  * @return array
178
  */
179
  protected function getMissingOnlyExclusions() {
180
+ $aExclusions = $this->getFeature()->getDef( 'corechecksum_exclusions_missing_only' );
181
  if ( empty( $aExclusions ) || !is_array( $aExclusions ) ) {
182
  $aExclusions = array();
183
  }
196
  $sLocale = $this->loadWp()->getLocale( true );
197
  $bUseInternational = $bUseLocale && ( $sLocale != 'en_US' );
198
  if ( $bUseInternational ) {
199
+ $sRootUrl = $this->getFeature()->getDef( 'url_wordress_core_svn_il8n' ).$sLocale;
200
  }
201
  else {
202
+ $sRootUrl = $this->getFeature()->getDef( 'url_wordress_core_svn' );
203
  }
204
  $sFileUrl = sprintf(
205
  '%s/tags/%s/%s',
231
  return false;
232
  }
233
 
234
+ /**
235
+ * @param array[][] $aFiles
236
+ */
237
+ protected function emailResults( $aFiles ) {
238
+ /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
239
+ $oFO = $this->getFeature();
240
+
241
+ $sName = $this->getController()->getHumanName();
242
+ $sHomeUrl = $this->loadWp()->getHomeUrl();
243
+
244
+ $aContent = array_merge(
245
+ array(
246
+ sprintf( _wpsf__( "The %s Core File Scanner found files with potential problems." ), $sName ),
247
+ sprintf( _wpsf__( 'Site URL - %s' ), sprintf( '<a href="%s" target="_blank">%s</a>', $sHomeUrl, $sHomeUrl ) ),
248
+ ''
249
+ ),
250
+ $oFO->canRunWizards() ? $this->buildEmailBody( $aFiles ) : $this->buildEmailBody_Legacy( $aFiles )
251
+ );
252
+
253
+ $aContent[] = '';
254
+ $aContent[] = '[ <a href="http://icwp.io/moreinfochecksum">'._wpsf__( 'More Info On This Scanner' ).' ]</a>';
255
+
256
+ $this->getEmailProcessor()
257
+ ->sendEmailTo(
258
+ $this->getPluginDefaultRecipientAddress(),
259
+ sprintf( _wpsf__( 'Warning - %s' ), _wpsf__( 'Modified Core WordPress Files Discovered' ) ),
260
+ $aContent
261
+ );
262
+
263
+ $this->addToAuditEntry(
264
+ sprintf( _wpsf__( 'Sent Checksum Scan Notification email alert to: %s' ), $this->getPluginDefaultRecipientAddress() )
265
+ );
266
+ }
267
+
268
  /**
269
  * @param array $aFiles
270
+ * @return array
271
  */
272
+ private function buildEmailBody( $aFiles ) {
273
+ /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
274
+ $oFO = $this->getFeature();
275
+ $sName = $this->getController()->getHumanName();
276
+
277
+ $aContent = array();
278
+
279
+ if ( $this->getIsOption( 'attempt_auto_file_repair', 'Y' ) ) {
280
+ $aContent[] = sprintf( _wpsf__( "%s has already attempted to repair the files." ), $sName );
281
+
282
+ if ( !empty( $aFiles[ 'checksum_mismatch' ] ) ) {
283
+ $aContent[] = '';
284
+ $aContent[] = _wpsf__( "The contents of the core files listed below don't match official WordPress files:" );
285
+ foreach ( $aFiles[ 'checksum_mismatch' ] as $sFile ) {
286
+ $aContent[] = ' - '.$sFile.$this->getFileRepairLink( $sFile );
287
+ }
288
+ }
289
+ if ( !empty( $aFiles[ 'missing' ] ) ) {
290
+ $aContent[] = '';
291
+ $aContent[] = _wpsf__( 'The WordPress Core Files listed below are missing:' );
292
+ foreach ( $aFiles[ 'missing' ] as $sFile ) {
293
+ $aContent[] = ' - '.$sFile.$this->getFileRepairLink( $sFile );
294
+ }
295
+ }
296
  }
297
 
298
+ $aContent[] = '';
299
+ $aContent[] = _wpsf__( 'We recommend you run the scanner to review your site:' );
300
+ $aContent[] = sprintf( '<a href="%s" target="_blank" style="%s">%s →</a>',
301
+ $oFO->getUrl_Wizard( 'wcf' ),
302
+ 'border:1px solid;padding:20px;line-height:19px;margin:10px 20px;display:inline-block;text-align:center;width:290px;font-size:18px;',
303
+ _wpsf__( 'Run Scanner' )
 
 
 
304
  );
305
 
306
+ return $aContent;
307
+ }
308
+
309
+ /**
310
+ * @param array $aFiles
311
+ * @return array
312
+ */
313
+ private function buildEmailBody_Legacy( $aFiles ) {
314
+
315
+ $aContent = array();
316
+
317
  if ( !empty( $aFiles[ 'checksum_mismatch' ] ) ) {
318
+ $aContent[] = _wpsf__( "The contents of the core files listed below don't match official WordPress files:" );
 
319
  foreach ( $aFiles[ 'checksum_mismatch' ] as $sFile ) {
320
  $aContent[] = ' - '.$sFile.$this->getFileRepairLink( $sFile );
321
  }
322
  }
323
  if ( !empty( $aFiles[ 'missing' ] ) ) {
324
+ $aContent[] = _wpsf__( 'The WordPress Core Files listed below are missing:' );
 
325
  foreach ( $aFiles[ 'missing' ] as $sFile ) {
326
  $aContent[] = ' - '.$sFile.$this->getFileRepairLink( $sFile );
327
  }
338
  .' [<a href="http://icwp.io/moreinfochecksum">'._wpsf__( 'More Info' ).']</a>';
339
  }
340
 
341
+ return $aContent;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
342
  }
343
 
344
  /**
355
  $this->loadWp()->getUrl_WpAdmin()
356
  ),
357
  _wpsf__( 'Repair file now' ),
358
+ $this->getFeature()->getDef( 'url_wordress_core_svn' )
359
+ .'tags/'.$this->loadWp()->getVersion().'/'.$sFile,
360
  _wpsf__( 'WordPress.org source file' )
361
  );
362
  }
366
  */
367
  protected function getCronName() {
368
  $oFO = $this->getFeature();
369
+ return $oFO->prefixOptionKey( $oFO->getDef( 'corechecksum_cron_name' ) );
370
  }
371
 
372
  private function convertMd5FilePathToActual( $sMd5FilePath ) {
src/processors/hackprotect_filecleanerscan.php CHANGED
@@ -195,7 +195,7 @@ class ICWP_WPSF_Processor_HackProtect_FileCleanerScan extends ICWP_WPSF_Processo
195
  $this->deleteFiles( $aDiscoveredFiles );
196
  }
197
  if ( $oFO->isUfsSendReport() ) {
198
- $this->sendEmailNotification( $aDiscoveredFiles );
199
  }
200
  }
201
  }
@@ -216,62 +216,92 @@ class ICWP_WPSF_Processor_HackProtect_FileCleanerScan extends ICWP_WPSF_Processo
216
 
217
  /**
218
  * @param array $aFiles
219
- * @return bool
220
  */
221
- protected function sendEmailNotification( $aFiles ) {
222
- if ( empty( $aFiles ) ) {
223
- return true;
224
- }
225
  /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
226
  $oFO = $this->getFeature();
 
 
227
  $sHomeUrl = $this->loadWp()->getHomeUrl();
228
- $aContent = array(
229
- sprintf( _wpsf__( '%s detected files on your site which are not recognised.' ), $this->getController()
230
- ->getHumanName() ),
231
- _wpsf__( 'This is sent from the WordPress Unrecognised File Scanner, part of the Hack Guard module.' )
232
- .' [<a href="http://icwp.io/shieldmoreinfounrecognised">'._wpsf__( 'More Info' ).']</a>',
233
- '',
234
- sprintf( _wpsf__( 'Site Home URL - %s' ), sprintf( '<a href="%s" target="_blank">%s</a>', $sHomeUrl, $sHomeUrl ) ),
235
- _wpsf__( 'The following files are considered "unrecognised" and should be examined:' ),
236
- ''
237
- );
238
 
239
- foreach ( $aFiles as $sFile ) {
240
- $aContent[] = ' - '.$sFile;
241
- }
 
 
 
 
 
242
 
243
  $aContent[] = '';
244
- if ( $oFO->canRunWizards() ) {
245
- $aContent[] = sprintf( '<a href="%s" target="_blank" style="%s">%s →</a>',
246
- $oFO->getUrl_Wizard( 'ufc' ),
247
- 'border:1px solid;padding:20px;line-height:19px;margin:10px 20px;display:inline-block;text-align:center;width:290px;font-size:18px;',
248
- _wpsf__( 'Run the scanner manually' )
249
- );
250
- $aContent[] = '';
251
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252
 
253
  if ( $oFO->isUfcDeleteFiles() ) {
254
- $aContent[] = _wpsf__( 'We have already attempted to delete these files based on your current settings.' )
255
- .' '._wpsf__( 'But, you should always check these files to ensure everything is as you expect.' );
256
- }
257
- else {
258
- $aContent[] = _wpsf__( 'You should review these files and remove them if required.' );
259
- $aContent[] = _wpsf__( 'You can now add these file names to your exclusion list to no longer be warned about them.' );
260
- $aContent[] = _wpsf__( 'Alternatively you can have the plugin attempt to delete these files automatically.' )
261
- .' [<a href="http://icwp.io/shieldmoreinfounrecognised">'._wpsf__( 'More Info' ).']</a>';
262
  }
263
 
264
- $sRecipient = $this->getPluginDefaultRecipientAddress();
265
- $sEmailSubject = sprintf( _wpsf__( 'Warning - %s' ), _wpsf__( 'Unrecognised WordPress Files(s) Detected.' ) );
266
- $bSendSuccess = $this->getEmailProcessor()->sendEmailTo( $sRecipient, $sEmailSubject, $aContent );
 
 
 
 
 
267
 
268
- if ( $bSendSuccess ) {
269
- $this->addToAuditEntry( sprintf( _wpsf__( 'Successfully sent Unrecognised File Scan notification email alert to: %s' ), $sRecipient ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
270
  }
271
- else {
272
- $this->addToAuditEntry( sprintf( _wpsf__( 'Failed to send Unrecognised File Scan notification email alert to: %s' ), $sRecipient ) );
 
 
273
  }
274
- return $bSendSuccess;
 
275
  }
276
 
277
  /**
@@ -299,8 +329,8 @@ class ICWP_WPSF_Processor_HackProtect_FileCleanerScan extends ICWP_WPSF_Processo
299
  $this->loadWp()->getUrl_WpAdmin()
300
  ),
301
  _wpsf__( 'Repair file now' ),
302
- $this->getFeature()->getDefinition( 'url_wordress_core_svn' ).'tags/'.$this->loadWp()
303
- ->getVersion().'/'.$sFile,
304
  _wpsf__( 'WordPress.org source file' )
305
  );
306
  }
195
  $this->deleteFiles( $aDiscoveredFiles );
196
  }
197
  if ( $oFO->isUfsSendReport() ) {
198
+ $this->emailResults( $aDiscoveredFiles );
199
  }
200
  }
201
  }
216
 
217
  /**
218
  * @param array $aFiles
 
219
  */
220
+ protected function emailResults( $aFiles ) {
 
 
 
221
  /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
222
  $oFO = $this->getFeature();
223
+
224
+ $sName = $this->getController()->getHumanName();
225
  $sHomeUrl = $this->loadWp()->getHomeUrl();
 
 
 
 
 
 
 
 
 
 
226
 
227
+ $aContent = array_merge(
228
+ array(
229
+ sprintf( _wpsf__( 'The %s Unrecognised File Scanner found files which you need to review.' ), $sName ),
230
+ sprintf( _wpsf__( 'Site URL - %s' ), sprintf( '<a href="%s" target="_blank">%s</a>', $sHomeUrl, $sHomeUrl ) ),
231
+ ''
232
+ ),
233
+ $oFO->canRunWizards() ? $this->buildEmailBody( $aFiles ) : $this->buildEmailBody_Legacy( $aFiles )
234
+ );
235
 
236
  $aContent[] = '';
237
+ $aContent[] = '[ <a href="http://icwp.io/moreinfochecksum">'._wpsf__( 'More Info On This Scanner' ).' ]</a>';
238
+
239
+ $this->getEmailProcessor()
240
+ ->sendEmailTo(
241
+ $this->getPluginDefaultRecipientAddress(),
242
+ sprintf( _wpsf__( 'Warning - %s' ), _wpsf__( 'Unrecognised WordPress Files Detected' ) ),
243
+ $aContent
244
+ );
245
+
246
+ $this->addToAuditEntry(
247
+ sprintf( _wpsf__( 'Sent Unrecognised File Scan Notification email alert to: %s' ), $this->getPluginDefaultRecipientAddress() )
248
+ );
249
+ }
250
+
251
+ /**
252
+ * The newer approach is to only enumerate files if they were deleted
253
+ * @param string[] $aFiles
254
+ * @return string[]
255
+ */
256
+ private function buildEmailBody( $aFiles ) {
257
+ /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
258
+ $oFO = $this->getFeature();
259
+ $sName = $this->getController()->getHumanName();
260
+
261
+ $aContent = array();
262
 
263
  if ( $oFO->isUfcDeleteFiles() ) {
264
+ $aContent[] = 'Files that were discovered:';
265
+ foreach ( $aFiles as $sFile ) {
266
+ $aContent[] = ' - '.$sFile;
267
+ }
268
+ $aContent[] = '';
269
+ $aContent[] = sprintf( _wpsf__( '%s has attempted to delete these files based on your current settings.' ), $sName );
270
+ $aContent[] = '';
 
271
  }
272
 
273
+ $aContent[] = sprintf( '<a href="%s" target="_blank" style="%s">%s →</a>',
274
+ $oFO->getUrl_Wizard( 'ufc' ),
275
+ 'border:1px solid;padding:20px;line-height:19px;margin:10px 20px;display:inline-block;text-align:center;width:290px;font-size:18px;',
276
+ _wpsf__( 'Run Scanner' )
277
+ );
278
+
279
+ return $aContent;
280
+ }
281
 
282
+ /**
283
+ * Assumes cannot run wizard
284
+ * The older approach was to always enumerate files regardless of whether they were deleted
285
+ * @param string[] $aFiles
286
+ * @return string[]
287
+ */
288
+ private function buildEmailBody_Legacy( $aFiles ) {
289
+ /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
290
+ $oFO = $this->getFeature();
291
+ $sName = $this->getController()->getHumanName();
292
+
293
+ $aContent = array();
294
+ $aContent[] = 'Files that were discovered:';
295
+ foreach ( $aFiles as $sFile ) {
296
+ $aContent[] = ' - '.$sFile;
297
  }
298
+
299
+ if ( $oFO->isUfcDeleteFiles() ) {
300
+ $aContent[] = '';
301
+ $aContent[] = sprintf( _wpsf__( '%s has attempted to delete these files based on your current settings.' ), $sName );
302
  }
303
+
304
+ return $aContent;
305
  }
306
 
307
  /**
329
  $this->loadWp()->getUrl_WpAdmin()
330
  ),
331
  _wpsf__( 'Repair file now' ),
332
+ $this->getFeature()->getDef( 'url_wordress_core_svn' )
333
+ .'tags/'.$this->loadWp()->getVersion().'/'.$sFile,
334
  _wpsf__( 'WordPress.org source file' )
335
  );
336
  }
src/processors/hackprotect_pluginvulnerabilities.php CHANGED
@@ -108,7 +108,8 @@ if ( !class_exists( 'ICWP_WPSF_Processor_HackProtect_PluginVulnerabilities', fal
108
 
109
  $sEmailSubject = sprintf( _wpsf__( 'Warning - %s' ), _wpsf__( 'Plugin(s) Discovered With Known Security Vulnerabilities.' ) );
110
 
111
- $bSendSuccess = $this->getEmailProcessor()->sendEmailTo( $sRecipient, $sEmailSubject, $this->aEmailContents );
 
112
 
113
  if ( $bSendSuccess ) {
114
  $this->addToAuditEntry( sprintf( _wpsf__( 'Successfully sent Plugin Vulnerability Notification email alert to: %s' ), $sRecipient ) );
108
 
109
  $sEmailSubject = sprintf( _wpsf__( 'Warning - %s' ), _wpsf__( 'Plugin(s) Discovered With Known Security Vulnerabilities.' ) );
110
 
111
+ $bSendSuccess = $this->getEmailProcessor()
112
+ ->sendEmailTo( $sRecipient, $sEmailSubject, $this->aEmailContents );
113
 
114
  if ( $bSendSuccess ) {
115
  $this->addToAuditEntry( sprintf( _wpsf__( 'Successfully sent Plugin Vulnerability Notification email alert to: %s' ), $sRecipient ) );
src/processors/hackprotect_ptguard.php ADDED
@@ -0,0 +1,682 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( class_exists( 'ICWP_WPSF_Processor_HackProtect_PTGuard' ) ) {
4
+ return;
5
+ }
6
+
7
+ require_once( dirname( __FILE__ ).'/cronbase.php' );
8
+
9
+ class ICWP_WPSF_Processor_HackProtect_PTGuard extends ICWP_WPSF_Processor_CronBase {
10
+
11
+ const CONTEXT_PLUGINS = 'plugins';
12
+ const CONTEXT_THEMES = 'themes';
13
+
14
+ /**
15
+ */
16
+ public function run() {
17
+ parent::run();
18
+
19
+ /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
20
+ $oFO = $this->getFeature();
21
+ if ( $oFO->isPtgReadyToScan() ) {
22
+ add_action( 'upgrader_process_complete', array( $this, 'updateSnapshotAfterUpgrade' ), 10, 2 );
23
+ add_action( 'activated_plugin', array( $this, 'onActivatePlugin' ), 10 );
24
+ add_action( 'deactivated_plugin', array( $this, 'onDeactivatePlugin' ), 10 );
25
+ add_action( 'switch_theme', array( $this, 'onActivateTheme' ), 10, 0 );
26
+ }
27
+ else if ( $oFO->isPtgBuildRequired() ) {
28
+ $this->rebuildSnapshots(); // TODO: Consider if we can't write to disk - we do this forever.
29
+ if ( $this->storeExists( self::CONTEXT_PLUGINS ) && $this->storeExists( self::CONTEXT_THEMES ) ) {
30
+ $oFO->setPtgLastBuildAt();
31
+ }
32
+ }
33
+
34
+ if ( $oFO->isPtgReinstallLinks() ) {
35
+ add_filter( 'plugin_action_links', array( $this, 'addActionLinkRefresh' ), 50, 2 );
36
+ add_action( 'admin_footer', array( $this, 'printPluginReinstallDialogs' ) );
37
+ }
38
+ }
39
+
40
+ /**
41
+ * @param array $aLinks
42
+ * @param string $sPluginFile
43
+ * @return string[]
44
+ */
45
+ public function addActionLinkRefresh( $aLinks, $sPluginFile ) {
46
+ $oWpP = $this->loadWpPlugins();
47
+
48
+ if ( $oWpP->isWpOrg( $sPluginFile ) && !$oWpP->isUpdateAvailable( $sPluginFile ) ) {
49
+ $sLinkTemplate = '<a href="javascript:void(0)">%s</a>';
50
+ $aLinks[ 'icwp-reinstall' ] = sprintf(
51
+ $sLinkTemplate,
52
+ 'Re-Install'
53
+ );
54
+ }
55
+
56
+ return $aLinks;
57
+ }
58
+
59
+ public function printPluginReinstallDialogs() {
60
+
61
+ $aRenderData = array(
62
+ 'strings' => array(
63
+ 'editing_restricted' => _wpsf__( 'Editing this option is currently restricted.' ),
64
+ ),
65
+ 'js_snippets' => array()
66
+ );
67
+ echo $this->getFeature()
68
+ ->renderTemplate( 'snippets/hg-plugins-reinstall-dialogs.php', $aRenderData );
69
+ }
70
+
71
+ /**
72
+ * @param string $sBaseName
73
+ */
74
+ public function onActivatePlugin( $sBaseName ) {
75
+ $this->updateItemInSnapshot( $sBaseName, self::CONTEXT_PLUGINS );
76
+ }
77
+
78
+ /**
79
+ */
80
+ public function onActivateTheme() {
81
+ $this->deleteStore( self::CONTEXT_THEMES )
82
+ ->snapshotThemes();
83
+ }
84
+
85
+ /**
86
+ * @param string $sBaseName
87
+ */
88
+ public function onDeactivatePlugin( $sBaseName ) {
89
+ $this->deleteItemFromSnapshot( $sBaseName, self::CONTEXT_PLUGINS );
90
+ }
91
+
92
+ /**
93
+ * @param string $sBaseName
94
+ * @param string $sContext
95
+ * @return bool
96
+ */
97
+ public function reinstall( $sBaseName, $sContext = self::CONTEXT_PLUGINS ) {
98
+
99
+ if ( $sContext == self::CONTEXT_PLUGINS ) {
100
+ $oExecutor = $this->loadWpPlugins();
101
+ }
102
+ else {
103
+ $oExecutor = $this->loadWpThemes();
104
+ }
105
+
106
+ $bSuccess = $oExecutor->reinstall( $sBaseName, false );
107
+
108
+ if ( $bSuccess ) {
109
+ $this->updateItemInSnapshot( $sBaseName, $sContext );
110
+ }
111
+
112
+ return $bSuccess;
113
+ }
114
+
115
+ /**
116
+ * @param WP_Upgrader $oUpgrader
117
+ * @param array $aUpgradeInfo
118
+ */
119
+ public function updateSnapshotAfterUpgrade( $oUpgrader, $aUpgradeInfo ) {
120
+
121
+ $sContext = '';
122
+ if ( !empty( $aUpgradeInfo[ self::CONTEXT_PLUGINS ] ) ) {
123
+ $sContext = self::CONTEXT_PLUGINS;
124
+ }
125
+ else if ( !empty( $aUpgradeInfo[ self::CONTEXT_PLUGINS ] ) ) {
126
+ $sContext = self::CONTEXT_PLUGINS;
127
+ }
128
+
129
+ if ( !empty( $sContext ) ) {
130
+ foreach ( $aUpgradeInfo[ $sContext ] as $sSlug ) {
131
+ $this->updateItemInSnapshot( $sSlug, $sContext );
132
+ }
133
+ }
134
+ }
135
+
136
+ /**
137
+ * @param string $sSlug - the basename for plugin, or stylesheet for theme.
138
+ * @param string $sContext
139
+ * @return $this
140
+ */
141
+ public function deleteItemFromSnapshot( $sSlug, $sContext = self::CONTEXT_PLUGINS ) {
142
+ $aSnapshot = $this->loadSnapshotData( $sContext );
143
+ if ( isset( $aSnapshot[ $sSlug ] ) ) {
144
+ unset( $aSnapshot[ $sSlug ] );
145
+ $this->storeSnapshot( $aSnapshot, $sContext );
146
+ }
147
+ return $this;
148
+ }
149
+
150
+ /**
151
+ * Only snaps active.
152
+ * @param string $sSlug - the basename for plugin, or stylesheet for theme.
153
+ * @param string $sContext
154
+ * @return $this
155
+ */
156
+ public function updateItemInSnapshot( $sSlug, $sContext = self::CONTEXT_PLUGINS ) {
157
+
158
+ $aNewSnapData = null;
159
+ if ( $sContext == self::CONTEXT_PLUGINS && $this->loadWpPlugins()->isActive( $sSlug ) ) {
160
+ $aNewSnapData = $this->snapshotPlugin( $sSlug );
161
+ }
162
+ if ( $sContext == self::CONTEXT_THEMES && $this->loadWpThemes()->isActive( $sSlug, true ) ) {
163
+ $aNewSnapData = $this->snapshotTheme( $sSlug );
164
+ }
165
+
166
+ if ( $aNewSnapData ) {
167
+ $aSnapshot = $this->loadSnapshotData( $sContext );
168
+ $aSnapshot[ $sSlug ] = $aNewSnapData;
169
+ $this->storeSnapshot( $aSnapshot, $sContext );
170
+ }
171
+
172
+ return $this;
173
+ }
174
+
175
+ /**
176
+ * @return $this
177
+ */
178
+ public function rebuildSnapshots() {
179
+ return $this->deleteStores()
180
+ ->setupSnapshots();
181
+ }
182
+
183
+ /**
184
+ * @return $this
185
+ */
186
+ protected function setupSnapshots() {
187
+ $this->snapshotPlugins();
188
+ $this->snapshotThemes();
189
+ return $this;
190
+ }
191
+
192
+ /**
193
+ * @param string $sBaseFile
194
+ * @return array
195
+ */
196
+ private function snapshotPlugin( $sBaseFile ) {
197
+ $aPlugin = $this->loadWpPlugins()
198
+ ->getPlugin( $sBaseFile );
199
+
200
+ return array(
201
+ 'version' => $aPlugin[ 'Version' ],
202
+ 'ts' => $this->loadDP()->time(),
203
+ 'hashes' => $this->hashPluginFiles( $sBaseFile )
204
+ );
205
+ }
206
+
207
+ /**
208
+ * @param string $sSlug
209
+ * @return array
210
+ */
211
+ private function snapshotTheme( $sSlug ) {
212
+ $oTheme = $this->loadWpThemes()
213
+ ->getTheme( $sSlug );
214
+ return array(
215
+ 'version' => $oTheme->get( 'Version' ),
216
+ 'ts' => $this->loadDP()->time(),
217
+ 'hashes' => $this->hashThemeFiles( $sSlug )
218
+ );
219
+ }
220
+
221
+ /**
222
+ * @return $this
223
+ */
224
+ private function snapshotPlugins() {
225
+ $oWpPl = $this->loadWpPlugins();
226
+
227
+ $aSnapshot = array();
228
+ foreach ( $oWpPl->getInstalledPluginFiles() as $sBaseName ) {
229
+ if ( $oWpPl->isActive( $sBaseName ) ) {
230
+ $aSnapshot[ $sBaseName ] = $this->snapshotPlugin( $sBaseName );
231
+ }
232
+ }
233
+ return $this->storeSnapshot( $aSnapshot, self::CONTEXT_PLUGINS );
234
+ }
235
+
236
+ /**
237
+ * @return $this
238
+ */
239
+ private function snapshotThemes() {
240
+ $oWpThemes = $this->loadWpThemes();
241
+
242
+ $oActiveTheme = $oWpThemes->getCurrent();
243
+ $aThemes = array(
244
+ $oActiveTheme->get_stylesheet() => $oActiveTheme
245
+ );
246
+
247
+ if ( $oWpThemes->isActiveThemeAChild() ) { // is child theme
248
+ $oParent = $oWpThemes->getCurrentParent();
249
+ $aThemes[ $oActiveTheme->get_template() ] = $oParent;
250
+ }
251
+
252
+ $aSnapshot = array();
253
+ /** @var $oTheme WP_Theme */
254
+ foreach ( $aThemes as $sSlug => $oTheme ) {
255
+ $aSnapshot[ $sSlug ] = $this->snapshotTheme( $sSlug );
256
+ }
257
+ return $this->storeSnapshot( $aSnapshot, self::CONTEXT_THEMES );
258
+ }
259
+
260
+ /**
261
+ * @param string $sContext
262
+ * @return bool
263
+ */
264
+ protected function storeExists( $sContext = self::CONTEXT_PLUGINS ) {
265
+ return $this->loadFS()
266
+ ->isFile( path_join( $this->getSnapsBaseDir(), $sContext.'.txt' ) );
267
+ }
268
+
269
+ /**
270
+ * @return $this
271
+ */
272
+ public function deleteStores() {
273
+ return $this->deleteStore( self::CONTEXT_PLUGINS )
274
+ ->deleteStore( self::CONTEXT_THEMES );
275
+ }
276
+
277
+ /**
278
+ * @param string $sContext
279
+ * @return $this
280
+ */
281
+ public function deleteStore( $sContext = self::CONTEXT_PLUGINS ) {
282
+ $this->loadFS()
283
+ ->deleteDir( path_join( $this->getSnapsBaseDir(), $sContext.'.txt' ) );
284
+ return $this;
285
+ }
286
+
287
+ /**
288
+ * @param array $aSnapshot
289
+ * @param string $sContext
290
+ * @return $this
291
+ */
292
+ private function storeSnapshot( $aSnapshot, $sContext = self::CONTEXT_PLUGINS ) {
293
+ $oWpFs = $this->loadFS();
294
+ $sDir = $this->getSnapsBaseDir();
295
+ $sSnap = path_join( $sDir, $sContext.'.txt' );
296
+ $oWpFs->mkdir( $sDir );
297
+ $oWpFs->putFileContent( $sSnap, base64_encode( json_encode( $aSnapshot ) ) );
298
+ return $this;
299
+ }
300
+
301
+ /**
302
+ * @param string $sContext
303
+ * @return array
304
+ */
305
+ private function loadSnapshotData( $sContext = self::CONTEXT_PLUGINS ) {
306
+ $aDecoded = array();
307
+
308
+ $sSnap = path_join( $this->getSnapsBaseDir(), $sContext.'.txt' );
309
+
310
+ $sRaw = $this->loadFS()
311
+ ->getFileContent( $sSnap );
312
+ if ( !empty( $sRaw ) ) {
313
+ $aDecoded = json_decode( base64_decode( $sRaw ), true );
314
+ }
315
+ return $aDecoded;
316
+ }
317
+
318
+ /**
319
+ * @param string $sSlugBaseName
320
+ * @return string[]
321
+ */
322
+ protected function hashPluginFiles( $sSlugBaseName ) {
323
+ $sDir = dirname( path_join( WP_PLUGIN_DIR, $sSlugBaseName ) );
324
+ return $this->hashFilesInDir( $sDir );
325
+ }
326
+
327
+ /**
328
+ * @param string $sSlugStylesheet
329
+ * @return string[]
330
+ */
331
+ protected function hashThemeFiles( $sSlugStylesheet ) {
332
+ $sDir = $this->loadWpThemes()
333
+ ->getTheme( $sSlugStylesheet )
334
+ ->get_stylesheet_directory();
335
+ return $this->hashFilesInDir( $sDir );
336
+ }
337
+
338
+ /**
339
+ * @param string $sSlug
340
+ * @param string $sContext
341
+ * @return string[]
342
+ */
343
+ protected function hashFiles( $sSlug, $sContext = self::CONTEXT_PLUGINS ) {
344
+ switch ( $sContext ) {
345
+
346
+ case self::CONTEXT_PLUGINS:
347
+ return $this->hashPluginFiles( $sSlug );
348
+ break;
349
+
350
+ case self::CONTEXT_THEMES:
351
+ return $this->hashThemeFiles( $sSlug );
352
+ break;
353
+
354
+ default:
355
+ return array();
356
+ break;
357
+ }
358
+ }
359
+
360
+ /**
361
+ * @param string $sDir
362
+ * @return string[]
363
+ */
364
+ private function hashFilesInDir( $sDir ) {
365
+ $aSnaps = array();
366
+ /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
367
+ $oFO = $this->getFeature();
368
+
369
+ $nDepth = $oFO->getPtgDepth();
370
+ foreach ( $this->loadFS()->getFilesInDir( $sDir, $nDepth, $this->getIterator( $sDir ) ) as $oFile ) {
371
+ $aSnaps[ $oFile->getRealPath() ] = md5_file( $oFile->getPathname() );
372
+ }
373
+ return $aSnaps;
374
+ }
375
+
376
+ /**
377
+ * @param string $sDir
378
+ * @return GuardRecursiveFilterIterator
379
+ */
380
+ private function getIterator( $sDir ) {
381
+ /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
382
+ $oFO = $this->getFeature();
383
+ $oIt = new GuardRecursiveFilterIterator( new RecursiveDirectoryIterator( $sDir ) );
384
+ return $oIt->setExtensions( $oFO->getPtgFileExtensions() );
385
+ }
386
+
387
+ /**
388
+ * Cron callback
389
+ */
390
+ public function cron_runGuardScan() {
391
+ $aPs = $this->scanPlugins();
392
+ $aTs = $this->scanThemes();
393
+
394
+ $aResults = array();
395
+ if ( !empty( $aPs ) ) {
396
+ $aResults[ self::CONTEXT_PLUGINS ] = $aPs;
397
+ }
398
+ if ( !empty( $aTs ) ) {
399
+ $aResults[ self::CONTEXT_THEMES ] = $aTs;
400
+ }
401
+
402
+ // Only email if there's results
403
+ if ( !empty( $aResults ) ) {
404
+
405
+ if ( $this->canSendResults( $aResults ) ) {
406
+ $this->emailResults( $aResults );
407
+ }
408
+ else {
409
+ $this->addToAuditEntry( _wpsf__( 'Silenced repeated email alert from Plugin/Theme Scan Guard' ) );
410
+ }
411
+ }
412
+ }
413
+
414
+ /**
415
+ * @param array[][] $aResults
416
+ */
417
+ protected function emailResults( $aResults ) {
418
+ /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
419
+ $oFO = $this->getFeature();
420
+
421
+ // Plugins
422
+ $aAllPlugins = array();
423
+ if ( isset( $aResults[ self::CONTEXT_PLUGINS ] ) ) {
424
+ $oPlgs = $this->loadWpPlugins();
425
+ $aAllPlugins = array_filter( array_map(
426
+ function ( $sBaseFile ) use ( $oPlgs ) {
427
+ $aData = $oPlgs->getPlugin( $sBaseFile );
428
+ return sprintf( '%s: v%s', $aData[ 'Name' ], ltrim( $aData[ 'Version' ], 'v' ) );
429
+ },
430
+ array_keys( $aResults[ self::CONTEXT_PLUGINS ] )
431
+ ) );
432
+ }
433
+
434
+ // Themes
435
+ $aAllThemes = array();
436
+ if ( isset( $aResults[ self::CONTEXT_THEMES ] ) ) {
437
+ $oThms = $this->loadWpThemes();
438
+ $aAllThemes = array_filter( array_map(
439
+ function ( $sBaseFile ) use ( $oThms ) {
440
+ $oTheme = $oThms->getTheme( $sBaseFile );
441
+ return sprintf( '%s: v%s', $oTheme->get( 'name' ), ltrim( $oTheme->get( 'version' ), 'v' ) );
442
+ },
443
+ array_keys( $aResults[ self::CONTEXT_THEMES ] )
444
+ ) );
445
+ }
446
+
447
+ $sName = $this->getController()->getHumanName();
448
+ $sHomeUrl = $this->loadWp()->getHomeUrl();
449
+
450
+ $aContent = array(
451
+ sprintf( _wpsf__( '%s has detected at least 1 Plugins/Themes have been modified on your site.' ), $sName ),
452
+ '',
453
+ sprintf( '<strong>%s</strong>', _wpsf__( 'You will receive only 1 email notification about these changes in a 1 week period.' ) ),
454
+ '',
455
+ sprintf( _wpsf__( 'Site URL - %s' ), sprintf( '<a href="%s" target="_blank">%s</a>', $sHomeUrl, $sHomeUrl ) ),
456
+ '',
457
+ _wpsf__( 'Details of the problem items are below:' ),
458
+ );
459
+
460
+ if ( !empty( $aAllPlugins ) ) {
461
+ $aContent[] = '';
462
+ $aContent[] = sprintf( '<strong>%s</strong>', _wpsf__( 'Modified Plugins:' ) );
463
+ foreach ( $aAllPlugins as $sPlugins ) {
464
+ $aContent[] = ' - '.$sPlugins;
465
+ }
466
+ }
467
+
468
+ if ( !empty( $aAllThemes ) ) {
469
+ $aContent[] = '';
470
+ $aContent[] = sprintf( '<strong>%s</strong>', _wpsf__( 'Modified Themes:' ) );
471
+ foreach ( $aAllThemes as $sTheme ) {
472
+ $aContent[] = ' - '.$sTheme;
473
+ }
474
+ }
475
+
476
+ if ( $oFO->canRunWizards() ) {
477
+ $aContent[] = sprintf( '<a href="%s" target="_blank" style="%s">%s →</a>',
478
+ $oFO->getUrl_Wizard( 'ptg' ),
479
+ 'border:1px solid;padding:20px;line-height:19px;margin:10px 20px;display:inline-block;text-align:center;width:290px;font-size:18px;',
480
+ _wpsf__( 'Run the scanner' )
481
+ );
482
+ $aContent[] = '';
483
+ }
484
+
485
+ $sRecipient = $this->getPluginDefaultRecipientAddress();
486
+ $sEmailSubject = sprintf( _wpsf__( 'Warning - %s' ), _wpsf__( 'Plugins/Themes Have Been Altered' ) );
487
+ $bSendSuccess = $this->getEmailProcessor()
488
+ ->sendEmailTo( $sRecipient, $sEmailSubject, $aContent );
489
+
490
+ if ( $bSendSuccess ) {
491
+ $this->addToAuditEntry( sprintf( _wpsf__( 'Successfully sent Plugin/Theme Guard email alert to: %s' ), $sRecipient ) );
492
+ }
493
+ else {
494
+ $this->addToAuditEntry( sprintf( _wpsf__( 'Failed to send Plugin/Theme Guard email alert to: %s' ), $sRecipient ) );
495
+ }
496
+ }
497
+
498
+ /**
499
+ * @param array $aResults
500
+ * @return bool
501
+ */
502
+ private function canSendResults( $aResults ) {
503
+ return ( $this->getResultsHashTime( md5( serialize( $aResults ) ) ) === 0 );
504
+ }
505
+
506
+ /**
507
+ * @param string $sResultHash
508
+ * @return int
509
+ */
510
+ private function getResultsHashTime( $sResultHash ) {
511
+ /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
512
+ $oFO = $this->getFeature();
513
+
514
+ $aTracking = $oFO->getPtgEmailTrackData();
515
+
516
+ $nSent = isset( $aTracking[ $sResultHash ] ) ? $aTracking[ $sResultHash ] : 0;
517
+
518
+ if ( $this->time() - $nSent > WEEK_IN_SECONDS ) { // reset
519
+ $nSent = 0;
520
+ }
521
+
522
+ if ( $nSent == 0 ) { // we've seen this changeset before.
523
+ $aTracking[ $sResultHash ] = $this->time();
524
+ $oFO->setPtgEmailTrackData( $aTracking );
525
+ }
526
+
527
+ return $nSent;
528
+ }
529
+
530
+ /**
531
+ * @return array[][]
532
+ */
533
+ public function scanPlugins() {
534
+ return $this->runSnapshotScan( self::CONTEXT_PLUGINS );
535
+ }
536
+
537
+ /**
538
+ * @return array[][]
539
+ */
540
+ public function scanThemes() {
541
+ return $this->runSnapshotScan( self::CONTEXT_THEMES );
542
+ }
543
+
544
+ /**
545
+ * @param string $sContext
546
+ * @return array[][] - keys are slugs
547
+ */
548
+ protected function runSnapshotScan( $sContext = self::CONTEXT_PLUGINS ) {
549
+
550
+ $aResults = array();
551
+
552
+ foreach ( $this->loadSnapshotData( $sContext ) as $sBaseName => $aSnap ) {
553
+
554
+ $aItemResults = array();
555
+
556
+ // First find the difference between live hashes and cached.
557
+ try {
558
+ $aLiveHashes = $this->hashFiles( $sBaseName, $sContext );
559
+ }
560
+ catch ( Exception $oE ) {
561
+ // happens when a plugin/theme no longer exists on disk and we try to get its hashes.
562
+ // an exception is thrown by the recursive directory iterator
563
+ $this->deleteItemFromSnapshot( $sBaseName, $sContext );
564
+ continue;
565
+ }
566
+
567
+ $aDifferent = array();
568
+ foreach ( $aSnap[ 'hashes' ] as $sFile => $sHash ) {
569
+ if ( $aLiveHashes[ $sFile ] != $sHash ) {
570
+ $aDifferent[] = $sFile;
571
+ }
572
+ }
573
+ if ( !empty( $aDifferent ) ) {
574
+ $aItemResults[ 'different' ] = $aDifferent;
575
+ }
576
+
577
+ // 2nd: Identify live files that exist but not in the cache.
578
+ $aUnrecog = array_diff_key( $aLiveHashes, $aSnap[ 'hashes' ] );
579
+ if ( !empty( $aUnrecog ) ) {
580
+ $aItemResults[ 'unrecognised' ] = array_keys( $aUnrecog );
581
+ }
582
+
583
+ // 3rd: Identify files in the cache but have disappeared from live
584
+ $aMiss = array_diff_key( $aSnap[ 'hashes' ], $aLiveHashes );
585
+ if ( !empty( $aMiss ) ) {
586
+ $aItemResults[ 'missing' ] = array_keys( $aMiss );
587
+ }
588
+
589
+ if ( !empty( $aItemResults ) ) {
590
+ $aResults[ $sBaseName ] = $aItemResults;
591
+ }
592
+ }
593
+
594
+ return $aResults;
595
+ }
596
+
597
+ /**
598
+ * @return callable
599
+ */
600
+ protected function getCronCallback() {
601
+ return array( $this, 'cron_runGuardScan' );
602
+ }
603
+
604
+ /**
605
+ * @return int
606
+ */
607
+ protected function getCronFrequency() {
608
+ /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
609
+ $oFO = $this->getFeature();
610
+ return $oFO->getScanFrequency();
611
+ }
612
+
613
+ /**
614
+ * @return int
615
+ */
616
+ protected function getCronName() {
617
+ /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
618
+ $oFO = $this->getFeature();
619
+ return $oFO->getPtgCronName();
620
+ }
621
+
622
+ /**
623
+ * @return string
624
+ */
625
+ private function getSnapsBaseDir() {
626
+ /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
627
+ $oFO = $this->getFeature();
628
+ return $oFO->getPtgSnapsBaseDir();
629
+ }
630
+ }
631
+
632
+ class GuardRecursiveFilterIterator extends RecursiveFilterIterator {
633
+
634
+ /**
635
+ * @var bool
636
+ */
637
+ private $bHasExtensions;
638
+
639
+ /**
640
+ * @var array
641
+ */
642
+ private $aExtensions;
643
+
644
+ /**
645
+ * @return string[]
646
+ */
647
+ public function getExtensions() {
648
+ return is_array( $this->aExtensions ) ? $this->aExtensions : array();
649
+ }
650
+
651
+ /**
652
+ * @return bool
653
+ */
654
+ public function hasExtensions() {
655
+ if ( !isset( $this->bHasExtensions ) ) {
656
+ $aExt = $this->getExtensions();
657
+ $this->bHasExtensions = !empty( $aExt );
658
+ }
659
+ return $this->bHasExtensions;
660
+ }
661
+
662
+ /**
663
+ * @param string[] $aExtensions
664
+ * @return GuardRecursiveFilterIterator
665
+ */
666
+ public function setExtensions( $aExtensions ) {
667
+ $this->aExtensions = $aExtensions;
668
+ return $this;
669
+ }
670
+
671
+ public function accept() {
672
+ /** @var SplFileInfo $oCurrent */
673
+ $oCurrent = $this->current();
674
+
675
+ $bConsumeFile = !in_array( $oCurrent->getFilename(), array( '.', '..' ) );
676
+ if ( $bConsumeFile && $oCurrent->isFile() && $this->hasExtensions() ) {
677
+ $bConsumeFile = in_array( $oCurrent->getExtension(), $this->getExtensions() );
678
+ }
679
+
680
+ return $bConsumeFile;
681
+ }
682
+ }
src/processors/hackprotect_wpvulnscan.php CHANGED
@@ -43,7 +43,7 @@ class ICWP_WPSF_Processor_HackProtect_WpVulnScan extends ICWP_WPSF_Processor_Bas
43
  /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
44
  $oFO = $this->getFeature();
45
  if ( $oFO->isWpvulnAutoupdatesEnabled() ) {
46
- add_filter( 'auto_update_plugin', array( $this, 'autoupdateVulnerablePlugins' ), 100, 2 );
47
  }
48
 
49
  try {
@@ -222,7 +222,8 @@ class ICWP_WPSF_Processor_HackProtect_WpVulnScan extends ICWP_WPSF_Processor_Bas
222
 
223
  $sSubject = sprintf( _wpsf__( 'Warning - %s' ), _wpsf__( 'Plugin(s) Discovered With Known Security Vulnerabilities.' ) );
224
  $sRecipient = $this->getPluginDefaultRecipientAddress();
225
- $bSendSuccess = $this->getEmailProcessor()->sendEmailTo( $sRecipient, $sSubject, $this->aNotifEmail );
 
226
 
227
  if ( $bSendSuccess ) {
228
  $this->addToAuditEntry( sprintf( _wpsf__( 'Successfully sent Plugin Vulnerability Notification email alert to: %s' ), $sRecipient ) );
43
  /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
44
  $oFO = $this->getFeature();
45
  if ( $oFO->isWpvulnAutoupdatesEnabled() ) {
46
+ add_filter( 'auto_update_plugin', array( $this, 'autoupdateVulnerablePlugins' ), PHP_INT_MAX, 2 );
47
  }
48
 
49
  try {
222
 
223
  $sSubject = sprintf( _wpsf__( 'Warning - %s' ), _wpsf__( 'Plugin(s) Discovered With Known Security Vulnerabilities.' ) );
224
  $sRecipient = $this->getPluginDefaultRecipientAddress();
225
+ $bSendSuccess = $this->getEmailProcessor()
226
+ ->sendEmailTo( $sRecipient, $sSubject, $this->aNotifEmail );
227
 
228
  if ( $bSendSuccess ) {
229
  $this->addToAuditEntry( sprintf( _wpsf__( 'Successfully sent Plugin Vulnerability Notification email alert to: %s' ), $sRecipient ) );
src/processors/lockdown.php CHANGED
@@ -54,12 +54,33 @@ class ICWP_WPSF_Processor_Lockdown extends ICWP_WPSF_Processor_BaseWpsf {
54
  add_filter( 'xmlrpc_methods', '__return_empty_array', 1000 );
55
  }
56
 
57
- if ( $oFO->getIfRestApiDisabled() ) {
 
 
 
 
 
 
 
 
 
 
58
  // 99 so that we jump in just before the always-on WordPress cookie auth.
59
  add_filter( 'rest_authentication_errors', array( $this, 'disableAnonymousRestApi' ), 99 );
60
  }
61
  }
62
 
 
 
 
 
 
 
 
 
 
 
 
63
  /**
64
  * Understand that if $mCurrentStatus is null, no check has been made. If true, something has
65
  * authenticated the request, and if WP_Error, then an error is already present
@@ -74,6 +95,7 @@ class ICWP_WPSF_Processor_Lockdown extends ICWP_WPSF_Processor_BaseWpsf {
74
  sprintf( _wpsf__( 'Anonymous access to the WordPress Rest API has been restricted by %s.' ), $this->getController()
75
  ->getHumanName() ),
76
  array( 'status' => rest_authorization_required_code() ) );
 
77
  }
78
  return $mCurrentStatus;
79
  }
54
  add_filter( 'xmlrpc_methods', '__return_empty_array', 1000 );
55
  }
56
 
57
+ add_action( 'init', array( $this, 'onWpInit' ), 5 );
58
+ }
59
+
60
+ public function onWpInit() {
61
+ if ( $this->loadWp()->isRest() ) {
62
+ $this->processRestApi();
63
+ }
64
+ }
65
+
66
+ protected function processRestApi() {
67
+ if ( !$this->isRestApiAccessAllowed() ) {
68
  // 99 so that we jump in just before the always-on WordPress cookie auth.
69
  add_filter( 'rest_authentication_errors', array( $this, 'disableAnonymousRestApi' ), 99 );
70
  }
71
  }
72
 
73
+ /**
74
+ * @return bool
75
+ */
76
+ protected function isRestApiAccessAllowed() {
77
+ /** @var ICWP_WPSF_FeatureHandler_Lockdown $oFO */
78
+ $oFO = $this->getFeature();
79
+ return $oFO->isRestApiAnonymousAccessAllowed()
80
+ || $this->loadWpUsers()->isUserLoggedIn()
81
+ || in_array( $this->loadWp()->getRestNamespace(), $oFO->getRestApiAnonymousExclusions() );
82
+ }
83
+
84
  /**
85
  * Understand that if $mCurrentStatus is null, no check has been made. If true, something has
86
  * authenticated the request, and if WP_Error, then an error is already present
95
  sprintf( _wpsf__( 'Anonymous access to the WordPress Rest API has been restricted by %s.' ), $this->getController()
96
  ->getHumanName() ),
97
  array( 'status' => rest_authorization_required_code() ) );
98
+ $this->addToAuditEntry( 'Blocked Anonymous API Access', 1, 'anonymous_api' );
99
  }
100
  return $mCurrentStatus;
101
  }
src/processors/loginprotect_googleauthenticator.php CHANGED
@@ -291,7 +291,8 @@ class ICWP_WPSF_Processor_LoginProtect_GoogleAuthenticator extends ICWP_WPSF_Pro
291
  $sRecipient = $oUser->get( 'user_email' );
292
  if ( $this->loadDataProcessor()->validEmail( $sRecipient ) ) {
293
  $sEmailSubject = _wpsf__( 'Google Authenticator Removal Confirmation' );
294
- $bSendSuccess = $this->getEmailProcessor()->sendEmailTo( $sRecipient, $sEmailSubject, $aEmailContent );
 
295
  }
296
  return $bSendSuccess;
297
  }
291
  $sRecipient = $oUser->get( 'user_email' );
292
  if ( $this->loadDataProcessor()->validEmail( $sRecipient ) ) {
293
  $sEmailSubject = _wpsf__( 'Google Authenticator Removal Confirmation' );
294
+ $bSendSuccess = $this->getEmailProcessor()
295
+ ->sendEmailTo( $sRecipient, $sEmailSubject, $aEmailContent );
296
  }
297
  return $bSendSuccess;
298
  }
src/processors/loginprotect_intent.php CHANGED
@@ -184,8 +184,10 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
184
  * @return $this
185
  */
186
  protected function setLoginIntentExpiresAt( $nExpirationTime, $oUser ) {
187
- $oMeta = $this->loadWpUsers()->metaVoForUser( $this->prefix(), $oUser->ID );
188
- $oMeta->login_intent_expires_at = max( 0, (int)$nExpirationTime );
 
 
189
  return $this;
190
  }
191
 
184
  * @return $this
185
  */
186
  protected function setLoginIntentExpiresAt( $nExpirationTime, $oUser ) {
187
+ if ( $oUser instanceof WP_User ) {
188
+ $oMeta = $this->loadWpUsers()->metaVoForUser( $this->prefix(), $oUser->ID );
189
+ $oMeta->login_intent_expires_at = max( 0, (int)$nExpirationTime );
190
+ }
191
  return $this;
192
  }
193
 
src/processors/loginprotect_twofactorauth.php CHANGED
@@ -191,7 +191,7 @@ class ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth extends ICWP_WPSF_Processor
191
  sprintf( '- <a href="%s" target="_blank">%s</a>', 'http://icwp.io/96', _wpsf__( 'Why no login link?' ) ),
192
  ''
193
  );
194
- $sEmailSubject = sprintf( _wpsf__( '[%s] Two-Factor Login Verification' ), $this->loadWp()->getSiteName() );
195
 
196
  $bResult = $this->getEmailProcessor()
197
  ->sendEmailTo( $sEmail, $sEmailSubject, $aMessage );
191
  sprintf( '- <a href="%s" target="_blank">%s</a>', 'http://icwp.io/96', _wpsf__( 'Why no login link?' ) ),
192
  ''
193
  );
194
+ $sEmailSubject = _wpsf__( 'Two-Factor Login Verification' );
195
 
196
  $bResult = $this->getEmailProcessor()
197
  ->sendEmailTo( $sEmail, $sEmailSubject, $aMessage );
src/processors/loginprotect_wplogin.php CHANGED
@@ -60,11 +60,11 @@ class ICWP_WPSF_Processor_LoginProtect_WpLogin extends ICWP_WPSF_Processor_BaseW
60
  $sMessage = sprintf( _wpsf__( 'Can not use the Rename WP Login feature because you have the "%s" plugin installed and it is active.' ), 'Theme My Login' );
61
  $bConflicted = true;
62
  }
63
- else if ( !$oWp->getIsPermalinksEnabled() ) {
64
  $sMessage = sprintf( _wpsf__( 'Can not use the Rename WP Login feature because you have not enabled %s.' ), __( 'Permalinks' ) );
65
  $bConflicted = true;
66
  }
67
- else if ( $oWp->getIsPermalinksEnabled() && ( $oWp->getDoesWpSlugExist( $sCustomLoginPath ) || in_array( $sCustomLoginPath, $oWp->getAutoRedirectLocations() ) ) ) {
68
  $sMessage = sprintf( _wpsf__( 'Can not use the Rename WP Login feature because you have chosen a path ("%s") that is reserved on your WordPress site.' ), $sCustomLoginPath );
69
  $bConflicted = true;
70
  }
60
  $sMessage = sprintf( _wpsf__( 'Can not use the Rename WP Login feature because you have the "%s" plugin installed and it is active.' ), 'Theme My Login' );
61
  $bConflicted = true;
62
  }
63
+ else if ( !$oWp->isPermalinksEnabled() ) {
64
  $sMessage = sprintf( _wpsf__( 'Can not use the Rename WP Login feature because you have not enabled %s.' ), __( 'Permalinks' ) );
65
  $bConflicted = true;
66
  }
67
+ else if ( $oWp->isPermalinksEnabled() && ( $oWp->getDoesWpSlugExist( $sCustomLoginPath ) || in_array( $sCustomLoginPath, $oWp->getAutoRedirectLocations() ) ) ) {
68
  $sMessage = sprintf( _wpsf__( 'Can not use the Rename WP Login feature because you have chosen a path ("%s") that is reserved on your WordPress site.' ), $sCustomLoginPath );
69
  $bConflicted = true;
70
  }
src/processors/sessions.php CHANGED
@@ -59,7 +59,7 @@ class ICWP_WPSF_Processor_Sessions extends ICWP_WPSF_BaseDbProcessor {
59
  /**
60
  */
61
  public function onWpLoaded() {
62
- if ( $this->loadWpUsers()->isUserLoggedIn() && !$this->loadWp()->isRestUrl() ) {
63
  $this->autoAddSession();
64
  $this->queryUpdateSessionLastActivity();
65
  }
59
  /**
60
  */
61
  public function onWpLoaded() {
62
+ if ( $this->loadWpUsers()->isUserLoggedIn() && !$this->loadWp()->isRest() ) {
63
  $this->autoAddSession();
64
  $this->queryUpdateSessionLastActivity();
65
  }
src/processors/usermanagement_sessions.php CHANGED
@@ -25,7 +25,7 @@ class ICWP_WPSF_Processor_UserManagement_Sessions extends ICWP_WPSF_Processor_Ba
25
  /**
26
  */
27
  public function onWpLoaded() {
28
- if ( $this->loadWpUsers()->isUserLoggedIn() && !$this->loadWp()->isRestUrl() ) {
29
  $this->checkCurrentSession();
30
  }
31
  }
25
  /**
26
  */
27
  public function onWpLoaded() {
28
+ if ( $this->loadWpUsers()->isUserLoggedIn() && !$this->loadWp()->isRest() ) {
29
  $this->checkCurrentSession();
30
  }
31
  }
src/wizards/base.php CHANGED
@@ -68,21 +68,17 @@ abstract class ICWP_WPSF_Wizard_Base extends ICWP_WPSF_Foundation {
68
 
69
  $sDieMessage = 'Not Permitted';
70
  if ( $this->getUserCan() ) {
71
- if ( $this->verifyNonce() ) {
72
- $this->loadWizard();
73
- }
74
- else {
75
- $sDieMessage = 'Sorry, this link has expired.';
76
- }
77
  }
78
  else {
79
  $sDieMessage = 'Please login to run this wizard';
80
  }
 
81
  $this->loadWp()
82
  ->wpDie( $sDieMessage );
83
  }
84
  catch ( Exception $oE ) {
85
- if ( $sWizard == 'landing' && $this->verifyNonce( 'landing' ) ) {
86
  $this->loadWizardLanding();
87
  }
88
  }
@@ -243,10 +239,20 @@ abstract class ICWP_WPSF_Wizard_Base extends ICWP_WPSF_Foundation {
243
  $aWizard[ 'has_perm' ] = $this->getUserCan( $aWizard[ 'min_user_permissions' ] );
244
  $aWizard[ 'url' ] = $oFO->getUrl_Wizard( $sKey );
245
  $aWizard[ 'has_premium' ] = isset( $aWizard[ 'has_premium' ] ) && $aWizard[ 'has_premium' ];
 
246
  }
247
  return $aWizards;
248
  }
249
 
 
 
 
 
 
 
 
 
 
250
  /**
251
  * @return array[]
252
  */
@@ -548,14 +554,4 @@ abstract class ICWP_WPSF_Wizard_Base extends ICWP_WPSF_Foundation {
548
  protected function getPluginCon() {
549
  return $this->getModCon()->getConn();
550
  }
551
-
552
- /**
553
- * @return false|int
554
- */
555
- protected function verifyNonce( $sWizard = null ) {
556
- if ( is_null( $sWizard ) ) {
557
- $sWizard = $this->getWizardSlug();
558
- }
559
- return wp_verify_nonce( $this->loadDP()->query( 'nonwizard' ), 'wizard'.$sWizard );
560
- }
561
  }
68
 
69
  $sDieMessage = 'Not Permitted';
70
  if ( $this->getUserCan() ) {
71
+ $this->loadWizard();
 
 
 
 
 
72
  }
73
  else {
74
  $sDieMessage = 'Please login to run this wizard';
75
  }
76
+
77
  $this->loadWp()
78
  ->wpDie( $sDieMessage );
79
  }
80
  catch ( Exception $oE ) {
81
+ if ( $sWizard == 'landing' ) {
82
  $this->loadWizardLanding();
83
  }
84
  }
239
  $aWizard[ 'has_perm' ] = $this->getUserCan( $aWizard[ 'min_user_permissions' ] );
240
  $aWizard[ 'url' ] = $oFO->getUrl_Wizard( $sKey );
241
  $aWizard[ 'has_premium' ] = isset( $aWizard[ 'has_premium' ] ) && $aWizard[ 'has_premium' ];
242
+ $aWizard[ 'available' ] = $this->getWizardAvailability( $sKey );
243
  }
244
  return $aWizards;
245
  }
246
 
247
+ /**
248
+ * Override this to provide custom logic for wizard availability - e.g. isPremium() etc.
249
+ * @param string $sKey
250
+ * @return bool
251
+ */
252
+ protected function getWizardAvailability( $sKey ) {
253
+ return true;
254
+ }
255
+
256
  /**
257
  * @return array[]
258
  */
554
  protected function getPluginCon() {
555
  return $this->getModCon()->getConn();
556
  }
 
 
 
 
 
 
 
 
 
 
557
  }
src/wizards/hack_protect.php CHANGED
@@ -18,6 +18,22 @@ class ICWP_WPSF_Wizard_HackProtect extends ICWP_WPSF_Wizard_BaseWpsf {
18
  return sprintf( _wpsf__( '%s Hack Protect Wizard' ), $this->getPluginCon()->getHumanName() );
19
  }
20
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  /**
22
  * @param string $sStep
23
  * @return \FernleafSystems\Utilities\Response|null
@@ -33,12 +49,18 @@ class ICWP_WPSF_Wizard_HackProtect extends ICWP_WPSF_Wizard_BaseWpsf {
33
  case 'restorefiles':
34
  $oResponse = $this->process_RestoreFiles();
35
  break;
 
 
 
36
  case 'ufcconfig':
37
  $oResponse = $this->process_UfcConfig();
38
  break;
39
  case 'wcfconfig':
40
  $oResponse = $this->process_WcfConfig();
41
  break;
 
 
 
42
  default:
43
  $oResponse = parent::processWizardStep( $sStep );
44
  break;
@@ -116,6 +138,31 @@ class ICWP_WPSF_Wizard_HackProtect extends ICWP_WPSF_Wizard_BaseWpsf {
116
  ->setMessageText( $sMessage );
117
  }
118
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  /**
120
  * @return \FernleafSystems\Utilities\Response
121
  */
@@ -199,6 +246,82 @@ class ICWP_WPSF_Wizard_HackProtect extends ICWP_WPSF_Wizard_BaseWpsf {
199
  ->setMessageText( $sMessage );
200
  }
201
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
202
  /**
203
  * @return string[]
204
  * @throws Exception
@@ -212,6 +335,9 @@ class ICWP_WPSF_Wizard_HackProtect extends ICWP_WPSF_Wizard_BaseWpsf {
212
  case 'ufc':
213
  $aSteps = $this->determineWizardSteps_Ufc();
214
  break;
 
 
 
215
  default:
216
  parent::determineWizardSteps();
217
  break;
@@ -219,6 +345,27 @@ class ICWP_WPSF_Wizard_HackProtect extends ICWP_WPSF_Wizard_BaseWpsf {
219
  return array_values( array_intersect( array_keys( $this->getAllDefinedSteps() ), $aSteps ) );
220
  }
221
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
  /**
223
  * @return string[]
224
  */
@@ -324,6 +471,17 @@ class ICWP_WPSF_Wizard_HackProtect extends ICWP_WPSF_Wizard_BaseWpsf {
324
  break;
325
  }
326
  }
 
 
 
 
 
 
 
 
 
 
 
327
 
328
  if ( empty( $aAdditional ) ) {
329
  $aAdditional = parent::getRenderData_SlideExtra( $sStep );
@@ -331,6 +489,82 @@ class ICWP_WPSF_Wizard_HackProtect extends ICWP_WPSF_Wizard_BaseWpsf {
331
  return $aAdditional;
332
  }
333
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
334
  /**
335
  * @param string[] $aFilePaths
336
  * @return string[]
18
  return sprintf( _wpsf__( '%s Hack Protect Wizard' ), $this->getPluginCon()->getHumanName() );
19
  }
20
 
21
+ /**
22
+ * @param string $sKey
23
+ * @return bool
24
+ */
25
+ protected function getWizardAvailability( $sKey ) {
26
+ switch ( $sKey ) {
27
+ case 'ptg':
28
+ $bAvailable = false;
29
+ break;
30
+ default:
31
+ $bAvailable = parent::getWizardAvailability( $sKey );
32
+ break;
33
+ }
34
+ return $bAvailable;
35
+ }
36
+
37
  /**
38
  * @param string $sStep
39
  * @return \FernleafSystems\Utilities\Response|null
49
  case 'restorefiles':
50
  $oResponse = $this->process_RestoreFiles();
51
  break;
52
+ case 'ptgconfig':
53
+ $oResponse = $this->process_PtgConfig();
54
+ break;
55
  case 'ufcconfig':
56
  $oResponse = $this->process_UfcConfig();
57
  break;
58
  case 'wcfconfig':
59
  $oResponse = $this->process_WcfConfig();
60
  break;
61
+ case 'ptg_assetaction':
62
+ $oResponse = $this->process_AssetAction();
63
+ break;
64
  default:
65
  $oResponse = parent::processWizardStep( $sStep );
66
  break;
138
  ->setMessageText( $sMessage );
139
  }
140
 
141
+ /**
142
+ * @return \FernleafSystems\Utilities\Response
143
+ */
144
+ private function process_PtgConfig() {
145
+ /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
146
+ $oFO = $this->getModCon();
147
+
148
+ $sSetting = $this->loadDP()->post( 'enable_scan' );
149
+ $oFO->setPtgEnabledOption( $sSetting )
150
+ ->savePluginOptions();
151
+
152
+ $bSuccess = ( $sSetting == $oFO->getPtgEnabledOption() );
153
+
154
+ if ( $bSuccess && $oFO->isPtgEnabled() ) {
155
+ $sMessage = 'Scanner automation has been enabled.';
156
+ }
157
+ else {
158
+ $sMessage = 'There was a problem with saving this option. You may need to reload.';
159
+ }
160
+
161
+ $oResponse = new \FernleafSystems\Utilities\Response();
162
+ return $oResponse->setSuccessful( $bSuccess )
163
+ ->setMessageText( $sMessage );
164
+ }
165
+
166
  /**
167
  * @return \FernleafSystems\Utilities\Response
168
  */
246
  ->setMessageText( $sMessage );
247
  }
248
 
249
+ /**
250
+ * @return \FernleafSystems\Utilities\Response
251
+ */
252
+ private function process_AssetAction() {
253
+ /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
254
+ $oFO = $this->getModCon();
255
+ $oDP = $this->loadDP();
256
+
257
+ $sSlug = $oDP->post( 'slug' );
258
+ $sContext = $oDP->post( 'context' );
259
+ $sItemAction = $oDP->post( 'ptgaction' );
260
+
261
+ $oWpPlugins = $this->loadWpPlugins();
262
+ $oWpThemes = $this->loadWpThemes();
263
+
264
+ // 1. load the asset
265
+ $bWpOrg = false;
266
+ $mAsset = null;
267
+ if ( $sContext == 'plugins' ) {
268
+ $mAsset = $oWpPlugins->getPlugin( $sSlug );
269
+ $bWpOrg = $oWpPlugins->isWpOrg( $sSlug );
270
+ }
271
+ else if ( $sContext == 'themes' ) {
272
+ $mAsset = $oWpThemes->getTheme( $sSlug );
273
+ $bWpOrg = $oWpThemes->isWpOrg( $sSlug );
274
+ }
275
+
276
+ $bSuccess = false;
277
+ if ( empty( $mAsset ) ) {
278
+ $sMessage = 'Item could not be found.';
279
+ }
280
+ else {
281
+ switch ( $sItemAction ) {
282
+
283
+ case 'reinstall':
284
+ if ( $bWpOrg ) {
285
+ /** @var ICWP_WPSF_Processor_HackProtect $oP */
286
+ $oP = $oFO->getProcessor();
287
+ $bSuccess = $oP->getSubProcessorGuard()
288
+ ->reinstall( $sSlug, $sContext );
289
+ $sMessage = 'The item has been re-installed from WordPress.org sources.';
290
+ }
291
+ break;
292
+
293
+ case 'ignore':
294
+ if ( $bWpOrg ) {
295
+ /** @var ICWP_WPSF_Processor_HackProtect $oProc */
296
+ $oProc = $this->getModCon()->getProcessor();
297
+ $oP = $oProc->getSubProcessorGuard();
298
+ $oP->updateItemInSnapshot( $sSlug, $sContext );
299
+ $bSuccess = true;
300
+ $sMessage = _wpsf__( 'All changes detected have been ignored.' );
301
+ }
302
+ break;
303
+
304
+ case 'deactivate':
305
+ if ( $sContext == 'plugins' ) {
306
+ $oWpPlugins->deactivate( $sSlug );
307
+ $bSuccess = true;
308
+ $sMessage = _wpsf__( 'The plugin has been deactivated.' );
309
+ }
310
+ break;
311
+
312
+ default:
313
+ $sMessage = 'Action not supported.'.$sItemAction;
314
+ break;
315
+ }
316
+ }
317
+
318
+ //_wpsf__( 'Success.' )
319
+
320
+ $oResponse = new \FernleafSystems\Utilities\Response();
321
+ return $oResponse->setSuccessful( $bSuccess )
322
+ ->setMessageText( $sMessage );
323
+ }
324
+
325
  /**
326
  * @return string[]
327
  * @throws Exception
335
  case 'ufc':
336
  $aSteps = $this->determineWizardSteps_Ufc();
337
  break;
338
+ case 'ptg':
339
+ $aSteps = $this->determineWizardSteps_Ptg();
340
+ break;
341
  default:
342
  parent::determineWizardSteps();
343
  break;
345
  return array_values( array_intersect( array_keys( $this->getAllDefinedSteps() ), $aSteps ) );
346
  }
347
 
348
+ /**
349
+ * @return string[]
350
+ */
351
+ private function determineWizardSteps_Ptg() {
352
+ /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
353
+ $oFO = $this->getModCon();
354
+
355
+ $aStepsSlugs = array(
356
+ 'start',
357
+ );
358
+ if ( !$oFO->isPtgEnabled() ) {
359
+ $aStepsSlugs[] = 'config';
360
+ }
361
+ else {
362
+ $aStepsSlugs[] = 'scanresult_plugins';
363
+ $aStepsSlugs[] = 'scanresult_themes';
364
+ }
365
+ $aStepsSlugs[] = 'finished';
366
+ return $aStepsSlugs;
367
+ }
368
+
369
  /**
370
  * @return string[]
371
  */
471
  break;
472
  }
473
  }
474
+ else if ( $sCurrentWiz == 'ptg' ) {
475
+
476
+ switch ( $sStep ) {
477
+ case 'scanresult_themes':
478
+ $aAdditional[ 'data' ] = $this->getPtgScanResults( 'themes' );
479
+ break;
480
+ case 'scanresult_plugins':
481
+ $aAdditional[ 'data' ] = $this->getPtgScanResults( 'plugins' );
482
+ break;
483
+ }
484
+ }
485
 
486
  if ( empty( $aAdditional ) ) {
487
  $aAdditional = parent::getRenderData_SlideExtra( $sStep );
489
  return $aAdditional;
490
  }
491
 
492
+ private function getPtgScanResults( $sContext ) {
493
+ /** @var ICWP_WPSF_Processor_HackProtect $oProc */
494
+ $oProc = $this->getModCon()->getProcessor();
495
+ $oP = $oProc->getSubProcessorGuard();
496
+ if ( $sContext == 'plugins' ) {
497
+ $aResults = $oP->scanPlugins();
498
+ }
499
+ else {
500
+ $aResults = $oP->scanThemes();
501
+ }
502
+
503
+ $oWpPlugins = $this->loadWpPlugins();
504
+ $oWpThemes = $this->loadWpThemes();
505
+ foreach ( $aResults as $sSlug => $aItemResultSet ) {
506
+ if ( $sContext == 'plugins' ) {
507
+ $bIsWpOrg = $oWpPlugins->isWpOrg( $sSlug );
508
+ $sName = $oWpPlugins->getPlugin( $sSlug )[ 'Name' ];
509
+ $aFlags = array(
510
+ 'is_wporg' => $bIsWpOrg,
511
+ 'can_reinstall' => $bIsWpOrg,
512
+ 'can_deactivate' => true,
513
+ 'slug' => $sSlug,
514
+ 'id' => $sContext.sanitize_key( $sSlug ),
515
+ );
516
+ }
517
+ else {
518
+ $sName = $oWpThemes->getTheme( $sSlug )->get( 'Name' );
519
+ $bIsWpOrg = $oWpThemes->isWpOrg( $sSlug );
520
+ $aFlags = array(
521
+ 'is_wporg' => $bIsWpOrg,
522
+ 'can_reinstall' => $bIsWpOrg,
523
+ 'can_deactivate' => false,
524
+ 'slug' => $sSlug,
525
+ 'id' => $sContext.sanitize_key( $sSlug ),
526
+ );
527
+ }
528
+ $aResults[ $sName ] = $this->stripPaths( $aItemResultSet );
529
+ $aResults[ $sName ][ 'flags' ] = $aFlags;
530
+ unset( $aResults[ $sSlug ] );
531
+ }
532
+
533
+ return array(
534
+ 'context_sing' => rtrim( ucfirst( $sContext ), 's' ),
535
+ 'context' => $sContext,
536
+ 'result' => $aResults,
537
+ );
538
+ }
539
+
540
+ /**
541
+ * @param array[] $aLists
542
+ * @return int
543
+ */
544
+ private function count( $aLists ) {
545
+ $nCount = 0;
546
+ foreach ( $aLists as $aList ) {
547
+ $nCount += count( $aList );
548
+ }
549
+ return $nCount;
550
+ }
551
+
552
+ /**
553
+ * @param array[] $aLists
554
+ * @return array[]
555
+ */
556
+ private function stripPaths( $aLists ) {
557
+ foreach ( $aLists as $sKey => $aList ) {
558
+ $aLists[ $sKey ] = array_map(
559
+ function ( $sPath ) {
560
+ return ltrim( str_replace( WP_CONTENT_DIR, '', $sPath ), '/' );
561
+ },
562
+ $aList
563
+ );
564
+ }
565
+ return $aLists;
566
+ }
567
+
568
  /**
569
  * @param string[] $aFilePaths
570
  * @return string[]
templates/php/snippets/hg-plugins-reinstall-dialogs.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div id="icwpWpsfReinstall" class="hidden icwp-wpsf-dialog">
2
+ <h3>Really Re-Install Plugin?</h3>
3
+ <p>WordPress will now download and install the <strong>latest available version</strong> of this plugin.</p>
4
+ <p>Note: In case of possible failure, it's preferred to do this while the plugin is not active.</p>
5
+ </div>
6
+
7
+ <div id="icwpWpsfActivateReinstall" class="hidden icwp-wpsf-dialog">
8
+ <h3>Re-Install First?</h3>
9
+ <p>For best security practices, Shield will download and re-install the
10
+ <strong>latest available version</strong> of this plugin.</p>
11
+ <p>This ensures the files for this plugin have not been corrupted in any way.</p>
12
+ <p>You can choose to 'Activate Only' (not recommended), or close this message to cancel activation.</p>
13
+ </div>
templates/php/snippets/module-actions-plugin.php DELETED
@@ -1,42 +0,0 @@
1
- <h2>Plugin Walk-Through Wizards</h2>
2
- <p>Click the buttons below to launch the respective walk-through wizard (opens in a new window).</p>
3
-
4
- <?php if ( !$flags[ 'can_php54' ] ) : ?>
5
- <div class="alert alert-danger">
6
- <h3>Running Wizards is not supported on your web hosting.</h3>
7
- <p>You're site is running PHP Version <strong><?php echo $data[ 'phpversion' ]; ?></strong>.</p>
8
- <p>Running Shield Wizards requires at least <strong>PHP 5.4</strong>.
9
- <br />PHP 5.4 was released around 6 years ago and by now,
10
- any <strong>decent webhost</strong> will have provisioned support for <em>at least</em> this
11
- version of PHP. Check with your webhost or site developer to see about switching up your PHP version
12
- because you're running your website on old, outdated, non-maintained software. And if you're PHP
13
- is this far out-of-date, you gotta wonder what else on your webhost needs some important upgrades.
14
- </p>
15
- <p>Website security covers many areas, and running your webhost/server on up-to-date software is
16
- a critical one of these areas.</p>
17
- <p>Note: As <?php echo $sPluginName; ?> is further developed, more and more features will require higher versions of PHP.</p>
18
- </div>
19
- <?php endif; ?>
20
-
21
- <div class="well">
22
- <h3>Original Welcome Wizard</h3>
23
- <p>Use this to re-run the original welcome wizard that gets you started with <?php echo $sPluginName; ?>.</p>
24
- <p><a href="<?php echo $hrefs[ 'wizard_welcome' ]; ?>" title="Shield Welcome Wizard" target="_blank"
25
- <?php echo $flags[ 'can_welcome' ] ? '' : 'disabled="disabled" onclick="event.preventDefault();"'; ?>
26
- class="btn btn-default btn-large">Shield Welcome Wizard</a></p>
27
- </div>
28
-
29
- <hr />
30
-
31
- <div class="well">
32
- <h3>Import Options From Another Site</h3>
33
- <p>Use this to import all the options from a remote site directly into this site.</p>
34
- <p><a href="<?php echo $hrefs[ 'wizard_import' ]; ?>" title="Import Options Wizard" target="_blank"
35
- <?php echo $flags[ 'can_import' ] ? '' : 'disabled="disabled" onclick="event.preventDefault();"'; ?>
36
- class="btn btn-default btn-large">Import Options Wizard</a></p>
37
- <div class="alert alert-warning">
38
- <p class="text-warning">Warning: Use of this feature will overwrite all Shield settings on this site.</p>
39
- </div>
40
- </div>
41
-
42
- <hr />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
templates/php/snippets/module-help-template.php CHANGED
@@ -10,7 +10,7 @@
10
  <div class="module-headline">
11
  <div class="float-right">
12
 
13
- <div class="btn-group icwp-top-buttons" role="group">
14
 
15
  <a href="javascript:void(0)" class="btn btn-outline-success icwp-carousel-0">
16
  <?php echo $strings[ 'btn_options' ]; ?>
10
  <div class="module-headline">
11
  <div class="float-right">
12
 
13
+ <div class="btn-group icwp-top-buttons" role="group">
14
 
15
  <a href="javascript:void(0)" class="btn btn-outline-success icwp-carousel-0">
16
  <?php echo $strings[ 'btn_options' ]; ?>
templates/php/snippets/options_form.php CHANGED
@@ -19,7 +19,8 @@
19
 
20
  <div class="btn-group" role="group" aria-label="Basic example">
21
 
22
- <a aria-disabled="true" class="btn btn-success disabled icwp-carousel-0" href="javascript:void(0)">
 
23
  <?php echo $strings[ 'btn_options' ]; ?></a>
24
 
25
  <?php if ( $flags[ 'can_wizard' ] && $flags[ 'has_wizard' ] ) : ?>
@@ -99,11 +100,50 @@
99
  <?php endif; ?>
100
  </legend>
101
 
102
- <?php if ( !empty( $aOptSection[ 'summary' ] ) ) : ?>
103
- <div class="row_section_summary">
104
- <?php foreach ( $aOptSection[ 'summary' ] as $sItem ) : ?>
105
- <p class="noselect"><?php echo $sItem; ?></p>
106
- <?php endforeach; ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  </div>
108
  <?php endif; ?>
109
 
@@ -114,7 +154,7 @@
114
  $bEnabled = $aOption[ 'enabled' ];
115
  $sDisabledText = $bEnabled ? '' : 'disabled="Disabled"';
116
  ?>
117
- <div class="form-group row row_number_<?php echo $nKeyRow; ?>">
118
 
119
  <label class="form-label col-3 col-form-label" for="<?php echo $sOptKey; ?>">
120
  <div class="form-label-inner text-right">
19
 
20
  <div class="btn-group" role="group" aria-label="Basic example">
21
 
22
+ <a aria-disabled="true" class="btn btn-success disabled icwp-carousel-0"
23
+ href="javascript:void(0)">
24
  <?php echo $strings[ 'btn_options' ]; ?></a>
25
 
26
  <?php if ( $flags[ 'can_wizard' ] && $flags[ 'has_wizard' ] ) : ?>
100
  <?php endif; ?>
101
  </legend>
102
 
103
+ <div class="row_section_summary row">
104
+ <div class="col-8">
105
+ <?php if ( !empty( $aOptSection[ 'summary' ] ) ) : ?>
106
+ <?php foreach ( $aOptSection[ 'summary' ] as $sItem ) : ?>
107
+ <p class="noselect"><?php echo $sItem; ?></p>
108
+ <?php endforeach; ?>
109
+ <?php endif; ?>
110
+ </div>
111
+
112
+ <div class="col-4">
113
+ <?php if ( !empty( $aOptSection[ 'help_video' ] ) ) : ?>
114
+ <button class="btn btn-lg btn-outline-info section_help_video" type="button"
115
+ data-toggle="collapse"
116
+ data-target="#sectionVideo<?php echo $aOptSection[ 'help_video' ][ 'id' ]; ?>"
117
+ aria-expanded="false"
118
+ aria-controls="sectionVideo<?php echo $aOptSection[ 'help_video' ][ 'id' ]; ?>">
119
+ <span class="dashicons dashicons-controls-play"></span> Watch The Video</button>
120
+ <?php endif; ?>
121
+ </div>
122
+
123
+ <?php if ( !empty( $aOptSection[ 'help_video' ] ) ) : ?>
124
+ <div class="w-100"></div>
125
+ <div class="col">
126
+ <div class="collapse section_video"
127
+ id="sectionVideo<?php echo $aOptSection[ 'help_video' ][ 'id' ]; ?>">
128
+ <div class="embed-responsive embed-responsive-16by9">
129
+ <iframe src="<?php echo $aOptSection[ 'help_video' ][ 'embed_url' ]; ?>" width="640"
130
+ height="360"
131
+ class="embed-responsive-item" allowfullscreen></iframe>
132
+ </div>
133
+ </div>
134
+ </div>
135
+ <?php endif; ?>
136
+ </div>
137
+
138
+ <?php if ( !empty( $aOptSection[ 'warnings' ] ) ) : ?>
139
+ <div class="row">
140
+ <div class="col">
141
+ <?php foreach ( $aOptSection[ 'warnings' ] as $sWarning ) :?>
142
+ <div class="alert alert-warning text-center">
143
+ <?php echo $sWarning; ?>
144
+ </div>
145
+ <?php endforeach; ?>
146
+ </div>
147
  </div>
148
  <?php endif; ?>
149
 
154
  $bEnabled = $aOption[ 'enabled' ];
155
  $sDisabledText = $bEnabled ? '' : 'disabled="Disabled"';
156
  ?>
157
+ <div class="form-group row row_number_<?php echo $nKeyRow; ?>">
158
 
159
  <label class="form-label col-3 col-form-label" for="<?php echo $sOptKey; ?>">
160
  <div class="form-label-inner text-right">
templates/php/snippets/pro.php CHANGED
@@ -179,7 +179,7 @@ $aLicKeyInput = $inputs[ 'license_key' ];
179
  <div id="colltwo" class="collapse" aria-labelledby="headingTwo" data-parent="#accordion">
180
  <div class="card-body">
181
  <dl>
182
- <dt>Catch Hacks Immediately - Plugins and Themes Locker</dt>
183
  <dd>Be alerted immediately to ANY unauthorized changes to plugin and theme files.</dd>
184
 
185
  <dt>White Label</dt>
179
  <div id="colltwo" class="collapse" aria-labelledby="headingTwo" data-parent="#accordion">
180
  <div class="card-body">
181
  <dl>
182
+ <dt>Catch Hacks Immediately - Plugins and Themes Guard</dt>
183
  <dd>Be alerted immediately to ANY unauthorized changes to plugin and theme files.</dd>
184
 
185
  <dt>White Label</dt>
templates/twig/wizard/slides/common/base.twig CHANGED
@@ -7,7 +7,7 @@
7
  <div class="row">
8
  <div class="col-6">
9
  {% block slide_header_previous %}
10
- <button class="btn btn-default btn-block ButtonPreviousSlide">&larr; Previous Step </button>
11
  {% endblock %}
12
  </div>
13
  <div class="col-6">
7
  <div class="row">
8
  <div class="col-6">
9
  {% block slide_header_previous %}
10
+ <button class="btn btn-outline-secondary btn-block ButtonPreviousSlide">&larr; Previous Step </button>
11
  {% endblock %}
12
  </div>
13
  <div class="col-6">
templates/twig/wizard/slides/common/no_access.twig CHANGED
@@ -8,7 +8,7 @@
8
  <p>To run this wizard you need to have certain privileges that are not met by your current account level.</p>
9
  <p>If this doesn't seem right, please contact your site administrator.</p>
10
 
11
- <a href="{{ hrefs.dashboard }}" class="btn btn-default">Go Back To Shield Dashboard</a>
12
 
13
  {% endblock %}
14
 
8
  <p>To run this wizard you need to have certain privileges that are not met by your current account level.</p>
9
  <p>If this doesn't seem right, please contact your site administrator.</p>
10
 
11
+ <a href="{{ hrefs.dashboard }}" class="btn btn-outline-secondary">Go Back To Shield Dashboard</a>
12
 
13
  {% endblock %}
14
 
templates/twig/wizard/slides/ptg/config.twig ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'wizard/slides/common/base.twig' %}
2
+
3
+ {% block slide_body %}
4
+ {{ slideMacros.slideTitle( 'Turn On Plugin and Theme Guard Scanner' ) }}
5
+
6
+ <p>It looks like the Plugin and Theme Guard scanner isn't set to run yet.</p>
7
+ <p>You can adjust this using the settings below.</p>
8
+
9
+ <form class="form-horizontal icwp-wizard-form">
10
+
11
+ {% set radiovalues =
12
+ {
13
+ 'enabled': '<span>Scan and Report</span> - scan and email report (<em>recommended</em>)',
14
+ 'disabled': '<span>Disabled</span> - do not scan.'
15
+ } %}
16
+ {{ slideMacros.formInput_Radio( 'enable_scan', radiovalues, 'Enable Automatic Scanning' ) }}
17
+
18
+ <span id="helpBlock" class="help-block">
19
+ Be sure that when you're enabling this scan that you are satisfied that all active plugins
20
+ and themes are in pristine condition, free from hacks or corruption.
21
+ </span>
22
+
23
+ {{ slideMacros.formInput_Hidden( 'wizard-step', 'ptgconfig' ) }}
24
+ {{ slideMacros.formInput_Submit( 'Set Automatic Scan' ) }}
25
+ </form>
26
+ {% endblock %}
templates/twig/wizard/slides/ptg/finished.twig ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ {% extends 'wizard/slides/common/base_finish.twig' %}
2
+
3
+ {% block slide_body_top %}
4
+ {{ slideMacros.slideTitle( 'Finished: Plugin & Theme Guard' ) }}
5
+
6
+ <p>This is the end of Shield Security's Plugin & Theme Guard Scanner Wizard.</p>
7
+ {% endblock %}
templates/twig/wizard/slides/ptg/scanresult_base.twig ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'wizard/slides/common/base.twig' %}
2
+
3
+ {% block slide_body %}
4
+ {{ slideMacros.slideTitle( data.context_sing~' Guard Scan Results' ) }}
5
+
6
+ {% if data.result|length == 0 %}
7
+ <div class="alert alert-success" role="alert">
8
+ There were no files discovered that need your attention.
9
+ </div>
10
+ {% else %}
11
+ <div class="alert alert-warning" role="alert">
12
+ {{ data.result|length }} {{ data.context_sing }}(s) that need your attention.
13
+ </div>
14
+
15
+ <div id="accord{{ data.context_sing }}" class="scan-results-accordian">
16
+ {% set resultCounter = 0 %}
17
+ {% for item_name,item_res in data.result %}
18
+ {% set resultCounter = resultCounter + 1 %}
19
+
20
+ <div class="card">
21
+ <div class="card-header bg-secondary">
22
+ <h5 class="mb-0">
23
+ <button class="btn btn-link btn-block text-left collapsed"
24
+ data-toggle="collapse" data-target="#coll{{ data.context~resultCounter }}">
25
+ {{ data.context_sing }}: {{ item_name }}
26
+ </button>
27
+ </h5>
28
+ </div>
29
+
30
+ <div id="coll{{ data.context~resultCounter }}" class="collapse" data-parent="#accord{{ data.context_sing }}">
31
+ <div class="card-body">
32
+ {% if item_res.different is defined %}
33
+ <div class="indent_slight">
34
+ <h6>Modified Files: {{ item_res.different|length }}</h6>
35
+ {% for file in item_res.different %}
36
+ <li><code class="filepath">{{ file }}</code></li>
37
+ {% endfor %}
38
+ </div>
39
+ {% endif %}
40
+
41
+ {% if item_res.missing is defined %}
42
+ <div class="indent_slight">
43
+ <h6>Missing Files: {{ item_res.missing|length }}</h6>
44
+ {% for file in item_res.missing %}
45
+ <li><code class="filepath">{{ file }}</code></li>
46
+ {% endfor %}
47
+ </div>
48
+ {% endif %}
49
+
50
+ {% if item_res.unrecognised is defined %}
51
+ <div class="indent_slight">
52
+ <h6>Unrecognised Files: {{ item_res.unrecognised|length }}</h6>
53
+ {% for file in item_res.unrecognised %}
54
+ <li><code class="filepath">{{ file }}</code></li>
55
+ {% endfor %}
56
+ </div>
57
+ {% endif %}
58
+ </div>
59
+ </div>
60
+ <div class="card-footer">
61
+ <form class="icwp-wizard-form mb-0">
62
+ <div class="clearfix">
63
+ <div class="form-check form-check-inline">
64
+ <input class="form-check-input"
65
+ type="radio"
66
+ name="ptgaction"
67
+ id="ptgaction_{{ item_res.flags.id }}1"
68
+ {% if item_res.flags.can_reinstall %}
69
+ {% else %}
70
+ disabled
71
+ {% endif %}
72
+ value="reinstall" />
73
+ <label class="form-check-label" for="ptgaction_{{ item_res.flags.id }}1">
74
+ Re-Install / Upgrade</label>
75
+ </div>
76
+
77
+ {% if item_res.flags.can_deactivate %}
78
+ <div class="form-check form-check-inline">
79
+ <input class="form-check-input"
80
+ type="radio"
81
+ name="ptgaction"
82
+ id="ptgaction_{{ item_res.flags.id }}2"
83
+ {% if item_res.flags.can_deactivate %}
84
+ {% else %}
85
+ disabled
86
+ {% endif %}
87
+ value="deactivate" >
88
+ <label class="form-check-label" for="ptgaction_{{ item_res.flags.id }}2">
89
+ Deactivate</label>
90
+ </div>
91
+ {% endif %}
92
+
93
+ <div class="form-check form-check-inline">
94
+ <input class="form-check-input"
95
+ type="radio"
96
+ name="ptgaction"
97
+ id="ptgaction_{{ item_res.flags.id }}3"
98
+ value="ignore" >
99
+ <label class="form-check-label" for="ptgaction_{{ item_res.flags.id }}3">
100
+ Ignore Changes</label>
101
+ </div>
102
+ <button type="submit" class="btn btn-warning mb-2 float-right">
103
+ Run Selected Action</button>
104
+ </div>
105
+ {{ slideMacros.formInput_Hidden( 'wizard-step', 'ptg_assetaction' ) }}
106
+ {{ slideMacros.formInput_Hidden( 'slug', item_res.flags.slug ) }}
107
+ {{ slideMacros.formInput_Hidden( 'context', data.context ) }}
108
+ </form>
109
+ </div>
110
+ </div>
111
+ {% endfor %}
112
+ </div>
113
+
114
+ {% endif %}
115
+
116
+ {% endblock %}
templates/twig/wizard/slides/ptg/scanresult_plugins.twig ADDED
@@ -0,0 +1 @@
 
1
+ {% extends 'wizard/slides/ptg/scanresult_base.twig' %}
templates/twig/wizard/slides/ptg/scanresult_themes.twig ADDED
@@ -0,0 +1 @@
 
1
+ {% extends 'wizard/slides/ptg/scanresult_base.twig' %}
templates/twig/wizard/slides/ptg/start.twig ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'wizard/slides/common/base_start.twig' %}
2
+
3
+ {% block slide_body %}
4
+ {{ slideMacros.slideTitle( 'Start: Plugin & Theme Guard' ) }}
5
+
6
+ <p>What is the Plugin & Theme Guard?</p>
7
+ <p>The purpose of this scanner is to detect potentially malicious or
8
+ unintended changes to plugin and theme files.</p>
9
+ <p>Why is this important?</p>
10
+ <p>It is common for hacks to involve modifications to existing plugin and theme files.</p>
11
+ <p>This scanner will detect filesystem changes that have occurred outside normal WordPress operations, specifically:</p>
12
+ <ul>
13
+ <li>files where content has been modified</li>
14
+ <li>files that are missing</li>
15
+ <li>files that have been added</li>
16
+ </ul>
17
+ <p>If you're in doubt about the results, please discuss the findings with your hosting provider.</p>
18
+ {% endblock %}
templates/twig/wizard/slides/ufc/exclusions.twig CHANGED
@@ -1,18 +1,16 @@
1
  {% extends 'wizard/slides/common/base.twig' %}
2
 
3
  {% block slide_body %}
4
- {{ slideMacros.slideTitle( 'Unrecognised File Scanner - Exclusions' ) }}
5
-
6
- <p>Every website is different, so there are often many different types of files present on web hosts
7
- that are perfectly legitimate.</p>
8
- <p>Since we can't account for all these possibilities, we provide you with the option
9
- to add your own list of excluded files, that the scanner will then ignore.</p>
10
- <p>In the box provided below, simply add each file name you want to ignore. If you
11
- don't know what to put in here just now, or you don't want to add any further exclusions, simply move
12
- to the next step to run the scanner.</p>
13
- <p>Note: You can easily come back to this step and add files if the scanner picks anything up
14
- that you then want to ignore. You can do this as often as you like.</p>
15
- <p>Please use the list of files below to tell the file scanner which files it should completely ignore:</p>
16
 
17
  <form class="form-horizontal icwp-wizard-form" id>
18
 
1
  {% extends 'wizard/slides/common/base.twig' %}
2
 
3
  {% block slide_body %}
4
+ {{ slideMacros.slideTitle( 'Exclude Certain Files From Scan' ) }}
5
+ <p class="font-italic">(Skip to the next step to run the scan immediately.)</p>
6
+ <p>There are often different types of files on a website that are legitimate but
7
+ not part of the WordPress Core.</p>
8
+ <p>Since Shield can't automatically know about all the files on your hosting, we give you the ability
9
+ to add your own list of files to exclude from the scanner.</p>
10
+ <p>In the box below, add each file name you want to ignore. If you
11
+ don't know what to put in here just now, skip to the next step to run the scanner.</p>
12
+ <p>Note: You can come back here and add files if the scanner picks up something
13
+ that you want to ignore.</p>
 
 
14
 
15
  <form class="form-horizontal icwp-wizard-form" id>
16
 
templates/twig/wizard/slides/ufc/scanresult.twig CHANGED
@@ -4,8 +4,10 @@
4
  {{ slideMacros.slideTitle( 'Unrecognised File Scanner Results' ) }}
5
 
6
  {% if data.files.has %}
 
 
 
7
  <div class="indent_slight">
8
- <p>A total of {{ data.files.count }} file(s) were discovered.</p>
9
  <ul>
10
  {% for file in data.files.list %}
11
  <li><code class="filepath">{{ file }}</code></li>
4
  {{ slideMacros.slideTitle( 'Unrecognised File Scanner Results' ) }}
5
 
6
  {% if data.files.has %}
7
+ <div class="alert alert-warning" role="alert">
8
+ {{ data.files.count }} file(s) were discovered that you need to review.
9
+ </div>
10
  <div class="indent_slight">
 
11
  <ul>
12
  {% for file in data.files.list %}
13
  <li><code class="filepath">{{ file }}</code></li>
templates/twig/wizard/slides/wcf/scanresult.twig CHANGED
@@ -4,7 +4,9 @@
4
  {{ slideMacros.slideTitle( 'Core File Scanner Results' ) }}
5
 
6
  {% if data.files.has %}
7
- <p>A total of {{ data.files.count }} file(s) were discovered.</p>
 
 
8
  <div class="indent_slight">
9
  {% if data.files.checksum.has %}
10
  <h5>Modified Core Files: {{ data.files.checksum.count }}</h5>
@@ -47,6 +49,8 @@
47
  </form>
48
 
49
  {% else %}
50
- <p>There were no modified files discovered in the scan.</p>
 
 
51
  {% endif %}
52
  {% endblock %}
4
  {{ slideMacros.slideTitle( 'Core File Scanner Results' ) }}
5
 
6
  {% if data.files.has %}
7
+ <div class="alert alert-warning" role="alert">
8
+ {{ data.files.count }} file(s) were discovered that you need to review.
9
+ </div>
10
  <div class="indent_slight">
11
  {% if data.files.checksum.has %}
12
  <h5>Modified Core Files: {{ data.files.checksum.count }}</h5>
49
  </form>
50
 
51
  {% else %}
52
+ <div class="alert alert-success" role="alert">
53
+ Great! There were no modified files discovered in the scan.
54
+ </div>
55
  {% endif %}
56
  {% endblock %}
templates/twig/wizard/slides/wcf/start.twig CHANGED
@@ -3,14 +3,12 @@
3
  {% block slide_body %}
4
  {{ slideMacros.slideTitle( 'Start: WordPress Core File Scanner' ) }}
5
  <p>What is the WordPress Core File Scanner?</p>
6
- <p>The purpose of this scanner is to detect potentially malicious or
7
- unintended changes to any of the Core WordPress files.
8
- This is quite different to the Unrecognised File Scanner, which aims to detect
9
- the presence of files that are not part of the official set of WordPress core files.</p>
10
  <p>Why is this important?</p>
11
- <p>Your site may already be compromised and you wouldn't know it by glancing at which core
12
- files are installed on your site. The only way to know if your core WordPress files
13
- have been modified in any way is to compare them against the official files.</p>
14
  <p>This scanner will do exactly that and report to you any files it finds to be different.</p>
15
  <p>If you're in doubt about the results, please discuss the findings with your hosting provider.</p>
16
  {% endblock %}
3
  {% block slide_body %}
4
  {{ slideMacros.slideTitle( 'Start: WordPress Core File Scanner' ) }}
5
  <p>What is the WordPress Core File Scanner?</p>
6
+ <p>The purpose of this scanner is to detect malicious or
7
+ unintended changes to your Core WordPress files.</p>
 
 
8
  <p>Why is this important?</p>
9
+ <p>Your files may already be compromised and you wouldn't know it.
10
+ The only way to know if your core WordPress files
11
+ have been modified is to compare them against the official files from WordPress.org.</p>
12
  <p>This scanner will do exactly that and report to you any files it finds to be different.</p>
13
  <p>If you're in doubt about the results, please discuss the findings with your hosting provider.</p>
14
  {% endblock %}
templates/twig/wizard/snippets/wizard_landing.twig CHANGED
@@ -6,7 +6,7 @@
6
  </div>
7
  {% for wizard in data.mod_wizards %}
8
  <div class="row">
9
- <div class="col-6 offset-3 col-sm-10 offset-sm-1 col-lg-6 offset-lg-3">
10
  <div class="wizard_slot">
11
  <div><h5>{{ wizard.title }}</h5></div>
12
  <div>
@@ -15,7 +15,13 @@
15
  <p>{{ strings.premium_note }}</p>
16
  {% endif %}
17
  </div>
18
- <div><a class="btn btn-info" href="{{ wizard.url }}" target="_blank">Launch Wizard</a></div>
 
 
 
 
 
 
19
  </div>
20
  </div>
21
  </div>
6
  </div>
7
  {% for wizard in data.mod_wizards %}
8
  <div class="row">
9
+ <div class="col-8 offset-2">
10
  <div class="wizard_slot">
11
  <div><h5>{{ wizard.title }}</h5></div>
12
  <div>
15
  <p>{{ strings.premium_note }}</p>
16
  {% endif %}
17
  </div>
18
+ <div>
19
+ {% if wizard.available %}
20
+ <a class="btn btn-info" href="{{ wizard.url }}" target="_blank">Launch Wizard</a>
21
+ {% else %}
22
+ <button class="btn btn-outline-dark" disabled>Not Available</button>
23
+ {% endif %}
24
+ </div>
25
  </div>
26
  </div>
27
  </div>