Shield Security for WordPress - Version 6.1.0

Version Description

Latest Release = Released: 15th January, 2018 Release Notes

  • (v.0) ADDED: 3x more Shield Wizards: Multi-factor Authentication, Core File Scanning, Unrecognised File Scanning.
  • (v.0) ADDED: You can now use regular expressions for file exclusions in the 'Unrecognised File Scanner'.
  • (v.0) CHANGED: File Scanner email notifications now link to the appropriate scanner wizard directly.
  • (v.0) IMPROVED: Plugin options pages restyling.
  • (v.0) IMPROVED: Plugin refactoring and improvements.
Download this release

Release Info

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

Code changes from version 6.0.0 to 6.1.0

Files changed (99) hide show
  1. icwp-plugin-controller.php +9 -19
  2. icwp-wpsf.php +8 -104
  3. init.php +106 -0
  4. plugin-spec.php +2 -3
  5. readme.txt +21 -6
  6. resources/css/global-plugin.css +0 -72
  7. resources/css/plugin.css +237 -79
  8. resources/css/wizard.css +50 -1
  9. resources/images/banner-1500x500-transparent.png +0 -0
  10. resources/images/wand.png +0 -0
  11. resources/js/icwp-options.js +1 -0
  12. src/common/icwp-data.php +12 -1
  13. src/common/icwp-edd.php +3 -2
  14. src/common/icwp-foundation.php +1 -1
  15. src/common/icwp-ip.php +51 -14
  16. src/common/icwp-wpfunctions.php +13 -4
  17. src/config/feature-admin_access_restriction.php +2 -2
  18. src/config/feature-hack_protect.php +182 -135
  19. src/config/feature-login_protect.php +248 -222
  20. src/config/feature-plugin.php +321 -260
  21. src/features/admin_access_restriction.php +47 -43
  22. src/features/base.php +146 -10
  23. src/features/base_wpsf.php +1 -22
  24. src/features/hack_protect.php +54 -2
  25. src/features/license.php +1 -1
  26. src/features/login_protect.php +58 -9
  27. src/features/plugin.php +20 -34
  28. src/processors/admin_access_restriction.php +2 -2
  29. src/processors/base.php +2 -3
  30. src/processors/base_plugin.php +2 -1
  31. src/processors/base_wpsf.php +1 -0
  32. src/processors/email.php +49 -40
  33. src/processors/hack_protect.php +3 -3
  34. src/processors/hackprotect_corechecksumscan.php +13 -0
  35. src/processors/hackprotect_filecleanerscan.php +40 -23
  36. src/processors/hackprotect_wpvulnscan.php +1 -1
  37. src/processors/login_protect.php +2 -3
  38. src/processors/loginprotect_googleauthenticator.php +30 -8
  39. src/processors/loginprotect_intent.php +15 -18
  40. src/processors/loginprotect_intent_base.php +9 -6
  41. src/processors/loginprotect_twofactorauth.php +10 -40
  42. src/processors/plugin.php +0 -23
  43. src/processors/plugin_setupwizard.php +0 -830
  44. src/wizards/base.php +537 -0
  45. src/wizards/base_wpsf.php +127 -0
  46. src/wizards/hack_protect.php +346 -0
  47. src/wizards/login_protect.php +267 -0
  48. src/wizards/plugin.php +548 -0
  49. templates/html/plugin_badge.html +1 -1
  50. templates/php/feature-default.php +20 -4
  51. templates/php/index_footer.php +13 -1
  52. templates/php/index_header.php +11 -13
  53. templates/php/snippets/module-help-plugin.php +1 -1
  54. templates/php/snippets/module-help-template.php +4 -0
  55. templates/php/snippets/module-plugin-actions.php +2 -1
  56. templates/php/snippets/options_form.php +201 -159
  57. templates/php/snippets/plugin_badge.php +4 -2
  58. templates/php/snippets/state_summary.php +2 -13
  59. templates/twig/pages/base.twig +26 -17
  60. templates/twig/wizard/base_finish.twig +0 -7
  61. templates/twig/wizard/base_start.twig +0 -3
  62. templates/twig/wizard/pages/base.twig +19 -0
  63. templates/twig/wizard/pages/landing.twig +36 -0
  64. templates/twig/{pages → wizard/pages}/wizard.twig +15 -8
  65. templates/twig/wizard/slide-import_finished.twig +0 -7
  66. templates/twig/wizard/{base.twig → slides/common/base.twig} +7 -3
  67. templates/twig/wizard/slides/common/base_finish.twig +50 -0
  68. templates/twig/wizard/slides/common/base_start.twig +3 -0
  69. templates/twig/wizard/{slide-no_access.twig → slides/common/no_access.twig} +1 -1
  70. templates/twig/wizard/{slide-admin_access_restriction_verify.twig → slides/common/security_admin_verify.twig} +2 -2
  71. templates/twig/wizard/slides/importexport/finished.twig +6 -0
  72. templates/twig/wizard/{slide-import_options.twig → slides/importexport/import.twig} +4 -3
  73. templates/twig/wizard/{slide-import_start.twig → slides/importexport/start.twig} +5 -2
  74. templates/twig/wizard/slides/mfa/authemail.twig +69 -0
  75. templates/twig/wizard/slides/mfa/authga.twig +76 -0
  76. templates/twig/wizard/slides/mfa/finished.twig +6 -0
  77. templates/twig/wizard/slides/mfa/multiselect.twig +50 -0
  78. templates/twig/wizard/slides/mfa/start.twig +22 -0
  79. templates/twig/wizard/slides/ufc/config.twig +42 -0
  80. templates/twig/wizard/slides/ufc/exclusions.twig +53 -0
  81. templates/twig/wizard/slides/ufc/finished.twig +6 -0
  82. templates/twig/wizard/slides/ufc/scanresult.twig +50 -0
  83. templates/twig/wizard/slides/ufc/start.twig +18 -0
  84. templates/twig/wizard/slides/wcf/config.twig +36 -0
  85. templates/twig/wizard/slides/wcf/finished.twig +6 -0
  86. templates/twig/wizard/slides/wcf/scanresult.twig +64 -0
  87. templates/twig/wizard/slides/wcf/start.twig +16 -0
  88. templates/twig/wizard/{slide-admin_access_restriction.twig → slides/welcome/admin_access_restriction.twig} +1 -1
  89. templates/twig/wizard/{slide-audit_trail.twig → slides/welcome/audit_trail.twig} +1 -1
  90. templates/twig/wizard/{slide-comments_filter.twig → slides/welcome/comments_filter.twig} +1 -1
  91. templates/twig/wizard/{slide-how_shield_works.twig → slides/welcome/how_shield_works.twig} +1 -1
  92. templates/twig/wizard/slides/welcome/import.twig +1 -0
  93. templates/twig/wizard/slides/welcome/ip_detect.twig +40 -0
  94. templates/twig/wizard/{slide-ips.twig → slides/welcome/ips.twig} +1 -1
  95. templates/twig/wizard/{slide-license.twig → slides/welcome/license.twig} +1 -1
  96. templates/twig/wizard/{slide-login_protect.twig → slides/welcome/login_protect.twig} +1 -1
  97. templates/twig/wizard/{slide-optin.twig → slides/welcome/optin.twig} +1 -1
  98. templates/twig/wizard/{slide-thankyou.twig → slides/welcome/thankyou.twig} +2 -2
  99. templates/twig/wizard/{slide-welcome.twig → slides/welcome/welcome.twig} +1 -1
icwp-plugin-controller.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Copyright (c) 2017 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
  *
6
  * "Shield" (formerly WordPress Simple Firewall) is distributed under the GNU
@@ -127,9 +127,10 @@ class ICWP_WPSF_Plugin_Controller extends ICWP_WPSF_Foundation {
127
  private function __construct( $sRootFile ) {
128
  self::$sRootFile = $sRootFile;
129
  $this->checkMinimumRequirements();
130
- add_action( 'plugins_loaded', array( $this, 'onWpPluginsLoaded' ), 0 ); // this hook then registers everything
131
  $this->loadWpTrack();
132
  $this->loadFactory(); // so we know it's loaded whenever we need it. Cuz we need it.
 
133
  }
134
 
135
  /**
@@ -138,7 +139,7 @@ class ICWP_WPSF_Plugin_Controller extends ICWP_WPSF_Foundation {
138
  */
139
  private function readPluginSpecification() {
140
  $aSpec = array();
141
- $sContents = $this->loadDataProcessor()->readFileContentsUsingInclude( $this->getPathPluginSpec() );
142
  if ( !empty( $sContents ) ) {
143
  $aSpec = json_decode( $sContents, true );
144
  if ( empty( $aSpec ) ) {
@@ -256,13 +257,6 @@ class ICWP_WPSF_Plugin_Controller extends ICWP_WPSF_Foundation {
256
  $this->loadAllFeatures( true, true );
257
  }
258
 
259
- /**
260
- */
261
- public function onWpPluginsLoaded() {
262
- $this->doLoadTextDomain();
263
- $this->doRegisterHooks();
264
- }
265
-
266
  /**
267
  */
268
  protected function doRegisterHooks() {
@@ -985,20 +979,13 @@ class ICWP_WPSF_Plugin_Controller extends ICWP_WPSF_Foundation {
985
  return $this->getPluginSpec_Property( 'base_permissions' );
986
  }
987
 
988
- /**
989
- * @return bool
990
- */
991
- public function getUserCanBasePerms() {
992
- return current_user_can( $this->getBasePermissions() );
993
- }
994
-
995
  /**
996
  * @param bool $bCheckUserPerms - do we check the logged-in user permissions
997
  * @return bool
998
  */
999
  public function getIsValidAdminArea( $bCheckUserPerms = true ) {
1000
  if ( $bCheckUserPerms && $this->loadWpTrack()->getWpActionHasFired( 'init' )
1001
- && !$this->getUserCanBasePerms() ) {
1002
  return false;
1003
  }
1004
 
@@ -1205,7 +1192,7 @@ class ICWP_WPSF_Plugin_Controller extends ICWP_WPSF_Foundation {
1205
  * @return string
1206
  */
1207
  public function getPluginUrl_AdminMainPage() {
1208
- return $this->loadCorePluginFeatureHandler()->getFeatureAdminPageUrl();
1209
  }
1210
 
1211
  /**
@@ -1551,6 +1538,9 @@ class ICWP_WPSF_Plugin_Controller extends ICWP_WPSF_Foundation {
1551
  }
1552
  }
1553
  }
 
 
 
1554
  return $bSuccess;
1555
  }
1556
 
1
  <?php
2
  /**
3
+ * Copyright (c) 2018 iControlWP <support@icontrolwp.com>
4
  * All rights reserved.
5
  *
6
  * "Shield" (formerly WordPress Simple Firewall) is distributed under the GNU
127
  private function __construct( $sRootFile ) {
128
  self::$sRootFile = $sRootFile;
129
  $this->checkMinimumRequirements();
130
+ $this->doRegisterHooks();
131
  $this->loadWpTrack();
132
  $this->loadFactory(); // so we know it's loaded whenever we need it. Cuz we need it.
133
+ $this->doLoadTextDomain();
134
  }
135
 
136
  /**
139
  */
140
  private function readPluginSpecification() {
141
  $aSpec = array();
142
+ $sContents = $this->loadDP()->readFileContentsUsingInclude( $this->getPathPluginSpec() );
143
  if ( !empty( $sContents ) ) {
144
  $aSpec = json_decode( $sContents, true );
145
  if ( empty( $aSpec ) ) {
257
  $this->loadAllFeatures( true, true );
258
  }
259
 
 
 
 
 
 
 
 
260
  /**
261
  */
262
  protected function doRegisterHooks() {
979
  return $this->getPluginSpec_Property( 'base_permissions' );
980
  }
981
 
 
 
 
 
 
 
 
982
  /**
983
  * @param bool $bCheckUserPerms - do we check the logged-in user permissions
984
  * @return bool
985
  */
986
  public function getIsValidAdminArea( $bCheckUserPerms = true ) {
987
  if ( $bCheckUserPerms && $this->loadWpTrack()->getWpActionHasFired( 'init' )
988
+ && !$this->getMeetsBasePermissions() ) {
989
  return false;
990
  }
991
 
1192
  * @return string
1193
  */
1194
  public function getPluginUrl_AdminMainPage() {
1195
+ return $this->loadCorePluginFeatureHandler()->getUrl_AdminPage();
1196
  }
1197
 
1198
  /**
1538
  }
1539
  }
1540
  }
1541
+
1542
+ do_action( $this->doPluginPrefix( 'run_processors' ) );
1543
+
1544
  return $bSuccess;
1545
  }
1546
 
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.0.0
7
  * Text Domain: wp-simple-firewall
8
  * Domain Path: /languages/
9
  * Author: iControlWP
@@ -11,13 +11,11 @@
11
  */
12
 
13
  /**
14
- * Copyright (c) 2017 iControlWP <support@icontrolwp.com>
15
  * All rights reserved.
16
- *
17
  * "Shield" (formerly WordPress Simple Firewall) is distributed under the GNU
18
  * General Public License, Version 2, June 1991. Copyright (C) 1989, 1991 Free
19
  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
20
- *
21
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -30,11 +28,6 @@
30
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
  */
32
 
33
- if ( class_exists( 'ICWP_Wordpress_Simple_Firewall', false ) ) {
34
- error_log( 'Attempting to load the Shield Plugin twice?' );
35
- return;
36
- }
37
-
38
  if ( !defined( 'ICWP_DS' ) ) {
39
  define( 'ICWP_DS', DIRECTORY_SEPARATOR );
40
  }
@@ -50,100 +43,11 @@ if ( !function_exists( '_wpsf__' ) ) {
50
  }
51
  }
52
 
53
- // By requiring this file here, we assume we wont need to require it anywhere else.
54
- require_once( dirname( __FILE__ ).DIRECTORY_SEPARATOR.'src'.DIRECTORY_SEPARATOR.'common'.DIRECTORY_SEPARATOR.'icwp-foundation.php' );
55
- require_once( dirname( __FILE__ ).DIRECTORY_SEPARATOR.'icwp-plugin-controller.php' );
56
-
57
- class ICWP_Wordpress_Simple_Firewall extends ICWP_WPSF_Foundation {
58
-
59
- /**
60
- * @var ICWP_WPSF_Plugin_Controller
61
- */
62
- protected static $oPluginController;
63
-
64
- /**
65
- * @param ICWP_WPSF_Plugin_Controller $oController
66
- */
67
- protected function __construct( ICWP_WPSF_Plugin_Controller $oController ) {
68
-
69
- // All core values of the plugin are derived from the values stored in this value object.
70
- self::$oPluginController = $oController;
71
- $this->getController()->loadAllFeatures();
72
- add_filter( $oController->doPluginPrefix( 'plugin_update_message' ), array( $this, 'getPluginsListUpdateMessage' ) );
73
- add_action( 'plugin_action_links', array( $this, 'onWpPluginActionLinks' ), 10, 4 );
74
- }
75
-
76
- /**
77
- * @return ICWP_WPSF_Plugin_Controller
78
- */
79
- public static function getController() {
80
- return self::$oPluginController;
81
- }
82
-
83
- public function getPluginsListUpdateMessage( $sMessage ) {
84
- return _wpsf__( 'Upgrade Now To Keep Your Firewall Up-To-Date With The Latest Features.' );
85
- }
86
-
87
- /**
88
- * On the plugins listing page, hides the edit and deactivate links
89
- * for this plugin based on permissions
90
- * @param $aActionLinks
91
- * @param $sPluginFile
92
- * @return mixed
93
- */
94
- public function onWpPluginActionLinks( $aActionLinks, $sPluginFile ) {
95
- $oCon = $this->getController();
96
- if ( !$oCon->getIsValidAdminArea() ) {
97
- return $aActionLinks;
98
- }
99
-
100
- if ( $sPluginFile == $oCon->getPluginBaseFile() ) {
101
- if ( !$oCon->getHasPermissionToManage() ) {
102
-
103
- if ( array_key_exists( 'edit', $aActionLinks ) ) {
104
- unset( $aActionLinks[ 'edit' ] );
105
- }
106
- if ( array_key_exists( 'deactivate', $aActionLinks ) ) {
107
- unset( $aActionLinks[ 'deactivate' ] );
108
- }
109
- }
110
- }
111
- return $aActionLinks;
112
- }
113
- }
114
-
115
- class ICWP_WPSF_Shield_Security extends ICWP_Wordpress_Simple_Firewall {
116
-
117
- /**
118
- * @var ICWP_Wordpress_Simple_Firewall
119
- */
120
- protected static $oInstance = null;
121
-
122
- /**
123
- * @param ICWP_WPSF_Plugin_Controller $oController
124
- * @return self
125
- * @throws Exception
126
- */
127
- public static function GetInstance( $oController = null ) {
128
- if ( is_null( self::$oInstance ) ) {
129
- if ( is_null( $oController ) || !( $oController instanceof ICWP_WPSF_Plugin_Controller ) ) {
130
- throw new Exception( 'Trying to create a Shield Security instance without a valid Controller' );
131
- }
132
- self::$oInstance = new self( $oController );
133
- }
134
- return self::$oInstance;
135
- }
136
- }
137
-
138
- global $oICWP_Wpsf;
139
 
140
- try {
141
- $oICWP_Wpsf_Controller = ICWP_WPSF_Plugin_Controller::GetInstance( __FILE__ );
142
- $oICWP_Wpsf = ICWP_WPSF_Shield_Security::GetInstance( $oICWP_Wpsf_Controller );
143
- }
144
- catch ( Exception $oE ) {
145
- if ( is_admin() ) {
146
- error_log( 'Perhaps due to a failed upgrade, the Shield plugin failed to load certain component(s) - you should remove the plugin and reinstall.' );
147
- error_log( $oE->getMessage() );
148
- }
149
  }
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.1.0
7
  * Text Domain: wp-simple-firewall
8
  * Domain Path: /languages/
9
  * Author: iControlWP
11
  */
12
 
13
  /**
14
+ * Copyright (c) 2018 iControlWP <support@icontrolwp.com>
15
  * All rights reserved.
 
16
  * "Shield" (formerly WordPress Simple Firewall) is distributed under the GNU
17
  * General Public License, Version 2, June 1991. Copyright (C) 1989, 1991 Free
18
  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
 
19
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
  */
30
 
 
 
 
 
 
31
  if ( !defined( 'ICWP_DS' ) ) {
32
  define( 'ICWP_DS', DIRECTORY_SEPARATOR );
33
  }
43
  }
44
  }
45
 
46
+ // makes it available to the extension also.
47
+ require_once( dirname( __FILE__ ).'/src/common/icwp-foundation.php' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
49
+ add_action( 'plugins_loaded', 'icwp_wpsf_init', 1 ); // use 0 for extensions to ensure hooks have been added.
50
+ function icwp_wpsf_init() {
51
+ $sRootFile = __FILE__;
52
+ require_once( dirname( __FILE__ ).'/init.php' );
 
 
 
 
 
53
  }
init.php ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /** @var string $sRootFile */
3
+ global $oICWP_Wpsf;
4
+
5
+ if ( isset( $oICWP_Wpsf ) ) {
6
+ error_log( 'Attempting to load the Shield Plugin twice?' );
7
+ return;
8
+ }
9
+
10
+ // By requiring this file here, we assume we wont need to require it anywhere else.
11
+ require_once( dirname( __FILE__ ).DIRECTORY_SEPARATOR.'icwp-plugin-controller.php' );
12
+
13
+ class ICWP_Wordpress_Simple_Firewall extends ICWP_WPSF_Foundation {
14
+
15
+ /**
16
+ * @var ICWP_WPSF_Plugin_Controller
17
+ */
18
+ protected static $oPluginController;
19
+
20
+ /**
21
+ * @param ICWP_WPSF_Plugin_Controller $oController
22
+ */
23
+ protected function __construct( ICWP_WPSF_Plugin_Controller $oController ) {
24
+
25
+ // All core values of the plugin are derived from the values stored in this value object.
26
+ self::$oPluginController = $oController;
27
+ $this->getController()->loadAllFeatures();
28
+ add_filter( $oController->doPluginPrefix( 'plugin_update_message' ), array(
29
+ $this,
30
+ 'getPluginsListUpdateMessage'
31
+ ) );
32
+ add_action( 'plugin_action_links', array( $this, 'onWpPluginActionLinks' ), 10, 4 );
33
+ }
34
+
35
+ /**
36
+ * @return ICWP_WPSF_Plugin_Controller
37
+ */
38
+ public static function getController() {
39
+ return self::$oPluginController;
40
+ }
41
+
42
+ public function getPluginsListUpdateMessage( $sMessage ) {
43
+ return _wpsf__( 'Upgrade Now To Keep Your Firewall Up-To-Date With The Latest Features.' );
44
+ }
45
+
46
+ /**
47
+ * On the plugins listing page, hides the edit and deactivate links
48
+ * for this plugin based on permissions
49
+ * @param $aActionLinks
50
+ * @param $sPluginFile
51
+ * @return mixed
52
+ */
53
+ public function onWpPluginActionLinks( $aActionLinks, $sPluginFile ) {
54
+ $oCon = $this->getController();
55
+ if ( !$oCon->getIsValidAdminArea() ) {
56
+ return $aActionLinks;
57
+ }
58
+
59
+ if ( $sPluginFile == $oCon->getPluginBaseFile() ) {
60
+ if ( !$oCon->getHasPermissionToManage() ) {
61
+
62
+ if ( array_key_exists( 'edit', $aActionLinks ) ) {
63
+ unset( $aActionLinks[ 'edit' ] );
64
+ }
65
+ if ( array_key_exists( 'deactivate', $aActionLinks ) ) {
66
+ unset( $aActionLinks[ 'deactivate' ] );
67
+ }
68
+ }
69
+ }
70
+ return $aActionLinks;
71
+ }
72
+ }
73
+
74
+ class ICWP_WPSF_Shield_Security extends ICWP_Wordpress_Simple_Firewall {
75
+
76
+ /**
77
+ * @var ICWP_Wordpress_Simple_Firewall
78
+ */
79
+ protected static $oInstance = null;
80
+
81
+ /**
82
+ * @param ICWP_WPSF_Plugin_Controller $oController
83
+ * @return self
84
+ * @throws Exception
85
+ */
86
+ public static function GetInstance( $oController = null ) {
87
+ if ( is_null( self::$oInstance ) ) {
88
+ if ( is_null( $oController ) || !( $oController instanceof ICWP_WPSF_Plugin_Controller ) ) {
89
+ throw new Exception( 'Trying to create a Shield Security instance without a valid Controller' );
90
+ }
91
+ self::$oInstance = new self( $oController );
92
+ }
93
+ return self::$oInstance;
94
+ }
95
+ }
96
+
97
+ try {
98
+ $oICWP_Wpsf_Controller = ICWP_WPSF_Plugin_Controller::GetInstance( $sRootFile );
99
+ $oICWP_Wpsf = ICWP_WPSF_Shield_Security::GetInstance( $oICWP_Wpsf_Controller );
100
+ }
101
+ catch ( Exception $oE ) {
102
+ if ( is_admin() ) {
103
+ error_log( 'Perhaps due to a failed upgrade, the Shield plugin failed to load certain component(s) - you should remove the plugin and reinstall.' );
104
+ error_log( $oE->getMessage() );
105
+ }
106
+ }
plugin-spec.php CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "properties": {
3
- "version": "6.0.0",
4
  "slug_parent": "icwp",
5
  "slug_plugin": "wpsf",
6
  "human_name": "Shield",
@@ -44,8 +44,7 @@
44
  "plugin"
45
  ],
46
  "js": [
47
- "bootstrap.min",
48
- "icwp-options"
49
  ]
50
  },
51
  "frontend": {
1
  {
2
  "properties": {
3
+ "version": "6.1.0",
4
  "slug_parent": "icwp",
5
  "slug_plugin": "wpsf",
6
  "human_name": "Shield",
44
  "plugin"
45
  ],
46
  "js": [
47
+ "bootstrap.min"
 
48
  ]
49
  },
50
  "frontend": {
readme.txt CHANGED
@@ -3,10 +3,10 @@ Contributors: onedollarplugin, paultgoodchild
3
  Donate link: http://icwp.io/q
4
  License: GPLv3
5
  License URI: http://www.gnu.org/licenses/gpl.html
6
- Tags: security, firewall, spam, scan, 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.0.0
10
 
11
  Protect your reputation, your customers' reputation, and your WordPress sites for free with Shield - the most powerful security system for WordPress
12
 
@@ -338,7 +338,25 @@ Technical support, and some newer options and features will not be available to
338
 
339
  You can [go Pro for just $1/month](http://icwp.io/aa). Technical support is available to premium clients only.
340
 
341
- = 6.0.0 Latest Point Release =
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
342
  *Released: 18th December, 2017*
343
 
344
  * **(v.0)** ADDED: All-new Shield Welcome and Setup Wizard - more helpful guided wizards to come.
@@ -346,9 +364,6 @@ You can [go Pro for just $1/month](http://icwp.io/aa). Technical support is avai
346
  * **(v.0)** ADDED: [**PRO**] In conjunction with import/export - Shield Security Network: automated options syncing.
347
  * **(v.0)** CHANGED: Going forward, new features and options will [support only PHP 5.4+](http://icwp.io/au). Existing features will remain unaffected.
348
 
349
- = 6.0.0 Series =
350
- *Released: 18th December, 2017*
351
-
352
  = 5.20.0 Series =
353
  *Released: 11th December, 2017*
354
 
3
  Donate link: http://icwp.io/q
4
  License: GPLv3
5
  License URI: http://www.gnu.org/licenses/gpl.html
6
+ Tags: security, firewall, 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.1.0
10
 
11
  Protect your reputation, your customers' reputation, and your WordPress sites for free with Shield - the most powerful security system for WordPress
12
 
338
 
339
  You can [go Pro for just $1/month](http://icwp.io/aa). Technical support is available to premium clients only.
340
 
341
+ = 6.1.0 Latest Release =
342
+ *Released: 15th January, 2018* [Release Notes](http://icwp.io/ay)
343
+
344
+ * **(v.0)** ADDED: 3x more Shield Wizards: Multi-factor Authentication, Core File Scanning, Unrecognised File Scanning.
345
+ * **(v.0)** ADDED: You can now use regular expressions for file exclusions in the 'Unrecognised File Scanner'.
346
+ * **(v.0)** CHANGED: File Scanner email notifications now link to the appropriate scanner wizard directly.
347
+ * **(v.0)** IMPROVED: Plugin options pages restyling.
348
+ * **(v.0)** IMPROVED: Plugin refactoring and improvements.
349
+
350
+ = 6.1.0 Series =
351
+ *Released: 15th January, 2018*
352
+
353
+ * **(v.0)** ADDED: 3x more Shield Wizards: Multi-factor Authentication, Core File Scanning, Unrecognised File Scanning.
354
+ * **(v.0)** ADDED: You can now use regular expressions for file exclusions in the 'Unrecognised File Scanner'.
355
+ * **(v.0)** CHANGED: File Scanner email notifications now link to the appropriate scanner wizard directly.
356
+ * **(v.0)** IMPROVED: Plugin options pages restyling.
357
+ * **(v.0)** IMPROVED: Plugin refactoring and improvements.
358
+
359
+ = 6.0.0 Series =
360
  *Released: 18th December, 2017*
361
 
362
  * **(v.0)** ADDED: All-new Shield Welcome and Setup Wizard - more helpful guided wizards to come.
364
  * **(v.0)** ADDED: [**PRO**] In conjunction with import/export - Shield Security Network: automated options syncing.
365
  * **(v.0)** CHANGED: Going forward, new features and options will [support only PHP 5.4+](http://icwp.io/au). Existing features will remain unaffected.
366
 
 
 
 
367
  = 5.20.0 Series =
368
  *Released: 11th December, 2017*
369
 
resources/css/global-plugin.css CHANGED
@@ -76,78 +76,6 @@ ul.nav-tabs li.active a {
76
  .bootstrap-wpadmin .icwpTopLevelRow .icwpTopLevelSpan {
77
  margin-left: 0;
78
  }
79
- #icwpOptionsTopPill {
80
- }
81
- #icwpOptionsTopPill > .nav-pills {
82
- border-bottom: 1px dashed #999999;
83
- padding-bottom: 10px;
84
- }
85
- #icwpOptionsTopPill > .nav-pills li {
86
- width: 33.3%;
87
- }
88
- #icwpOptionsTopPill > .nav-pills li a {
89
- background-color: rgba(0, 0, 0, 0.2);
90
- text-shadow: 1px 0 0 rgba(255, 255, 255, 0.4);
91
- color: #666666;
92
- height: 50px;
93
- }
94
- #icwpOptionsTopPill > .nav-pills li a:hover {
95
- background-color: rgba(38, 66, 1, 0.3);
96
- }
97
- #icwpOptionsTopPill > .nav-pills li a:focus {
98
- box-shadow: none;
99
- }
100
- #icwpOptionsTopPill > .nav-pills li span.dashicons {
101
- float: left;
102
- height: 100%;
103
- font-size: 48px;
104
- display: block;
105
- width: 62px;
106
- }
107
- #icwpOptionsTopPill > .nav-pills li.active a {
108
- background-color: rgba(69, 119, 0, 1);
109
- color: #ffffff;
110
- text-shadow: 1px 0 0 rgba(0, 0, 0, 0.5);
111
- }
112
- #icwpOptionsTopPill > .nav-pills li a .title {
113
- font-weight: bolder;
114
- font-size: 18px;
115
- line-height: 24px;
116
- }
117
- #icwpOptionsTopPill > .nav-pills li a .summary {
118
- font-size: 16px;
119
- line-height: 28px;
120
- padding-left: 10px;
121
- }
122
- #icwpOptionsTopPill > .nav-pills li a.active {
123
- }
124
- #icwpOptionsTopPill > .tab-content {
125
- background-color: transparent;
126
- border: 1px solid transparent;
127
- }
128
- #icwpOptionsTopPill > .tab-content .content-help {
129
- background-color: #fafafa;
130
- padding: 10px 20px;
131
- box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
132
- margin: 5px;
133
- }
134
- #icwpOptionsTopPill .content-help h2 {
135
- margin-bottom: 8px;
136
- }
137
- #icwpOptionsTopPill .content-help p,
138
- #icwpOptionsTopPill .content-help li {
139
- font-size: 14px;
140
- }
141
- #icwpOptionsTopPill .content-help dt {
142
- border-bottom: 1px dotted rgba(0, 0, 0, 0.2);
143
- font-size: 16px;
144
- margin-bottom: 7px;
145
- padding-bottom: 3px;
146
- }
147
- #icwpOptionsTopPill .content-help dd {
148
- margin-bottom: 15px;
149
- margin-left: 12px;
150
- }
151
  th.column-icwp_autoupdate, td.icwp_autoupdate, th#icwp_autoupdate {
152
  text-align: center;
153
  vertical-align: middle;
76
  .bootstrap-wpadmin .icwpTopLevelRow .icwpTopLevelSpan {
77
  margin-left: 0;
78
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  th.column-icwp_autoupdate, td.icwp_autoupdate, th#icwp_autoupdate {
80
  text-align: center;
81
  vertical-align: middle;
resources/css/plugin.css CHANGED
@@ -29,7 +29,16 @@
29
  .wrap .icon32 {
30
  width: 32px;
31
  }
32
-
 
 
 
 
 
 
 
 
 
33
  .icwp-options-page ul.nav-tabs {
34
  margin: 0;
35
  }
@@ -51,7 +60,6 @@
51
  border: 1px solid #dddddd;
52
  border-top: 0 none;
53
  }
54
-
55
  .icwp-options-page .form-actions {
56
  background-color: #d8d8d8;
57
  border: 0 none;
@@ -62,13 +70,11 @@
62
  .icwp-options-page .form-actions .btn {
63
  padding: 16px 40px;
64
  }
65
-
66
  table.table-audit_trail {
67
  border: 2px solid #777777;
68
  margin-bottom: 40px;
69
  width: auto;
70
  }
71
-
72
  table.table-audit_trail .cell-time {
73
  width: 90px;
74
  max-width: 90px;
@@ -93,14 +99,6 @@ table.table-audit_trail .cell-ip {
93
  width: 200px;
94
  max-width: 240px;
95
  }
96
-
97
-
98
-
99
- .bootstrap-wpadmin .page-header {
100
- padding-bottom: 17px;
101
- margin: 18px 0 0;
102
- border-bottom: 1px solid transparent;
103
- }
104
  /* Form elements */
105
  .bootstrap-wpadmin form fieldset {
106
  width: 80%;
@@ -117,7 +115,7 @@ p.code-description {
117
  }
118
  /* Worpit promo */
119
  #worpit_button {
120
- background: url("../images/bright_squares.png") #EFEFEF;
121
  }
122
  #worpit_button {
123
  border: 1px solid #cccccc;
@@ -132,14 +130,13 @@ p.code-description {
132
  height: 275px;
133
  }
134
  .row#developer_channel_promo #developer_channel_form {
135
- border: 1px solid #EEE;
136
  border-radius: 6px;
137
  height: 315px; /* 275px + 20px-padding-x2 */
138
  }
139
  .row#developer_channel_promo #developer_channel_form h3 {
140
  padding: 10px 20px;
141
  }
142
-
143
  .row.option_section_row {
144
  margin-left: 0;
145
  padding-bottom: 24px;
@@ -163,14 +160,12 @@ p.code-description {
163
 
164
  .well.admin_access_restriction_form {
165
  background-color: #fbfbfb;
166
- border: 1px solid #ccc;
167
  box-shadow: none;
168
  }
169
-
170
  .well.admin_access_restriction_form .form-actions {
171
  background-color: #fbfbfb;
172
  }
173
-
174
  /** LESS PAGE **/
175
  .enabled_section {
176
  opacity: 1.0;
@@ -180,25 +175,25 @@ p.code-description {
180
  }
181
  /* BOOSTRAP SETTINGS PAGE STYLES */
182
 
 
 
 
183
  /** Section summaries **/
184
- .row.row_section_summary {
185
- margin: 10px 0 20px;
186
  }
187
- .row.row_section_summary div {
188
- background-color: #f1f1f1;
189
- border-radius: 2px;
190
- box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
191
  margin: 0;
192
- padding: 15px 0 12px;
193
  }
194
- .row.row_section_summary p {
195
- margin: 0 20px 12px 20px;
196
- font-family: 'Open Sans';
197
  }
198
- .row.row_section_summary p.noselect {
199
  -webkit-touch-callout: none;
200
  -webkit-user-select: none;
201
- -khtml-user-select: none;
202
  -moz-user-select: none;
203
  -ms-user-select: none;
204
  user-select: none;
@@ -212,46 +207,59 @@ p.code-description {
212
  font-size: smaller;
213
  font-style: italic;
214
  }
215
- .form-horizontal legend {
216
- border-bottom: 1px dashed #aaaaaa;
217
- margin-bottom: 11px;
218
- padding: 16px 0 3px;
 
219
  }
220
- .form-horizontal .item_group {
221
- border: 1px solid rgba(0, 0, 0, 0.08);
222
- border-radius: 4px;
 
223
  box-sizing: border-box;
224
- margin-left: 40px;
225
  padding: 0;
226
- }
227
- .form-horizontal .item_group .control-group {
228
- margin: 20px 20px 20px 0;
229
  }
230
- .form-horizontal .item_group .control-group .control-label {
231
- padding-left: 10px;
232
  }
233
- .form-horizontal .selected_item_group {
234
- background-color: rgba(135, 232, 38, 0.05);
235
- border: 1px solid rgba(135, 232, 38, 0.55);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
  }
237
-
238
  .row.option_row {
239
  margin-bottom: 15px;
240
  }
241
-
242
  .overlay_container.disabled {
243
  position: relative;
244
  }
245
  .option_overlay {
246
  position: absolute;
247
- background-color: rgba(0,0,0,0.2);
248
  height: 100%;
249
  width: 100%;
250
  transition: background-color 0.5s ease;
251
  z-index: 5;
252
  }
253
  .option_overlay:hover {
254
- background-color: rgba(0,0,0,0.5);
255
  }
256
  .option_overlay .overlay_message {
257
  display: none;
@@ -259,23 +267,28 @@ p.code-description {
259
  .option_overlay .overlay_message:hover,
260
  .option_overlay:hover .overlay_message {
261
  display: block;
262
- color: #333;
263
- font-size: 32px;
264
  margin: 25px auto auto auto;
265
  padding: 0 20px;
266
  width: auto;
267
- background: rgba(255,255,255,0.8);
268
  line-height: 50px;
269
  text-align: center;
270
  user-select: none;
271
  }
272
-
 
 
273
  .option_section {
274
- background-color: rgba(0, 0, 0, 0.008);
275
- border: 1px dashed rgba(0, 0, 0, 0.1);
276
  border-radius: 4px;
277
  padding: 8px 10px;
278
  }
 
 
 
279
  .option_section label {
280
  background-color: transparent;
281
  }
@@ -290,16 +303,13 @@ p.code-description {
290
  }
291
  .option_section:hover {
292
  background-color: #ffffff;
293
- border: 1px dashed #BBBBBB;
294
- cursor: pointer;
295
  }
296
-
297
  .option_section.active {
298
  }
299
  table.table th {
300
  border-bottom: 1px solid #777777;
301
  }
302
-
303
  table.tbl_tbs_options {
304
  width: 100%;
305
  border: 1px solid transparent;
@@ -308,19 +318,16 @@ table.tbl_tbs_options tr td {
308
  width: 49%;
309
  border: 1px solid transparent;
310
  }
311
-
312
  select#hlt_bootstrap_option {
313
  padding: 5px;
314
- border-radius:6px 6px 6px 6px;
315
  height: 30px;
316
  width: 200px;
317
  }
318
-
319
  table#tbl_tbs_options_javascript td {
320
  vertical-align: top;
321
  width: 50%;
322
  }
323
-
324
  /** OPTIONS PAGES **/
325
  .bootstrap-wpadmin > .row {
326
  width: 960px;
@@ -330,13 +337,14 @@ table#tbl_tbs_options_javascript td {
330
  label input[type=checkbox] {
331
  height: 16px !important;
332
  }
333
-
334
  /** FEature summaries **/
335
  .bootstrap-wpadmin .feature-summary-blocks {
336
  text-align: center;
337
  width: 100%;
338
  margin-top: 20px;
339
- box-shadow: 3px 3px 6px 0 rgba(0,0,0,0.3);
 
 
340
  }
341
  .feature-summary-blocks .feature-icon:before {
342
  -webkit-font-smoothing: antialiased;
@@ -349,22 +357,20 @@ label input[type=checkbox] {
349
  text-shadow: 1px 0 0 rgba(0, 0, 0, 0.4);
350
  width: 100%;
351
  }
352
-
353
  .feature-summary-blocks .summary-state {
354
  border: 1px solid transparent;
355
  overflow: hidden;
356
  text-align: center;
357
  margin-bottom: -1px;
358
  }
359
-
360
  .feature-summary-blocks .summary-state.active-feature {
361
  background-color: rgba(69, 119, 0, 1);
362
  }
363
  .feature-summary-blocks .summary-state.active-feature a {
364
- color: rgba(255,255,255,1);
365
  }
366
  .feature-summary-blocks .summary-state.active-feature.state-off {
367
- background-color: rgba( 173, 84, 0, 0.85 );
368
  }
369
  .feature-summary-blocks .summary-state .popover {
370
  box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.4);
@@ -382,10 +388,10 @@ label input[type=checkbox] {
382
  border-left: 1px solid transparent;
383
  background-color: rgba(255, 255, 255, 0.8);
384
  }
385
- .feature-summary-blocks .summary-state:hover{
386
  }
387
  .feature-summary-blocks .summary-state a p {
388
- text-shadow: 0 0 0 rgba(0,0,0, 0.6);
389
  font-size: 12px;
390
  margin: 0;
391
  }
@@ -407,7 +413,7 @@ label input[type=checkbox] {
407
  color: rgba(69, 119, 0, 1);
408
  }
409
  .feature-summary-blocks .state-off a {
410
- color: rgba( 173, 84, 0, 0.85 );
411
  }
412
  .feature-summary-blocks .state-on a:hover {
413
  color: rgb(99, 150, 0);
@@ -415,14 +421,13 @@ label input[type=checkbox] {
415
  .feature-summary-blocks .state-off a:hover {
416
  color: rgba(207, 90, 0, 0.85);
417
  }
418
-
419
  .feature-summary-blocks .feature-summary-block.state-on {
420
- background-color: rgba( 102, 216, 45, 0.2 );
421
  }
422
  .feature-summary-blocks .feature-summary-block.state-off {
423
- background-color: rgba( 239, 141, 49, 0.2 );
424
  }
425
- #feature-plugin .feature-icon:before{
426
  content: "\f111";
427
  }
428
  #feature-admin_access_restriction .feature-icon:before {
@@ -464,11 +469,9 @@ label input[type=checkbox] {
464
  #feature-support .feature-icon:before {
465
  content: "\f525";
466
  }
467
-
468
  input[type="email"] {
469
  height: 28px;
470
  }
471
-
472
  .bootstrap-wpadmin .row .shield-free-block {
473
  background-color: rgba(255, 255, 255, 0.7);
474
  border: 1px solid rgba(0, 0, 0, 0.1);
@@ -476,4 +479,159 @@ input[type="email"] {
476
  }
477
  .bootstrap-wpadmin .row .shield-free-block p {
478
  margin-bottom: 18px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
479
  }
29
  .wrap .icon32 {
30
  width: 32px;
31
  }
32
+ .bootstrap-wpadmin .page-header {
33
+ margin: 5px 0 15px;
34
+ padding-bottom: 0;
35
+ border-bottom: 1px solid transparent;
36
+ }
37
+ .bootstrap-wpadmin .page-header h2 small.feature-tagline {
38
+ font-size: 14px;
39
+ line-height: 10px;
40
+ letter-spacing: -0.5px;
41
+ }
42
  .icwp-options-page ul.nav-tabs {
43
  margin: 0;
44
  }
60
  border: 1px solid #dddddd;
61
  border-top: 0 none;
62
  }
 
63
  .icwp-options-page .form-actions {
64
  background-color: #d8d8d8;
65
  border: 0 none;
70
  .icwp-options-page .form-actions .btn {
71
  padding: 16px 40px;
72
  }
 
73
  table.table-audit_trail {
74
  border: 2px solid #777777;
75
  margin-bottom: 40px;
76
  width: auto;
77
  }
 
78
  table.table-audit_trail .cell-time {
79
  width: 90px;
80
  max-width: 90px;
99
  width: 200px;
100
  max-width: 240px;
101
  }
 
 
 
 
 
 
 
 
102
  /* Form elements */
103
  .bootstrap-wpadmin form fieldset {
104
  width: 80%;
115
  }
116
  /* Worpit promo */
117
  #worpit_button {
118
+ background: url("../images/bright_squares.png") #efefef;
119
  }
120
  #worpit_button {
121
  border: 1px solid #cccccc;
130
  height: 275px;
131
  }
132
  .row#developer_channel_promo #developer_channel_form {
133
+ border: 1px solid #eeeeee;
134
  border-radius: 6px;
135
  height: 315px; /* 275px + 20px-padding-x2 */
136
  }
137
  .row#developer_channel_promo #developer_channel_form h3 {
138
  padding: 10px 20px;
139
  }
 
140
  .row.option_section_row {
141
  margin-left: 0;
142
  padding-bottom: 24px;
160
 
161
  .well.admin_access_restriction_form {
162
  background-color: #fbfbfb;
163
+ border: 1px solid #cccccc;
164
  box-shadow: none;
165
  }
 
166
  .well.admin_access_restriction_form .form-actions {
167
  background-color: #fbfbfb;
168
  }
 
169
  /** LESS PAGE **/
170
  .enabled_section {
171
  opacity: 1.0;
175
  }
176
  /* BOOSTRAP SETTINGS PAGE STYLES */
177
 
178
+ .bootstrap-wpadmin .form-horizontal .form-actions {
179
+ padding-left: 200px;
180
+ }
181
  /** Section summaries **/
182
+ .row_section_summary {
 
183
  }
184
+ .row_section_summary div {
185
+ background-color: #f5f4f4;
186
+ border: 1px solid rgb(230, 226, 226);
187
+ border-width: 1px 0;
188
  margin: 0;
189
+ padding: 0 20px 0 2px;
190
  }
191
+ .row_section_summary p {
192
+ margin: 12px 20px;
 
193
  }
194
+ .row_section_summary p.noselect {
195
  -webkit-touch-callout: none;
196
  -webkit-user-select: none;
 
197
  -moz-user-select: none;
198
  -ms-user-select: none;
199
  user-select: none;
207
  font-size: smaller;
208
  font-style: italic;
209
  }
210
+ .options-body legend {
211
+ border-bottom: 1px dashed transparent;
212
+ margin-bottom: 0;
213
+ padding: 16px 22px 12px;
214
+ width: 80%;
215
  }
216
+ .option_row .item_group {
217
+ border-style: solid;
218
+ border-width: 1px 0;
219
+ border-color: rgb(230, 226, 226);
220
  box-sizing: border-box;
 
221
  padding: 0;
222
+ margin-top: -1px;
 
 
223
  }
224
+ .option_row .item_group .control-group {
225
+ margin: 22px 20px;
226
  }
227
+ .option_row .item_group .control-group .controls {
228
+ margin-left: 180px;
229
+ }
230
+ .option_row .item_group .control-group .control-label {
231
+ float: left;
232
+ width: 150px;
233
+ margin-top: 2px;
234
+ text-align: right;
235
+ }
236
+ .control-label .optname {
237
+ display: block;
238
+ }
239
+ .control-label .optlinks {
240
+ display: block;
241
+ margin-top: 5px;
242
+ }
243
+ .option_row .item_group.selected_item_group {
244
+ background-color: rgba(135, 232, 38, 0.03);
245
+ border-color: rgb(203, 232, 174);
246
  }
 
247
  .row.option_row {
248
  margin-bottom: 15px;
249
  }
 
250
  .overlay_container.disabled {
251
  position: relative;
252
  }
253
  .option_overlay {
254
  position: absolute;
255
+ background-color: rgba(0, 0, 0, 0.2);
256
  height: 100%;
257
  width: 100%;
258
  transition: background-color 0.5s ease;
259
  z-index: 5;
260
  }
261
  .option_overlay:hover {
262
+ background-color: rgba(0, 0, 0, 0.5);
263
  }
264
  .option_overlay .overlay_message {
265
  display: none;
267
  .option_overlay .overlay_message:hover,
268
  .option_overlay:hover .overlay_message {
269
  display: block;
270
+ color: #333333;
271
+ font-size: 24px;
272
  margin: 25px auto auto auto;
273
  padding: 0 20px;
274
  width: auto;
275
+ background: rgba(255, 255, 255, 0.8);
276
  line-height: 50px;
277
  text-align: center;
278
  user-select: none;
279
  }
280
+ .option_overlay:hover .overlay_message a:hover {
281
+ text-decoration: none;
282
+ }
283
  .option_section {
284
+ background-color: transparent;
285
+ border: 1px dashed transparent;
286
  border-radius: 4px;
287
  padding: 8px 10px;
288
  }
289
+ .option_section input[type=checkbox] {
290
+ margin-right: 5px;
291
+ }
292
  .option_section label {
293
  background-color: transparent;
294
  }
303
  }
304
  .option_section:hover {
305
  background-color: #ffffff;
306
+ border: 1px dashed #bbbbbb;
 
307
  }
 
308
  .option_section.active {
309
  }
310
  table.table th {
311
  border-bottom: 1px solid #777777;
312
  }
 
313
  table.tbl_tbs_options {
314
  width: 100%;
315
  border: 1px solid transparent;
318
  width: 49%;
319
  border: 1px solid transparent;
320
  }
 
321
  select#hlt_bootstrap_option {
322
  padding: 5px;
323
+ border-radius: 6px 6px 6px 6px;
324
  height: 30px;
325
  width: 200px;
326
  }
 
327
  table#tbl_tbs_options_javascript td {
328
  vertical-align: top;
329
  width: 50%;
330
  }
 
331
  /** OPTIONS PAGES **/
332
  .bootstrap-wpadmin > .row {
333
  width: 960px;
337
  label input[type=checkbox] {
338
  height: 16px !important;
339
  }
 
340
  /** FEature summaries **/
341
  .bootstrap-wpadmin .feature-summary-blocks {
342
  text-align: center;
343
  width: 100%;
344
  margin-top: 20px;
345
+ box-shadow: 1px 1px 2px 0 rgba(0, 0, 0, 0.2) inset;
346
+ border: 1px solid #ccc;
347
+ background: #f9f9f9;
348
  }
349
  .feature-summary-blocks .feature-icon:before {
350
  -webkit-font-smoothing: antialiased;
357
  text-shadow: 1px 0 0 rgba(0, 0, 0, 0.4);
358
  width: 100%;
359
  }
 
360
  .feature-summary-blocks .summary-state {
361
  border: 1px solid transparent;
362
  overflow: hidden;
363
  text-align: center;
364
  margin-bottom: -1px;
365
  }
 
366
  .feature-summary-blocks .summary-state.active-feature {
367
  background-color: rgba(69, 119, 0, 1);
368
  }
369
  .feature-summary-blocks .summary-state.active-feature a {
370
+ color: rgba(255, 255, 255, 1);
371
  }
372
  .feature-summary-blocks .summary-state.active-feature.state-off {
373
+ background-color: rgba(173, 84, 0, 0.85);
374
  }
375
  .feature-summary-blocks .summary-state .popover {
376
  box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.4);
388
  border-left: 1px solid transparent;
389
  background-color: rgba(255, 255, 255, 0.8);
390
  }
391
+ .feature-summary-blocks .summary-state:hover {
392
  }
393
  .feature-summary-blocks .summary-state a p {
394
+ text-shadow: 0 0 0 rgba(0, 0, 0, 0.6);
395
  font-size: 12px;
396
  margin: 0;
397
  }
413
  color: rgba(69, 119, 0, 1);
414
  }
415
  .feature-summary-blocks .state-off a {
416
+ color: rgba(173, 84, 0, 0.85);
417
  }
418
  .feature-summary-blocks .state-on a:hover {
419
  color: rgb(99, 150, 0);
421
  .feature-summary-blocks .state-off a:hover {
422
  color: rgba(207, 90, 0, 0.85);
423
  }
 
424
  .feature-summary-blocks .feature-summary-block.state-on {
425
+ background-color: rgba(102, 216, 45, 0.2);
426
  }
427
  .feature-summary-blocks .feature-summary-block.state-off {
428
+ background-color: rgba(239, 141, 49, 0.2);
429
  }
430
+ #feature-plugin .feature-icon:before {
431
  content: "\f111";
432
  }
433
  #feature-admin_access_restriction .feature-icon:before {
469
  #feature-support .feature-icon:before {
470
  content: "\f525";
471
  }
 
472
  input[type="email"] {
473
  height: 28px;
474
  }
 
475
  .bootstrap-wpadmin .row .shield-free-block {
476
  background-color: rgba(255, 255, 255, 0.7);
477
  border: 1px solid rgba(0, 0, 0, 0.1);
479
  }
480
  .bootstrap-wpadmin .row .shield-free-block p {
481
  margin-bottom: 18px;
482
+ }
483
+ #icwpOptionsTopPill {
484
+ }
485
+ #icwpOptionsTopPill > .nav-pills {
486
+ border-bottom: 1px dashed #999999;
487
+ padding-bottom: 10px;
488
+ }
489
+ #icwpOptionsTopPill > .nav-pills li {
490
+ width: 30.5%;
491
+ }
492
+ #icwpOptionsTopPill > .nav-pills li#icwpWizardPill {
493
+ width: 8%;
494
+ }
495
+ #icwpOptionsTopPill > .nav-pills li#icwpWizardPill .tooltip {
496
+ opacity: 1.0;
497
+ }
498
+ #icwpOptionsTopPill > .nav-pills li#icwpWizardPill .tooltip .tooltip-inner {
499
+ max-width: none;
500
+ font-size: 16px;
501
+ padding: 8px 12px;
502
+ }
503
+ #icwpOptionsTopPill > .nav-pills li#icwpWizardPill a {
504
+ background-size: 100%;
505
+ background-color: #1cbaf3;
506
+ background-repeat: no-repeat;
507
+ background-origin: content-box;
508
+ background-position: 0 4px;
509
+ }
510
+ #icwpOptionsTopPill > .nav-pills li a {
511
+ background-color: rgba(0, 0, 0, 0.2);
512
+ text-shadow: 1px 0 0 rgba(255, 255, 255, 0.4);
513
+ color: #666666;
514
+ height: 50px;
515
+ }
516
+ #icwpOptionsTopPill > .nav-pills li a:hover {
517
+ background-color: rgba(38, 66, 1, 0.3);
518
+ }
519
+ #icwpOptionsTopPill > .nav-pills li a:focus {
520
+ box-shadow: none;
521
+ }
522
+ #icwpOptionsTopPill > .nav-pills li span.dashicons {
523
+ float: left;
524
+ height: 100%;
525
+ font-size: 48px;
526
+ display: block;
527
+ width: 62px;
528
+ }
529
+ #icwpOptionsTopPill > .nav-pills li.active a {
530
+ background-color: rgba(69, 119, 0, 1);
531
+ color: #ffffff;
532
+ text-shadow: 1px 0 0 rgba(0, 0, 0, 0.5);
533
+ }
534
+ #icwpOptionsTopPill > .nav-pills li a .title {
535
+ font-weight: bolder;
536
+ font-size: 18px;
537
+ line-height: 24px;
538
+ }
539
+ #icwpOptionsTopPill > .nav-pills li a .summary {
540
+ font-size: 16px;
541
+ line-height: 28px;
542
+ padding-left: 10px;
543
+ }
544
+ #icwpOptionsTopPill > .nav-pills li a.active {
545
+ }
546
+ #icwpOptionsTopPill > .tab-content {
547
+ background-color: transparent;
548
+ border: 1px solid transparent;
549
+ }
550
+ #icwpOptionsTopPill > .tab-content .content-help {
551
+ background-color: #fafafa;
552
+ padding: 10px 20px;
553
+ box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
554
+ margin: 5px;
555
+ }
556
+ #icwpOptionsTopPill .content-help h2 {
557
+ margin-bottom: 8px;
558
+ }
559
+ #icwpOptionsTopPill .content-help p,
560
+ #icwpOptionsTopPill .content-help li {
561
+ font-size: 14px;
562
+ }
563
+ #icwpOptionsTopPill .content-help dt {
564
+ border-bottom: 1px dotted rgba(0, 0, 0, 0.2);
565
+ font-size: 16px;
566
+ margin-bottom: 7px;
567
+ padding-bottom: 3px;
568
+ }
569
+ #icwpOptionsTopPill .content-help dd {
570
+ margin-bottom: 15px;
571
+ margin-left: 12px;
572
+ }
573
+ .bootstrap-wpadmin .option_section_row .options-body {
574
+ }
575
+ .bootstrap-wpadmin .option_row .item_group {
576
+ margin-left: 0;
577
+ }
578
+
579
+ /* The switch - the box around the slider */
580
+ label.forcheckbox .summary {
581
+ vertical-align: top;
582
+ line-height: 20px;
583
+ margin-left: 7px;
584
+ }
585
+ .switch {
586
+ position: relative;
587
+ display: inline-block;
588
+ width: 40px;
589
+ height: 20px;
590
+ }
591
+ .bootstrap-wpadmin .switch .summary {
592
+ display: block;
593
+ }
594
+ /* Hide default HTML checkbox */
595
+ .bootstrap-wpadmin .switch input {display:none; !important;}
596
+
597
+ /* The slider */
598
+ .slider {
599
+ position: absolute;
600
+ cursor: pointer;
601
+ top: 0;
602
+ left: 0;
603
+ right: 0;
604
+ bottom: 0;
605
+ background-color: #ccc;
606
+ -webkit-transition: .1s;
607
+ transition: .1s;
608
+ }
609
+ .slider:before {
610
+ position: absolute;
611
+ content: "";
612
+ height: 16px;
613
+ width: 16px;
614
+ left: 2px;
615
+ bottom: 2px;
616
+ background-color: white;
617
+ -webkit-transition: .1s;
618
+ transition: .1s;
619
+ }
620
+ input:checked + .slider {
621
+ background-color: rgba(69, 119, 0, 1);
622
+ }
623
+ input:focus + .slider {
624
+ box-shadow: 0 0 1px rgba(69, 119, 0, 1);
625
+ }
626
+ input:checked + .slider:before {
627
+ -webkit-transform: translateX(20px);
628
+ -ms-transform: translateX(20px);
629
+ transform: translateX(20px);
630
+ }
631
+ /* Rounded sliders */
632
+ .slider.round {
633
+ border-radius: 3px;
634
+ }
635
+ .slider.round:before {
636
+ border-radius: 10%;
637
  }
resources/css/wizard.css CHANGED
@@ -47,10 +47,14 @@ body.wait {
47
  .wizard p {
48
  margin-bottom: 20px;
49
  }
 
50
  .wizard .body ul {
51
- list-style: square inside none;
52
  padding-left: 20px;
53
  }
 
 
 
54
  .wizard p.wizard-response {
55
  padding: 10px 15px;
56
  }
@@ -67,4 +71,49 @@ body.wait {
67
  border: 1px solid #888;
68
  height: 64px;
69
  width: 64px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  }
47
  .wizard p {
48
  margin-bottom: 20px;
49
  }
50
+ .wizard .body ol,
51
  .wizard .body ul {
52
+ margin-bottom: 20px;
53
  padding-left: 20px;
54
  }
55
+ .wizard .body ul {
56
+ list-style: square inside none;
57
+ }
58
  .wizard p.wizard-response {
59
  padding: 10px 15px;
60
  }
71
  border: 1px solid #888;
72
  height: 64px;
73
  width: 64px;
74
+ }
75
+ .wizard .indent_slight {
76
+ margin-left: 26px;
77
+ }
78
+
79
+ .wizard_slot {
80
+ border: 1px solid #dddddd;
81
+ border-radius: 3px;
82
+ margin-top: 30px;
83
+ padding: 0 20px 20px;
84
+ }
85
+ .wizard_slot:hover {
86
+ background-color: #ffffff;
87
+ }
88
+
89
+ #GoProBtn {
90
+ width: 128px;
91
+ display: block;
92
+ margin: 5px auto 20px;
93
+ }
94
+
95
+ #FooterWizardBanner {
96
+ position: fixed;
97
+ bottom: 0;
98
+ height: 100px;
99
+ width: 100%;
100
+ }
101
+ #WizardTop {
102
+ height: 40px;
103
+ background-color: #fafafa;
104
+ background: linear-gradient(to top, rgba(250,250,250,0.95), rgba(250,250,250,0.7));
105
+ }
106
+ #WizardBanner {
107
+ height: 100px;
108
+ background-color: #eaffea;
109
+ border-top: 1px solid #bbbbbb;
110
+ padding-top: 10px;
111
+ text-align: center;
112
+ word-break: keep-all;
113
+ white-space: nowrap;
114
+ }
115
+ #WizardBanner p {
116
+ margin: 0;
117
+ line-height: 20px;
118
+ text-align: left;
119
  }
resources/images/banner-1500x500-transparent.png ADDED
Binary file
resources/images/wand.png ADDED
Binary file
resources/js/icwp-options.js CHANGED
@@ -1,5 +1,6 @@
1
  jQuery( document ).ready(
2
  function () {
 
3
 
4
  var $oIcwpOptions = jQuery( 'div#icwp-options-form' );
5
 
1
  jQuery( document ).ready(
2
  function () {
3
+ return;
4
 
5
  var $oIcwpOptions = jQuery( 'div#icwp-options-form' );
6
 
src/common/icwp-data.php CHANGED
@@ -64,6 +64,17 @@ class ICWP_WPSF_DataProcessor extends ICWP_WPSF_Foundation {
64
  return $aArray1;
65
  }
66
 
 
 
 
 
 
 
 
 
 
 
 
67
  /**
68
  * @param string $sKey
69
  * @param null $mDefault
@@ -485,10 +496,10 @@ class ICWP_WPSF_DataProcessor extends ICWP_WPSF_Foundation {
485
  * @return bool
486
  */
487
  public function setCookie( $sKey, $mValue, $nExpireLength = 3600, $sPath = null, $sDomain = null, $bSsl = false ) {
 
488
  if ( function_exists( 'headers_sent' ) && headers_sent() ) {
489
  return false;
490
  }
491
- $_COOKIE[ $sKey ] = $mValue;
492
  return setcookie(
493
  $sKey,
494
  $mValue,
64
  return $aArray1;
65
  }
66
 
67
+ /**
68
+ * @param string $sKey
69
+ * @param null $mDefault
70
+ * @param bool $bTrim -automatically trim whitespace
71
+ * @return mixed|null
72
+ */
73
+ public function cookie( $sKey, $mDefault = null, $bTrim = true ) {
74
+ $mVal = $this->FetchCookie( $sKey, $mDefault );
75
+ return ( $bTrim && is_scalar( $mVal ) ) ? trim( $mVal ) : $mVal;
76
+ }
77
+
78
  /**
79
  * @param string $sKey
80
  * @param null $mDefault
496
  * @return bool
497
  */
498
  public function setCookie( $sKey, $mValue, $nExpireLength = 3600, $sPath = null, $sDomain = null, $bSsl = false ) {
499
+ $_COOKIE[ $sKey ] = $mValue;
500
  if ( function_exists( 'headers_sent' ) && headers_sent() ) {
501
  return false;
502
  }
 
503
  return setcookie(
504
  $sKey,
505
  $mValue,
src/common/icwp-edd.php CHANGED
@@ -44,7 +44,7 @@ class ICWP_WPSF_Edd extends ICWP_WPSF_Foundation {
44
  );
45
 
46
  $mResponse = $this->loadFS()
47
- ->requestUrl( $sStoreUrl, $aParams );
48
 
49
  $sResult = 'Unknown error communicating with license server';
50
  if ( is_array( $mResponse ) && !empty( $mResponse[ 'body' ] ) ) {
@@ -92,7 +92,8 @@ class ICWP_WPSF_Edd extends ICWP_WPSF_Foundation {
92
  'edd_action' => $sAction,
93
  'license' => $sKey,
94
  'item_id' => $sItemId,
95
- 'url' => $this->loadWp()->getWpUrl()
 
96
  )
97
  );
98
 
44
  );
45
 
46
  $mResponse = $this->loadFS()
47
+ ->requestUrl( $sStoreUrl, $aParams, true );
48
 
49
  $sResult = 'Unknown error communicating with license server';
50
  if ( is_array( $mResponse ) && !empty( $mResponse[ 'body' ] ) ) {
92
  'edd_action' => $sAction,
93
  'license' => $sKey,
94
  'item_id' => $sItemId,
95
+ 'url' => $this->loadWp()->getWpUrl(),
96
+ 'home_url' => $this->loadWp()->getHomeUrl()
97
  )
98
  );
99
 
src/common/icwp-foundation.php CHANGED
@@ -254,7 +254,7 @@ class ICWP_WPSF_Foundation {
254
  if ( !empty( $sTemplatePath ) ) {
255
  self::$oRender->setTemplateRoot( $sTemplatePath );
256
  }
257
- return self::$oRender;
258
  }
259
 
260
  /**
254
  if ( !empty( $sTemplatePath ) ) {
255
  self::$oRender->setTemplateRoot( $sTemplatePath );
256
  }
257
+ return ( clone self::$oRender );
258
  }
259
 
260
  /**
src/common/icwp-ip.php CHANGED
@@ -9,14 +9,17 @@ if ( class_exists( 'ICWP_WPSF_Ip', false ) ) {
9
  class ICWP_WPSF_Ip extends ICWP_WPSF_Foundation {
10
 
11
  const IpifyEndpoint = 'https://api.ipify.org';
 
12
  /**
13
  * @var string
14
  */
15
  private $sIp;
 
16
  /**
17
  * @var string
18
  */
19
  private $sMyIp;
 
20
  /**
21
  * @var ICWP_WPSF_Ip
22
  */
@@ -244,6 +247,35 @@ class ICWP_WPSF_Ip extends ICWP_WPSF_Foundation {
244
  return $this->sMyIp;
245
  }
246
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
247
  /**
248
  * @return string|false
249
  */
@@ -261,22 +293,10 @@ class ICWP_WPSF_Ip extends ICWP_WPSF_Foundation {
261
 
262
  $sMyIp = $bRemoteVerify ? $this->whatIsMyIp() : null;
263
 
264
- $aAddressSourceOptions = array(
265
- 'REMOTE_ADDR',
266
- 'HTTP_CF_CONNECTING_IP',
267
- 'HTTP_X_FORWARDED_FOR',
268
- 'HTTP_X_FORWARDED',
269
- 'HTTP_X_REAL_IP',
270
- 'HTTP_X_SUCURI_CLIENTIP',
271
- 'HTTP_INCAP_CLIENT_IP',
272
- 'HTTP_FORWARDED',
273
- 'HTTP_CLIENT_IP'
274
- );
275
-
276
  $sIpToReturn = false;
277
  $sSource = false;
278
- $oDp = $this->loadDataProcessor();
279
- foreach ( $aAddressSourceOptions as $sSource ) {
280
 
281
  $sIpToTest = $oDp->FetchServer( $sSource );
282
  if ( empty( $sIpToTest ) ) {
@@ -300,6 +320,23 @@ class ICWP_WPSF_Ip extends ICWP_WPSF_Foundation {
300
  );
301
  }
302
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
303
  /**
304
  * @return string[]
305
  */
9
  class ICWP_WPSF_Ip extends ICWP_WPSF_Foundation {
10
 
11
  const IpifyEndpoint = 'https://api.ipify.org';
12
+
13
  /**
14
  * @var string
15
  */
16
  private $sIp;
17
+
18
  /**
19
  * @var string
20
  */
21
  private $sMyIp;
22
+
23
  /**
24
  * @var ICWP_WPSF_Ip
25
  */
247
  return $this->sMyIp;
248
  }
249
 
250
+ /**
251
+ * @param string $sVisitorIp
252
+ * @return string
253
+ */
254
+ public function determineSourceFromIp( $sVisitorIp ) {
255
+ $oDp = $this->loadDP();
256
+
257
+ $sBestSource = null;
258
+ foreach ( $this->getIpSourceOptions() as $sSource ) {
259
+
260
+ $sIpToTest = $oDp->FetchServer( $sSource );
261
+ if ( empty( $sIpToTest ) ) {
262
+ continue;
263
+ }
264
+
265
+ // sometimes a comma-separated list is returned
266
+ $aIpAddresses = array_map( 'trim', explode( ',', $sIpToTest ) );
267
+ foreach ( $aIpAddresses as $sIp ) {
268
+
269
+ if ( $sVisitorIp == $sIp ) {
270
+ $sBestSource = $sSource;
271
+ break( 2 );
272
+ }
273
+ }
274
+ }
275
+
276
+ return $sBestSource;
277
+ }
278
+
279
  /**
280
  * @return string|false
281
  */
293
 
294
  $sMyIp = $bRemoteVerify ? $this->whatIsMyIp() : null;
295
 
 
 
 
 
 
 
 
 
 
 
 
 
296
  $sIpToReturn = false;
297
  $sSource = false;
298
+ $oDp = $this->loadDP();
299
+ foreach ( $this->getIpSourceOptions() as $sSource ) {
300
 
301
  $sIpToTest = $oDp->FetchServer( $sSource );
302
  if ( empty( $sIpToTest ) ) {
320
  );
321
  }
322
 
323
+ /**
324
+ * @return string[]
325
+ */
326
+ protected function getIpSourceOptions() {
327
+ return array(
328
+ 'REMOTE_ADDR',
329
+ 'HTTP_CF_CONNECTING_IP',
330
+ 'HTTP_X_FORWARDED_FOR',
331
+ 'HTTP_X_FORWARDED',
332
+ 'HTTP_X_REAL_IP',
333
+ 'HTTP_X_SUCURI_CLIENTIP',
334
+ 'HTTP_INCAP_CLIENT_IP',
335
+ 'HTTP_FORWARDED',
336
+ 'HTTP_CLIENT_IP'
337
+ );
338
+ }
339
+
340
  /**
341
  * @return string[]
342
  */
src/common/icwp-wpfunctions.php CHANGED
@@ -406,10 +406,10 @@ class ICWP_WPSF_WpFunctions extends ICWP_WPSF_Foundation {
406
  public function doRedirect( $sUrl, $aQueryParams = array(), $bSafe = true, $bProtectAgainstInfiniteLoops = true ) {
407
  $sUrl = empty( $aQueryParams ) ? $sUrl : add_query_arg( $aQueryParams, $sUrl );
408
 
409
- $oDp = $this->loadDataProcessor();
410
  // we prevent any repetitive redirect loops
411
  if ( $bProtectAgainstInfiniteLoops ) {
412
- if ( $oDp->FetchCookie( 'icwp-isredirect' ) == 'yes' ) {
413
  return;
414
  }
415
  else {
@@ -420,7 +420,7 @@ class ICWP_WPSF_WpFunctions extends ICWP_WPSF_Foundation {
420
  // based on: https://make.wordpress.org/plugins/2015/04/20/fixing-add_query_arg-and-remove_query_arg-usage/
421
  // we now escape the URL to be absolutely sure since we can't guarantee the URL coming through there
422
  $sUrl = esc_url_raw( $sUrl );
423
- $bSafe ? wp_safe_redirect( $sUrl ) : wp_redirect( $sUrl );
424
  exit();
425
  }
426
 
@@ -735,7 +735,7 @@ class ICWP_WPSF_WpFunctions extends ICWP_WPSF_Foundation {
735
  * @return string
736
  */
737
  public function getTimeStringForDisplay( $nTime = null, $bShowTime = true, $bShowDate = true ) {
738
- $nTime = empty( $nTime ) ? $this->loadDataProcessor()->time() : $nTime;
739
 
740
  $sFullTimeString = $bShowTime ? $this->getTimeFormat() : '';
741
  if ( empty( $sFullTimeString ) ) {
@@ -747,6 +747,15 @@ class ICWP_WPSF_WpFunctions extends ICWP_WPSF_Foundation {
747
  return date_i18n( $sFullTimeString, $this->getTimeAsGmtOffset( $nTime ) );
748
  }
749
 
 
 
 
 
 
 
 
 
 
750
  /**
751
  * @param int $nTime
752
  * @return int
406
  public function doRedirect( $sUrl, $aQueryParams = array(), $bSafe = true, $bProtectAgainstInfiniteLoops = true ) {
407
  $sUrl = empty( $aQueryParams ) ? $sUrl : add_query_arg( $aQueryParams, $sUrl );
408
 
409
+ $oDp = $this->loadDP();
410
  // we prevent any repetitive redirect loops
411
  if ( $bProtectAgainstInfiniteLoops ) {
412
+ if ( $oDp->cookie( 'icwp-isredirect' ) == 'yes' ) {
413
  return;
414
  }
415
  else {
420
  // based on: https://make.wordpress.org/plugins/2015/04/20/fixing-add_query_arg-and-remove_query_arg-usage/
421
  // we now escape the URL to be absolutely sure since we can't guarantee the URL coming through there
422
  $sUrl = esc_url_raw( $sUrl );
423
+ $bSafe ? wp_redirect( $sUrl ) : wp_redirect( $sUrl );
424
  exit();
425
  }
426
 
735
  * @return string
736
  */
737
  public function getTimeStringForDisplay( $nTime = null, $bShowTime = true, $bShowDate = true ) {
738
+ $nTime = empty( $nTime ) ? $this->loadDP()->time() : $nTime;
739
 
740
  $sFullTimeString = $bShowTime ? $this->getTimeFormat() : '';
741
  if ( empty( $sFullTimeString ) ) {
747
  return date_i18n( $sFullTimeString, $this->getTimeAsGmtOffset( $nTime ) );
748
  }
749
 
750
+ /**
751
+ * @param int|null $nTime
752
+ * @return string
753
+ */
754
+ public function getTimeStampForDisplay( $nTime = null ) {
755
+ $nTime = empty( $nTime ) ? $this->loadDP()->time() : $nTime;
756
+ return date_i18n( DATE_RFC2822, $this->getTimeAsGmtOffset( $nTime ) );
757
+ }
758
+
759
  /**
760
  * @param int $nTime
761
  * @return int
src/config/feature-admin_access_restriction.php CHANGED
@@ -5,7 +5,7 @@
5
  "name": "Security Admin",
6
  "show_feature_menu_item": true,
7
  "storage_key": "admin_access_restriction",
8
- "tagline": "Protect your security plugin not just your WordPress site",
9
  "menu_title": "Security Admin",
10
  "show_central": true,
11
  "access_restricted": true,
@@ -207,7 +207,7 @@
207
  ],
208
  "definitions": {
209
  "help_video_id": "214855538",
210
- "admin_access_key_cookie_name": "icwp_wpsf_aakcook",
211
  "admin_access_options_to_restrict": {
212
  "wpms_options": [
213
  "admin_email",
5
  "name": "Security Admin",
6
  "show_feature_menu_item": true,
7
  "storage_key": "admin_access_restriction",
8
+ "tagline": "Protect your Security Plugin, not just your WordPress site",
9
  "menu_title": "Security Admin",
10
  "show_central": true,
11
  "access_restricted": true,
207
  ],
208
  "definitions": {
209
  "help_video_id": "214855538",
210
+ "security_admin_cookie_name": "icwp_wpsf_aakcook",
211
  "admin_access_options_to_restrict": {
212
  "wpms_options": [
213
  "admin_email",
src/config/feature-hack_protect.php CHANGED
@@ -1,233 +1,233 @@
1
  {
2
- "slug": "hack_protect",
3
- "properties": {
4
- "slug": "hack_protect",
5
- "name": "Hack Protection",
6
  "show_feature_menu_item": true,
7
- "storage_key": "hack_protect",
8
- "show_central": true,
9
- "access_restricted": true,
10
- "premium": false,
11
- "order": 70
12
  },
13
- "sections": [
14
  {
15
- "slug": "section_enable_plugin_feature_hack_protection_tools",
16
- "primary": true,
17
- "title": "Enable Plugin Feature: Hack Protection",
18
  "title_short": "Enable / Disable",
19
- "summary": [
20
  "Purpose - The Hack Protection system is a set of tools to warn you and protect you against hacks on your site.",
21
  "Recommendation - Keep the Hack Protection feature turned on."
22
  ]
23
  },
24
  {
25
- "slug": "section_wpvuln_scan",
26
- "title": "Vulnerability Scanner",
27
  "title_short": "Vulnerability Scanner",
28
- "summary": [
29
  "Purpose - Regularly scan your WordPress plugins and themes for known security vulnerabilities.",
30
  "Recommendation - Ensure this is turned on and you will always know if any of your assets have known security vulnerabilities."
31
  ]
32
  },
33
  {
34
- "slug": "section_core_file_integrity_scan",
35
- "title": "Core File Integrity Scanner",
36
  "title_short": "Core File Scanner",
37
- "summary": [
38
  "Purpose - Regularly scan your WordPress core files for changes compared to official WordPress files.",
39
  "Recommendation - Keep the Core File Integrity Scanner feature turned on."
40
  ]
41
  },
42
  {
43
- "slug": "section_unrecognised_file_scan",
44
- "title": "Unrecognised Files Scanner",
45
  "title_short": "Unrecognised Files Scanner",
46
- "summary": [
47
  "Purpose - Scan your WordPress core folders for unrecognised files that don't belong.",
48
  "Recommendation - Keep the Unrecognised Files Scanner feature turned on."
49
  ]
50
  },
51
  {
52
- "slug": "section_non_ui",
53
  "hidden": true
54
  }
55
  ],
56
- "options": [
57
  {
58
- "key": "enable_hack_protect",
59
- "section": "section_enable_plugin_feature_hack_protection_tools",
60
- "default": "Y",
61
- "type": "checkbox",
62
- "link_info": "http://icwp.io/wpsf38",
63
- "link_blog": "http://icwp.io/9x",
64
- "name": "Enable Hack Protection",
65
- "summary": "Enable (or Disable) The Hack Protection Feature",
66
  "description": "Checking/Un-Checking this option will completely turn on/off the whole Hack Protection feature"
67
  },
68
  {
69
- "key": "enable_wpvuln_scan",
70
- "section": "section_wpvuln_scan",
71
- "premium": true,
72
- "default": "enabled_email",
73
- "type": "select",
74
  "value_options": [
75
  {
76
  "value_key": "disabled",
77
- "text": "Scan Disabled"
78
  },
79
  {
80
  "value_key": "enabled_email",
81
- "text": "Enabled - Send Email Notification"
82
  },
83
  {
84
  "value_key": "enabled_no_email",
85
- "text": "Enabled - No Email Notification"
86
  }
87
  ],
88
- "link_info": "http://icwp.io/ah",
89
- "link_blog": "",
90
- "name": "Vulnerability Scanner",
91
- "summary": "Enable The Vulnerability Scanner",
92
- "description": "Scan all your WordPress assets for known security vulnerabilities."
93
  },
94
  {
95
- "key": "wpvuln_scan_autoupdate",
96
- "section": "section_wpvuln_scan",
97
- "premium": true,
98
- "default": "N",
99
- "type": "checkbox",
100
- "link_info": "",
101
- "link_blog": "",
102
- "name": "Automatic Updates",
103
- "summary": "Apply Updates Automatically To Vulnerable Plugins",
104
  "description": "When an update becomes available, automatically apply updates to items with known vulnerabilities."
105
  },
106
  {
107
- "key": "wpvuln_scan_display",
108
- "section": "section_wpvuln_scan",
109
- "default": "enabled_admin",
110
- "type": "select",
111
  "value_options": [
112
  {
113
  "value_key": "disabled",
114
- "text": "Display Disabled"
115
  },
116
  {
117
  "value_key": "enabled_admin",
118
- "text": "Display Enabled"
119
  },
120
  {
121
  "value_key": "enabled_securityadmin",
122
- "text": "Display Only For Security Admins"
123
  }
124
  ],
125
- "link_info": "",
126
- "link_blog": "",
127
- "name": "Highlight Plugins",
128
- "summary": "Highlight Vulnerable Plugins",
129
- "description": "Vulnerable plugins will be highlighted on the main plugins page."
130
  },
131
  {
132
- "key": "enable_core_file_integrity_scan",
133
- "section": "section_core_file_integrity_scan",
134
- "default": "Y",
135
- "type": "checkbox",
136
- "link_info": "http://icwp.io/wpsf36",
137
- "link_blog": "http://icwp.io/wpsf37",
138
- "name": "Core File Scanner",
139
- "summary": "Daily Cron - Scans WordPress Core Files For Alterations",
140
  "description": "Compares all WordPress core files on your site against the official WordPress files. WordPress Core files should never be altered for any reason."
141
  },
142
  {
143
- "key": "attempt_auto_file_repair",
144
- "section": "section_core_file_integrity_scan",
145
- "default": "N",
146
- "type": "checkbox",
147
- "link_info": "http://icwp.io/wpsf36",
148
- "link_blog": "http://icwp.io/wpsf37",
149
- "name": "Auto Repair",
150
- "summary": "Automatically Repair WordPress Core Files That Have Been Altered",
151
  "description": "Attempts to automatically repair WordPress Core files with the official WordPress file data, for files that have been altered or are missing."
152
  },
153
  {
154
- "key": "enable_unrecognised_file_cleaner_scan",
155
- "section": "section_unrecognised_file_scan",
156
- "default": "enabled_report_only",
157
- "type": "select",
158
  "value_options": [
159
  {
160
  "value_key": "disabled",
161
- "text": "Scan Disabled"
162
  },
163
  {
164
  "value_key": "enabled_report_only",
165
- "text": "Email Report Only"
166
  },
167
  {
168
  "value_key": "enabled_delete_only",
169
- "text": "Automatically Delete Files"
170
  },
171
  {
172
  "value_key": "enabled_delete_report",
173
- "text": "Auto Delete Files and Email Report"
174
  }
175
  ],
176
- "link_info": "http://icwp.io/9y",
177
- "link_blog": "http://icwp.io/95",
178
- "name": "Unrecognised Files Scanner",
179
- "summary": "Scans Core Directories For Unrecognised Files",
180
- "description": "Scans for, and automatically deletes, any files in your core WordPress folders that are not part of your WordPress installation."
181
  },
182
  {
183
- "key": "ufc_scan_uploads",
184
- "section": "section_unrecognised_file_scan",
185
- "default": "N",
186
- "type": "checkbox",
187
- "link_info": "http://icwp.io/95",
188
- "link_blog": "",
189
- "name": "Scan Uploads",
190
- "summary": "Scan Uploads Folder For PHP and Javascript",
191
  "description": "The Uploads folder is primarily for media, but could be used to store nefarious files."
192
  },
193
  {
194
- "key": "ufc_exclusions",
195
- "section": "section_unrecognised_file_scan",
196
- "default": [
197
- "error_log",
198
- ".htaccess",
199
- ".htpasswd",
200
- ".user.ini",
201
- "php.ini",
202
- "web.config",
203
- "php_mail.log",
204
- "mail.log"
205
  ],
206
- "type": "array",
207
- "link_info": "http://icwp.io/9z",
208
- "link_blog": "http://icwp.io/95",
209
- "name": "File Exclusions",
210
- "summary": "Provide A List Of Files To Be Excluded From The Scan",
211
  "description": "Take a new line for each file you wish to exclude from the scan. No commas are necessary."
212
  },
213
  {
214
- "key": "wpvuln_notified_ids",
215
  "transferable": false,
216
- "section": "section_non_ui",
217
- "default": []
218
  }
219
  ],
220
  "definitions": {
221
- "plugin_vulnerabilities_data_source": "https://raw.githubusercontent.com/FernleafSystems/wp-plugin-vulnerabilities/master/vulnerabilities.yaml",
222
- "notifications_cron_name": "plugin-vulnerabilities-notification",
223
- "wpvulnscan_cron_name": "wpvulnscan-notification",
224
- "corechecksum_cron_name": "core-checksum-notification",
225
- "unrecognisedscan_cron_name": "unrecognised-scan-notification",
226
- "url_checksum_api": "https://api.wordpress.org/core/checksums/1.0/",
227
- "url_wordress_core_svn": "https://core.svn.wordpress.org/",
228
- "url_wordress_core_svn_il8n": "https://svn.automattic.com/wordpress-i18n/",
229
- "wpvulndb_api_url_root": "https://wpvulndb.com/api/v2/",
230
- "corechecksum_exclusions": [
231
  "readme.html",
232
  "license.txt",
233
  "licens-sv_SE.txt",
@@ -238,10 +238,57 @@
238
  "wp-admin/install.php",
239
  "xmlrpc.php"
240
  ],
241
- "corechecksum_autofix": [
242
  "wp-content/index.php",
243
  "wp-content/plugins/index.php",
244
  "wp-content/themes/index.php"
245
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246
  }
247
  }
1
  {
2
+ "slug": "hack_protect",
3
+ "properties": {
4
+ "slug": "hack_protect",
5
+ "name": "Hack Protection",
6
  "show_feature_menu_item": true,
7
+ "storage_key": "hack_protect",
8
+ "show_central": true,
9
+ "access_restricted": true,
10
+ "premium": false,
11
+ "order": 70
12
  },
13
+ "sections": [
14
  {
15
+ "slug": "section_enable_plugin_feature_hack_protection_tools",
16
+ "primary": true,
17
+ "title": "Enable Plugin Feature: Hack Protection",
18
  "title_short": "Enable / Disable",
19
+ "summary": [
20
  "Purpose - The Hack Protection system is a set of tools to warn you and protect you against hacks on your site.",
21
  "Recommendation - Keep the Hack Protection feature turned on."
22
  ]
23
  },
24
  {
25
+ "slug": "section_wpvuln_scan",
26
+ "title": "Vulnerability Scanner",
27
  "title_short": "Vulnerability Scanner",
28
+ "summary": [
29
  "Purpose - Regularly scan your WordPress plugins and themes for known security vulnerabilities.",
30
  "Recommendation - Ensure this is turned on and you will always know if any of your assets have known security vulnerabilities."
31
  ]
32
  },
33
  {
34
+ "slug": "section_core_file_integrity_scan",
35
+ "title": "Core File Integrity Scanner",
36
  "title_short": "Core File Scanner",
37
+ "summary": [
38
  "Purpose - Regularly scan your WordPress core files for changes compared to official WordPress files.",
39
  "Recommendation - Keep the Core File Integrity Scanner feature turned on."
40
  ]
41
  },
42
  {
43
+ "slug": "section_unrecognised_file_scan",
44
+ "title": "Unrecognised Files Scanner",
45
  "title_short": "Unrecognised Files Scanner",
46
+ "summary": [
47
  "Purpose - Scan your WordPress core folders for unrecognised files that don't belong.",
48
  "Recommendation - Keep the Unrecognised Files Scanner feature turned on."
49
  ]
50
  },
51
  {
52
+ "slug": "section_non_ui",
53
  "hidden": true
54
  }
55
  ],
56
+ "options": [
57
  {
58
+ "key": "enable_hack_protect",
59
+ "section": "section_enable_plugin_feature_hack_protection_tools",
60
+ "default": "Y",
61
+ "type": "checkbox",
62
+ "link_info": "http://icwp.io/wpsf38",
63
+ "link_blog": "http://icwp.io/9x",
64
+ "name": "Enable Hack Protection",
65
+ "summary": "Enable (or Disable) The Hack Protection Feature",
66
  "description": "Checking/Un-Checking this option will completely turn on/off the whole Hack Protection feature"
67
  },
68
  {
69
+ "key": "enable_wpvuln_scan",
70
+ "section": "section_wpvuln_scan",
71
+ "premium": true,
72
+ "default": "enabled_email",
73
+ "type": "select",
74
  "value_options": [
75
  {
76
  "value_key": "disabled",
77
+ "text": "Scan Disabled"
78
  },
79
  {
80
  "value_key": "enabled_email",
81
+ "text": "Enabled - Send Email Notification"
82
  },
83
  {
84
  "value_key": "enabled_no_email",
85
+ "text": "Enabled - No Email Notification"
86
  }
87
  ],
88
+ "link_info": "http://icwp.io/ah",
89
+ "link_blog": "",
90
+ "name": "Vulnerability Scanner",
91
+ "summary": "Enable The Vulnerability Scanner",
92
+ "description": "Scan all your WordPress assets for known security vulnerabilities."
93
  },
94
  {
95
+ "key": "wpvuln_scan_autoupdate",
96
+ "section": "section_wpvuln_scan",
97
+ "premium": true,
98
+ "default": "N",
99
+ "type": "checkbox",
100
+ "link_info": "",
101
+ "link_blog": "",
102
+ "name": "Automatic Updates",
103
+ "summary": "Apply Updates Automatically To Vulnerable Plugins",
104
  "description": "When an update becomes available, automatically apply updates to items with known vulnerabilities."
105
  },
106
  {
107
+ "key": "wpvuln_scan_display",
108
+ "section": "section_wpvuln_scan",
109
+ "default": "enabled_admin",
110
+ "type": "select",
111
  "value_options": [
112
  {
113
  "value_key": "disabled",
114
+ "text": "Display Disabled"
115
  },
116
  {
117
  "value_key": "enabled_admin",
118
+ "text": "Display Enabled"
119
  },
120
  {
121
  "value_key": "enabled_securityadmin",
122
+ "text": "Display Only For Security Admins"
123
  }
124
  ],
125
+ "link_info": "",
126
+ "link_blog": "",
127
+ "name": "Highlight Plugins",
128
+ "summary": "Highlight Vulnerable Plugins",
129
+ "description": "Vulnerable plugins will be highlighted on the main plugins page."
130
  },
131
  {
132
+ "key": "enable_core_file_integrity_scan",
133
+ "section": "section_core_file_integrity_scan",
134
+ "default": "Y",
135
+ "type": "checkbox",
136
+ "link_info": "http://icwp.io/wpsf36",
137
+ "link_blog": "http://icwp.io/wpsf37",
138
+ "name": "Core File Scanner",
139
+ "summary": "Daily Cron - Scans WordPress Core Files For Alterations",
140
  "description": "Compares all WordPress core files on your site against the official WordPress files. WordPress Core files should never be altered for any reason."
141
  },
142
  {
143
+ "key": "attempt_auto_file_repair",
144
+ "section": "section_core_file_integrity_scan",
145
+ "default": "N",
146
+ "type": "checkbox",
147
+ "link_info": "http://icwp.io/wpsf36",
148
+ "link_blog": "http://icwp.io/wpsf37",
149
+ "name": "Auto Repair",
150
+ "summary": "Automatically Repair WordPress Core Files That Have Been Altered",
151
  "description": "Attempts to automatically repair WordPress Core files with the official WordPress file data, for files that have been altered or are missing."
152
  },
153
  {
154
+ "key": "enable_unrecognised_file_cleaner_scan",
155
+ "section": "section_unrecognised_file_scan",
156
+ "default": "enabled_report_only",
157
+ "type": "select",
158
  "value_options": [
159
  {
160
  "value_key": "disabled",
161
+ "text": "Scan Disabled"
162
  },
163
  {
164
  "value_key": "enabled_report_only",
165
+ "text": "Email Report Only"
166
  },
167
  {
168
  "value_key": "enabled_delete_only",
169
+ "text": "Automatically Delete Files"
170
  },
171
  {
172
  "value_key": "enabled_delete_report",
173
+ "text": "Auto Delete Files and Email Report"
174
  }
175
  ],
176
+ "link_info": "http://icwp.io/9y",
177
+ "link_blog": "http://icwp.io/95",
178
+ "name": "Unrecognised Files Scanner",
179
+ "summary": "Scans Core Directories For Unrecognised Files",
180
+ "description": "Scans for, and automatically deletes, any files in your core WordPress folders that are not part of your WordPress installation."
181
  },
182
  {
183
+ "key": "ufc_scan_uploads",
184
+ "section": "section_unrecognised_file_scan",
185
+ "default": "N",
186
+ "type": "checkbox",
187
+ "link_info": "http://icwp.io/95",
188
+ "link_blog": "",
189
+ "name": "Scan Uploads",
190
+ "summary": "Scan Uploads Folder For PHP and Javascript",
191
  "description": "The Uploads folder is primarily for media, but could be used to store nefarious files."
192
  },
193
  {
194
+ "key": "ufc_exclusions",
195
+ "section": "section_unrecognised_file_scan",
196
+ "default": [
197
+ "error_log",
198
+ ".htaccess",
199
+ ".htpasswd",
200
+ ".user.ini",
201
+ "php.ini",
202
+ "web.config",
203
+ "php_mail.log",
204
+ "mail.log"
205
  ],
206
+ "type": "array",
207
+ "link_info": "http://icwp.io/9z",
208
+ "link_blog": "http://icwp.io/95",
209
+ "name": "File Exclusions",
210
+ "summary": "Provide A List Of Files To Be Excluded From The Scan",
211
  "description": "Take a new line for each file you wish to exclude from the scan. No commas are necessary."
212
  },
213
  {
214
+ "key": "wpvuln_notified_ids",
215
  "transferable": false,
216
+ "section": "section_non_ui",
217
+ "default": []
218
  }
219
  ],
220
  "definitions": {
221
+ "plugin_vulnerabilities_data_source": "https://raw.githubusercontent.com/FernleafSystems/wp-plugin-vulnerabilities/master/vulnerabilities.yaml",
222
+ "notifications_cron_name": "plugin-vulnerabilities-notification",
223
+ "wpvulnscan_cron_name": "wpvulnscan-notification",
224
+ "corechecksum_cron_name": "core-checksum-notification",
225
+ "unrecognisedscan_cron_name": "unrecognised-scan-notification",
226
+ "url_checksum_api": "https://api.wordpress.org/core/checksums/1.0/",
227
+ "url_wordress_core_svn": "https://core.svn.wordpress.org/",
228
+ "url_wordress_core_svn_il8n": "https://svn.automattic.com/wordpress-i18n/",
229
+ "wpvulndb_api_url_root": "https://wpvulndb.com/api/v2/",
230
+ "corechecksum_exclusions": [
231
  "readme.html",
232
  "license.txt",
233
  "licens-sv_SE.txt",
238
  "wp-admin/install.php",
239
  "xmlrpc.php"
240
  ],
241
+ "corechecksum_autofix": [
242
  "wp-content/index.php",
243
  "wp-content/plugins/index.php",
244
  "wp-content/themes/index.php"
245
+ ],
246
+ "wizards": {
247
+ "ufc": {
248
+ "title": "Manually Run Unrecognised File Scanner",
249
+ "desc": "Walks you through the scanning for unrecognised files present in your WordPress core installation.",
250
+ "min_user_permissions": "manage_options",
251
+ "steps": {
252
+ "start": {
253
+ "security_admin": false,
254
+ "title": "Start: Unrecognised File Scanner"
255
+ },
256
+ "exclusions": {
257
+ "title": "Exclude Files"
258
+ },
259
+ "scanresult": {
260
+ "title": "Scan Results"
261
+ },
262
+ "config": {
263
+ "title": "Setup Scan Automation"
264
+ },
265
+ "finished": {
266
+ "security_admin": false,
267
+ "title": "Finished: Unrecognised File Scanner"
268
+ }
269
+ }
270
+ },
271
+ "wcf": {
272
+ "title": "Manually Run WordPress Core File Scanner",
273
+ "desc": "Walks you through the scanning for unintended changes to your official WordPress core files.",
274
+ "min_user_permissions": "manage_options",
275
+ "steps": {
276
+ "start": {
277
+ "security_admin": false,
278
+ "title": "Start: WordPress Core File Scanner"
279
+ },
280
+ "scanresult": {
281
+ "title": "Scan Results"
282
+ },
283
+ "config": {
284
+ "title": "Setup Scan Automation"
285
+ },
286
+ "finished": {
287
+ "security_admin": false,
288
+ "title": "Finished: WordPress Core File Scanner"
289
+ }
290
+ }
291
+ }
292
+ }
293
  }
294
  }
src/config/feature-login_protect.php CHANGED
@@ -1,181 +1,181 @@
1
  {
2
- "slug": "login_protect",
3
- "properties": {
4
- "slug": "login_protect",
5
- "name": "Login Protection",
6
  "show_feature_menu_item": true,
7
- "storage_key": "loginprotect",
8
- "tagline": "Block brute force attacks and secure user identities with Two-Factor Authentication",
9
- "show_central": true,
10
- "access_restricted": true,
11
- "premium": false,
12
- "order": 40
13
  },
14
  "admin_notices": {
15
  "email-verification-sent": {
16
- "once": false,
17
  "valid_admin": true,
18
- "type": "warning"
19
  }
20
  },
21
- "sections": [
22
  {
23
- "slug": "section_enable_plugin_feature_login_protection",
24
- "primary": true,
25
- "title": "Enable Plugin Feature: Login Protection",
26
  "title_short": "Enable / Disable",
27
- "summary": [
28
  "Purpose - Login Protection blocks all automated and brute force attempts to log in to your site.",
29
  "Recommendation - Keep the Login Protection feature turned on."
30
  ]
31
  },
32
  {
33
- "slug": "section_brute_force_login_protection",
34
- "title": "Brute Force Login Protection",
35
  "title_short": "Brute Force",
36
- "summary": [
37
  "Purpose - Blocks brute force hacking attacks against your login and registration pages.",
38
  "Recommendation - Use of this feature is highly recommend."
39
  ]
40
  },
41
  {
42
- "slug": "section_recaptcha",
43
- "title": "Google reCAPTCHA",
44
  "title_short": "reCAPTCHA",
45
- "summary": [
46
  "Purpose - Adds Google reCAPTCHA to the Login Forms.",
47
  "Recommendation - Keep this turned on.",
48
  "Note - You will need to register for Google reCAPTCHA keys and store them in the Shield 'Dashboard' settings."
49
  ]
50
  },
51
  {
52
- "slug": "section_multifactor_authentication",
53
- "title": "Multi-Factor Authentication",
54
  "title_short": "2-Factor Auth",
55
- "summary": [
56
  "Purpose - Verifies the identity of users who log in to your site - i.e. they are who they say they are.",
57
  "Recommendation - Use of this feature is highly recommend. However, if your host blocks email sending you may lock yourself out.",
58
  "Note: You may combine multiple authentication factors for increased security."
59
  ]
60
  },
61
  {
62
- "slug": "section_rename_wplogin",
63
- "title": "Rename WP Login Page",
64
  "title_short": "Rename wp-login.php",
65
- "summary": [
66
  "Purpose - To hide your wp-login.php page from brute force attacks and hacking attempts - if your login page cannot be found, no-one can login.",
67
  "Recommendation - This is not required for complete security and if your site has irregular or inconsistent configuration it may not work for you."
68
  ]
69
  },
70
  {
71
- "slug": "section_yubikey_authentication",
72
- "title": "Yubikey Authentication",
73
  "title_short": "Yubikey",
74
- "summary": [
75
  "Purpose - Verifies the identity of users who log in to your site - i.e. they are who they say they are.",
76
  "Recommendation - Use of this feature is highly recommend. Note: you must own the appropriate Yubikey hardware device."
77
  ]
78
  },
79
  {
80
- "slug": "section_user_messages",
81
- "title": "User Messages",
82
  "title_short": "User Messages",
83
- "summary": [
84
  "Purpose - Customize the messages shown to visitors.",
85
  "Recommendation - Be sure to change the messages to suit your audience.",
86
  "Hint - To reset any message to its default, enter the text exactly: default"
87
  ]
88
  },
89
  {
90
- "slug": "section_non_ui",
91
  "hidden": true
92
  }
93
  ],
94
- "options": [
95
  {
96
- "key": "enable_login_protect",
97
- "section": "section_enable_plugin_feature_login_protection",
98
- "default": "N",
99
- "type": "checkbox",
100
- "link_info": "http://icwp.io/51",
101
- "link_blog": "http://icwp.io/wpsf03",
102
- "name": "Enable Login Protection",
103
- "summary": "Enable (or Disable) The Login Protection Feature",
104
  "description": "Checking/Un-Checking this option will completely turn on/off the whole Login Protection feature"
105
  },
106
  {
107
- "key": "login_protect_3pty",
108
- "section": "section_enable_plugin_feature_login_protection",
109
- "premium": true,
110
- "default": "N",
111
- "type": "checkbox",
112
- "link_info": "",
113
- "link_blog": "",
114
- "name": "3rd-Party Support",
115
- "summary": "Support For 3rd-Party Plugins, e.g. WooCommerce",
116
  "description": "Add Support For 3rd-Party Login, Register, and Password Reset Forms e.g. WooCommerce, Easy Digital Downloads."
117
  },
118
  {
119
- "key": "enable_xmlrpc_compatibility",
120
- "section": "section_enable_plugin_feature_login_protection",
121
- "default": "Y",
122
- "type": "checkbox",
123
- "link_info": "http://icwp.io/9u",
124
- "link_blog": "",
125
- "name": "XML-RPC Compatibility",
126
- "summary": "Allow Login Through XML-RPC To By-Pass Login Protection Rules",
127
  "description": "Enable this if you need XML-RPC functionality e.g. if you use the WordPress iPhone/Android App."
128
  },
129
  {
130
- "key": "rename_wplogin_path",
131
- "section": "section_rename_wplogin",
132
- "sensitive": true,
133
- "default": "",
134
- "type": "text",
135
- "link_info": "http://icwp.io/5q",
136
- "link_blog": "http://icwp.io/5r",
137
- "name": "Rename WP Login",
138
- "summary": "Rename The WordPress Login Page",
139
  "description": "Creating a path here will disable your 'wp-login.php'. Only letters and numbers are permitted: abc123"
140
  },
141
  {
142
- "key": "enable_chained_authentication",
143
- "section": "section_multifactor_authentication",
144
- "default": "N",
145
- "type": "checkbox",
146
- "link_info": "http://icwp.io/9r",
147
- "link_blog": "http://icwp.io/84",
148
- "name": "Multi-Factor Authentication",
149
- "summary": "Require All Active Authentication Factors",
150
  "description": "When enabled, all multi-factor authentication methods will be applied to a user login. Disable to only require one to pass."
151
  },
152
  {
153
- "key": "enable_google_authenticator",
154
- "section": "section_multifactor_authentication",
155
- "default": "N",
156
- "type": "checkbox",
157
- "link_info": "http://icwp.io/shld7",
158
- "link_blog": "http://icwp.io/shld6",
159
- "name": "Enable Google Authenticator",
160
- "summary": "Allow Users To Use Google Authenticator",
161
  "description": "When enabled, users will have the option to add Google Authenticator to their WordPress user profile."
162
  },
163
  {
164
- "key": "enable_email_authentication",
165
- "section": "section_multifactor_authentication",
166
- "default": "N",
167
- "type": "checkbox",
168
- "link_info": "http://icwp.io/3t",
169
- "link_blog": "http://icwp.io/9q",
170
- "name": "Enable Email Authentication",
171
- "summary": "Two-Factor Login Authentication By Email",
172
  "description": "All users will be required to verify their login by email-based two-factor authentication."
173
  },
174
  {
175
- "key": "two_factor_auth_user_roles",
176
- "section": "section_multifactor_authentication",
177
- "type": "multiple_select",
178
- "default": [
179
  1,
180
  2,
181
  3,
@@ -184,197 +184,197 @@
184
  "value_options": [
185
  {
186
  "value_key": 0,
187
- "text": "Subscribers"
188
  },
189
  {
190
  "value_key": 1,
191
- "text": "Contributors"
192
  },
193
  {
194
  "value_key": 2,
195
- "text": "Authors"
196
  },
197
  {
198
  "value_key": 3,
199
- "text": "Editors"
200
  },
201
  {
202
  "value_key": 8,
203
- "text": "Administrators"
204
  }
205
  ],
206
- "link_info": "http://icwp.io/4v",
207
- "link_blog": "",
208
- "name": "Enforce - Email Authentication",
209
- "summary": "All User Roles Subject To Email Authentication",
210
- "description": "Enforces email-based authentication on all users with the selected roles. Note: This setting only applies to email authentication."
211
  },
212
  {
213
- "key": "enable_google_recaptcha_login",
214
- "section": "section_recaptcha",
215
- "default": "N",
216
- "type": "checkbox",
217
- "link_info": "http://icwp.io/9m",
218
- "link_blog": "http://icwp.io/shld5",
219
- "name": "Google reCAPTCHA",
220
- "summary": "Enable Google reCAPTCHA",
221
  "description": "Use Google reCAPTCHA on the login screen."
222
  },
223
  {
224
- "key": "google_recaptcha_style_login",
225
- "section": "section_recaptcha",
226
- "premium": true,
227
- "default": "default",
228
- "type": "select",
229
  "value_options": [
230
  {
231
  "value_key": "default",
232
- "text": "Default"
233
  },
234
  {
235
  "value_key": "light",
236
- "text": "Light Theme"
237
  },
238
  {
239
  "value_key": "dark",
240
- "text": "Dark Theme"
241
  },
242
  {
243
  "value_key": "invisible",
244
- "text": "Invisible reCAPTCHA"
245
  }
246
  ],
247
- "link_info": "",
248
- "link_blog": "",
249
- "name": "reCAPTCHA Style",
250
- "summary": "How Google reCAPTCHA Will Be Displayed",
251
- "description": "You can choose the reCAPTCHA display format that best suits your site, including the new Invisible Recaptcha."
252
  },
253
  {
254
- "key": "enable_login_gasp_check",
255
- "section": "section_brute_force_login_protection",
256
- "default": "Y",
257
- "type": "checkbox",
258
- "link_info": "http://icwp.io/3r",
259
- "link_blog": "http://icwp.io/9n",
260
- "name": "G.A.S.P Protection",
261
- "summary": "Use G.A.S.P. Protection To Prevent Login Attempts By Bots",
262
  "description": "Adds a dynamically (Javascript) generated checkbox to the login form that prevents bots using automated login techniques. Recommended: ON."
263
  },
264
  {
265
- "key": "login_limit_interval",
266
- "section": "section_brute_force_login_protection",
267
- "default": "10",
268
- "type": "integer",
269
- "link_info": "http://icwp.io/3q",
270
- "link_blog": "http://icwp.io/9o",
271
- "name": "Login Cooldown Interval",
272
- "summary": "Limit login attempts to every X seconds",
273
  "description": "WordPress will process only ONE login attempt for every number of seconds specified. Zero (0) turns this off."
274
  },
275
  {
276
- "key": "enable_user_register_checking",
277
- "section": "section_brute_force_login_protection",
278
- "default": "Y",
279
- "type": "checkbox",
280
- "link_info": "http://icwp.io/9p",
281
- "link_blog": "",
282
- "name": "User Registration",
283
- "summary": "Apply Brute Force Protection To User Registration And Lost Passwords",
284
  "description": "When enabled, settings in this section will also apply to new user registration and users trying to reset passwords."
285
  },
286
  {
287
- "key": "enable_yubikey",
288
- "section": "section_yubikey_authentication",
289
- "default": "N",
290
- "type": "checkbox",
291
- "link_info": "http://icwp.io/4f",
292
- "link_blog": "http://icwp.io/9t",
293
- "name": "Enable Yubikey Authentication",
294
- "summary": "Turn On / Off Yubikey Authentication On This Site",
295
  "description": "Combined with your Yubikey API Key (below) this will form the basis of your Yubikey Authentication."
296
  },
297
  {
298
- "key": "yubikey_app_id",
299
- "section": "section_yubikey_authentication",
300
- "sensitive": true,
301
- "default": "",
302
- "type": "text",
303
- "link_info": "http://icwp.io/4g",
304
- "link_blog": "",
305
- "name": "Yubikey App ID",
306
- "summary": "Your Unique Yubikey App ID",
307
  "description": "Combined with your Yubikey API Key this will form the basis of your Yubikey Authentication."
308
  },
309
  {
310
- "key": "yubikey_api_key",
311
- "section": "section_yubikey_authentication",
312
- "sensitive": true,
313
- "default": "",
314
- "type": "text",
315
- "link_info": "http://icwp.io/4g",
316
- "link_blog": "",
317
- "name": "Yubikey API Key",
318
- "summary": "Your Unique Yubikey App API Key",
319
  "description": "Combined with your Yubikey App ID this will form the basis of your Yubikey Authentication."
320
  },
321
  {
322
- "key": "text_imahuman",
323
- "section": "section_user_messages",
324
- "premium": true,
325
- "default": "default",
326
- "type": "text",
327
- "link_info": "",
328
- "link_blog": "",
329
- "name": "GASP Checkbox Text",
330
- "summary": "The Message Displayed Next To The GASP Checkbox",
331
- "description": "You can change the text displayed to the user beside the checkbox if you need a customized message."
332
- },
333
- {
334
- "key": "text_pleasecheckbox",
335
- "section": "section_user_messages",
336
- "premium": true,
337
- "default": "default",
338
- "type": "text",
339
- "link_info": "",
340
- "link_blog": "",
341
- "name": "GASP Alert Text",
342
- "summary": "The Message Displayed If The User Doesn't Check The Box",
343
- "description": "You can change the text displayed to the user in the alert message if they don't check the box."
344
- },
345
  {
346
- "key": "email_can_send_verified_at",
347
  "transferable": false,
348
- "section": "section_non_ui",
349
- "default": -1
350
  },
351
  {
352
- "key": "gasp_key",
353
  "transferable": false,
354
- "sensitive": true,
355
- "section": "section_non_ui"
356
  },
357
  {
358
- "key": "two_factor_secret_key",
359
  "transferable": false,
360
- "sensitive": true,
361
- "section": "section_non_ui"
362
  },
363
  {
364
- "key": "two_factor_auth_table_created",
365
  "transferable": false,
366
- "section": "section_non_ui"
367
  },
368
  {
369
- "key": "use_login_intent_page",
370
  "transferable": false,
371
- "value": true,
372
- "section": "section_non_ui"
373
  }
374
  ],
375
- "definitions": {
376
- "login_intent_timeout": 5,
377
- "two_factor_auth_table_name": "login_auth",
378
  "two_factor_auth_table_columns": [
379
  "id",
380
  "session_id",
@@ -384,6 +384,32 @@
384
  "expired_at",
385
  "created_at",
386
  "deleted_at"
387
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
388
  }
389
  }
1
  {
2
+ "slug": "login_protect",
3
+ "properties": {
4
+ "slug": "login_protect",
5
+ "name": "Login Protection",
6
  "show_feature_menu_item": true,
7
+ "storage_key": "loginprotect",
8
+ "tagline": "Block brute force attacks and secure user identities with Two-Factor Authentication",
9
+ "show_central": true,
10
+ "access_restricted": true,
11
+ "premium": false,
12
+ "order": 40
13
  },
14
  "admin_notices": {
15
  "email-verification-sent": {
16
+ "once": false,
17
  "valid_admin": true,
18
+ "type": "warning"
19
  }
20
  },
21
+ "sections": [
22
  {
23
+ "slug": "section_enable_plugin_feature_login_protection",
24
+ "primary": true,
25
+ "title": "Enable Plugin Feature: Login Protection",
26
  "title_short": "Enable / Disable",
27
+ "summary": [
28
  "Purpose - Login Protection blocks all automated and brute force attempts to log in to your site.",
29
  "Recommendation - Keep the Login Protection feature turned on."
30
  ]
31
  },
32
  {
33
+ "slug": "section_brute_force_login_protection",
34
+ "title": "Brute Force Login Protection",
35
  "title_short": "Brute Force",
36
+ "summary": [
37
  "Purpose - Blocks brute force hacking attacks against your login and registration pages.",
38
  "Recommendation - Use of this feature is highly recommend."
39
  ]
40
  },
41
  {
42
+ "slug": "section_recaptcha",
43
+ "title": "Google reCAPTCHA",
44
  "title_short": "reCAPTCHA",
45
+ "summary": [
46
  "Purpose - Adds Google reCAPTCHA to the Login Forms.",
47
  "Recommendation - Keep this turned on.",
48
  "Note - You will need to register for Google reCAPTCHA keys and store them in the Shield 'Dashboard' settings."
49
  ]
50
  },
51
  {
52
+ "slug": "section_multifactor_authentication",
53
+ "title": "Multi-Factor Authentication",
54
  "title_short": "2-Factor Auth",
55
+ "summary": [
56
  "Purpose - Verifies the identity of users who log in to your site - i.e. they are who they say they are.",
57
  "Recommendation - Use of this feature is highly recommend. However, if your host blocks email sending you may lock yourself out.",
58
  "Note: You may combine multiple authentication factors for increased security."
59
  ]
60
  },
61
  {
62
+ "slug": "section_rename_wplogin",
63
+ "title": "Rename WP Login Page",
64
  "title_short": "Rename wp-login.php",
65
+ "summary": [
66
  "Purpose - To hide your wp-login.php page from brute force attacks and hacking attempts - if your login page cannot be found, no-one can login.",
67
  "Recommendation - This is not required for complete security and if your site has irregular or inconsistent configuration it may not work for you."
68
  ]
69
  },
70
  {
71
+ "slug": "section_yubikey_authentication",
72
+ "title": "Yubikey Authentication",
73
  "title_short": "Yubikey",
74
+ "summary": [
75
  "Purpose - Verifies the identity of users who log in to your site - i.e. they are who they say they are.",
76
  "Recommendation - Use of this feature is highly recommend. Note: you must own the appropriate Yubikey hardware device."
77
  ]
78
  },
79
  {
80
+ "slug": "section_user_messages",
81
+ "title": "User Messages",
82
  "title_short": "User Messages",
83
+ "summary": [
84
  "Purpose - Customize the messages shown to visitors.",
85
  "Recommendation - Be sure to change the messages to suit your audience.",
86
  "Hint - To reset any message to its default, enter the text exactly: default"
87
  ]
88
  },
89
  {
90
+ "slug": "section_non_ui",
91
  "hidden": true
92
  }
93
  ],
94
+ "options": [
95
  {
96
+ "key": "enable_login_protect",
97
+ "section": "section_enable_plugin_feature_login_protection",
98
+ "default": "N",
99
+ "type": "checkbox",
100
+ "link_info": "http://icwp.io/51",
101
+ "link_blog": "http://icwp.io/wpsf03",
102
+ "name": "Enable Login Protection",
103
+ "summary": "Enable (or Disable) The Login Protection Feature",
104
  "description": "Checking/Un-Checking this option will completely turn on/off the whole Login Protection feature"
105
  },
106
  {
107
+ "key": "login_protect_3pty",
108
+ "section": "section_enable_plugin_feature_login_protection",
109
+ "premium": true,
110
+ "default": "N",
111
+ "type": "checkbox",
112
+ "link_info": "",
113
+ "link_blog": "",
114
+ "name": "3rd-Party Support",
115
+ "summary": "Support For 3rd-Party Plugins, e.g. WooCommerce",
116
  "description": "Add Support For 3rd-Party Login, Register, and Password Reset Forms e.g. WooCommerce, Easy Digital Downloads."
117
  },
118
  {
119
+ "key": "enable_xmlrpc_compatibility",
120
+ "section": "section_enable_plugin_feature_login_protection",
121
+ "default": "Y",
122
+ "type": "checkbox",
123
+ "link_info": "http://icwp.io/9u",
124
+ "link_blog": "",
125
+ "name": "XML-RPC Compatibility",
126
+ "summary": "Allow Login Through XML-RPC To By-Pass Login Protection Rules",
127
  "description": "Enable this if you need XML-RPC functionality e.g. if you use the WordPress iPhone/Android App."
128
  },
129
  {
130
+ "key": "rename_wplogin_path",
131
+ "section": "section_rename_wplogin",
132
+ "sensitive": true,
133
+ "default": "",
134
+ "type": "text",
135
+ "link_info": "http://icwp.io/5q",
136
+ "link_blog": "http://icwp.io/5r",
137
+ "name": "Rename WP Login",
138
+ "summary": "Rename The WordPress Login Page",
139
  "description": "Creating a path here will disable your 'wp-login.php'. Only letters and numbers are permitted: abc123"
140
  },
141
  {
142
+ "key": "enable_chained_authentication",
143
+ "section": "section_multifactor_authentication",
144
+ "default": "N",
145
+ "type": "checkbox",
146
+ "link_info": "http://icwp.io/9r",
147
+ "link_blog": "http://icwp.io/84",
148
+ "name": "Multi-Factor Authentication",
149
+ "summary": "Require All Active Authentication Factors",
150
  "description": "When enabled, all multi-factor authentication methods will be applied to a user login. Disable to only require one to pass."
151
  },
152
  {
153
+ "key": "enable_google_authenticator",
154
+ "section": "section_multifactor_authentication",
155
+ "default": "N",
156
+ "type": "checkbox",
157
+ "link_info": "http://icwp.io/shld7",
158
+ "link_blog": "http://icwp.io/shld6",
159
+ "name": "Enable Google Authenticator",
160
+ "summary": "Allow Users To Use Google Authenticator",
161
  "description": "When enabled, users will have the option to add Google Authenticator to their WordPress user profile."
162
  },
163
  {
164
+ "key": "enable_email_authentication",
165
+ "section": "section_multifactor_authentication",
166
+ "default": "N",
167
+ "type": "checkbox",
168
+ "link_info": "http://icwp.io/3t",
169
+ "link_blog": "http://icwp.io/9q",
170
+ "name": "Enable Email Authentication",
171
+ "summary": "Two-Factor Login Authentication By Email",
172
  "description": "All users will be required to verify their login by email-based two-factor authentication."
173
  },
174
  {
175
+ "key": "two_factor_auth_user_roles",
176
+ "section": "section_multifactor_authentication",
177
+ "type": "multiple_select",
178
+ "default": [
179
  1,
180
  2,
181
  3,
184
  "value_options": [
185
  {
186
  "value_key": 0,
187
+ "text": "Subscribers"
188
  },
189
  {
190
  "value_key": 1,
191
+ "text": "Contributors"
192
  },
193
  {
194
  "value_key": 2,
195
+ "text": "Authors"
196
  },
197
  {
198
  "value_key": 3,
199
+ "text": "Editors"
200
  },
201
  {
202
  "value_key": 8,
203
+ "text": "Administrators"
204
  }
205
  ],
206
+ "link_info": "http://icwp.io/4v",
207
+ "link_blog": "",
208
+ "name": "Enforce - Email Authentication",
209
+ "summary": "All User Roles Subject To Email Authentication",
210
+ "description": "Enforces email-based authentication on all users with the selected roles. Note: This setting only applies to email authentication."
211
  },
212
  {
213
+ "key": "enable_google_recaptcha_login",
214
+ "section": "section_recaptcha",
215
+ "default": "N",
216
+ "type": "checkbox",
217
+ "link_info": "http://icwp.io/9m",
218
+ "link_blog": "http://icwp.io/shld5",
219
+ "name": "Google reCAPTCHA",
220
+ "summary": "Enable Google reCAPTCHA",
221
  "description": "Use Google reCAPTCHA on the login screen."
222
  },
223
  {
224
+ "key": "google_recaptcha_style_login",
225
+ "section": "section_recaptcha",
226
+ "premium": true,
227
+ "default": "default",
228
+ "type": "select",
229
  "value_options": [
230
  {
231
  "value_key": "default",
232
+ "text": "Default"
233
  },
234
  {
235
  "value_key": "light",
236
+ "text": "Light Theme"
237
  },
238
  {
239
  "value_key": "dark",
240
+ "text": "Dark Theme"
241
  },
242
  {
243
  "value_key": "invisible",
244
+ "text": "Invisible reCAPTCHA"
245
  }
246
  ],
247
+ "link_info": "",
248
+ "link_blog": "",
249
+ "name": "reCAPTCHA Style",
250
+ "summary": "How Google reCAPTCHA Will Be Displayed",
251
+ "description": "You can choose the reCAPTCHA display format that best suits your site, including the new Invisible Recaptcha."
252
  },
253
  {
254
+ "key": "enable_login_gasp_check",
255
+ "section": "section_brute_force_login_protection",
256
+ "default": "Y",
257
+ "type": "checkbox",
258
+ "link_info": "http://icwp.io/3r",
259
+ "link_blog": "http://icwp.io/9n",
260
+ "name": "G.A.S.P Protection",
261
+ "summary": "Use G.A.S.P. Protection To Prevent Login Attempts By Bots",
262
  "description": "Adds a dynamically (Javascript) generated checkbox to the login form that prevents bots using automated login techniques. Recommended: ON."
263
  },
264
  {
265
+ "key": "login_limit_interval",
266
+ "section": "section_brute_force_login_protection",
267
+ "default": "10",
268
+ "type": "integer",
269
+ "link_info": "http://icwp.io/3q",
270
+ "link_blog": "http://icwp.io/9o",
271
+ "name": "Login Cooldown Interval",
272
+ "summary": "Limit login attempts to every X seconds",
273
  "description": "WordPress will process only ONE login attempt for every number of seconds specified. Zero (0) turns this off."
274
  },
275
  {
276
+ "key": "enable_user_register_checking",
277
+ "section": "section_brute_force_login_protection",
278
+ "default": "Y",
279
+ "type": "checkbox",
280
+ "link_info": "http://icwp.io/9p",
281
+ "link_blog": "",
282
+ "name": "User Registration",
283
+ "summary": "Apply Brute Force Protection To User Registration And Lost Passwords",
284
  "description": "When enabled, settings in this section will also apply to new user registration and users trying to reset passwords."
285
  },
286
  {
287
+ "key": "enable_yubikey",
288
+ "section": "section_yubikey_authentication",
289
+ "default": "N",
290
+ "type": "checkbox",
291
+ "link_info": "http://icwp.io/4f",
292
+ "link_blog": "http://icwp.io/9t",
293
+ "name": "Enable Yubikey Authentication",
294
+ "summary": "Turn On / Off Yubikey Authentication On This Site",
295
  "description": "Combined with your Yubikey API Key (below) this will form the basis of your Yubikey Authentication."
296
  },
297
  {
298
+ "key": "yubikey_app_id",
299
+ "section": "section_yubikey_authentication",
300
+ "sensitive": true,
301
+ "default": "",
302
+ "type": "text",
303
+ "link_info": "http://icwp.io/4g",
304
+ "link_blog": "",
305
+ "name": "Yubikey App ID",
306
+ "summary": "Your Unique Yubikey App ID",
307
  "description": "Combined with your Yubikey API Key this will form the basis of your Yubikey Authentication."
308
  },
309
  {
310
+ "key": "yubikey_api_key",
311
+ "section": "section_yubikey_authentication",
312
+ "sensitive": true,
313
+ "default": "",
314
+ "type": "text",
315
+ "link_info": "http://icwp.io/4g",
316
+ "link_blog": "",
317
+ "name": "Yubikey API Key",
318
+ "summary": "Your Unique Yubikey App API Key",
319
  "description": "Combined with your Yubikey App ID this will form the basis of your Yubikey Authentication."
320
  },
321
  {
322
+ "key": "text_imahuman",
323
+ "section": "section_user_messages",
324
+ "premium": true,
325
+ "default": "default",
326
+ "type": "text",
327
+ "link_info": "",
328
+ "link_blog": "",
329
+ "name": "GASP Checkbox Text",
330
+ "summary": "The Message Displayed Next To The GASP Checkbox",
331
+ "description": "You can change the text displayed to the user beside the checkbox if you need a customized message."
332
+ },
333
+ {
334
+ "key": "text_pleasecheckbox",
335
+ "section": "section_user_messages",
336
+ "premium": true,
337
+ "default": "default",
338
+ "type": "text",
339
+ "link_info": "",
340
+ "link_blog": "",
341
+ "name": "GASP Alert Text",
342
+ "summary": "The Message Displayed If The User Doesn't Check The Box",
343
+ "description": "You can change the text displayed to the user in the alert message if they don't check the box."
344
+ },
345
  {
346
+ "key": "email_can_send_verified_at",
347
  "transferable": false,
348
+ "section": "section_non_ui",
349
+ "default": -1
350
  },
351
  {
352
+ "key": "gasp_key",
353
  "transferable": false,
354
+ "sensitive": true,
355
+ "section": "section_non_ui"
356
  },
357
  {
358
+ "key": "two_factor_secret_key",
359
  "transferable": false,
360
+ "sensitive": true,
361
+ "section": "section_non_ui"
362
  },
363
  {
364
+ "key": "two_factor_auth_table_created",
365
  "transferable": false,
366
+ "section": "section_non_ui"
367
  },
368
  {
369
+ "key": "use_login_intent_page",
370
  "transferable": false,
371
+ "value": true,
372
+ "section": "section_non_ui"
373
  }
374
  ],
375
+ "definitions": {
376
+ "login_intent_timeout": 5,
377
+ "two_factor_auth_table_name": "login_auth",
378
  "two_factor_auth_table_columns": [
379
  "id",
380
  "session_id",
384
  "expired_at",
385
  "created_at",
386
  "deleted_at"
387
+ ],
388
+ "wizards": {
389
+ "mfa": {
390
+ "title": "Configure Multi-Factor Login Authentication",
391
+ "desc": "Easily setup multi-factor login authentication, using Email and Google Authenticator.",
392
+ "min_user_permissions": "manage_options",
393
+ "steps": {
394
+ "start": {
395
+ "security_admin": false,
396
+ "title": "Start: Multi-Factor Authentication"
397
+ },
398
+ "authemail": {
399
+ "title": "Email Authentication"
400
+ },
401
+ "authga": {
402
+ "title": "Google Authenticator"
403
+ },
404
+ "multiselect": {
405
+ "title": "Select Multifactor Auth"
406
+ },
407
+ "finished": {
408
+ "security_admin": false,
409
+ "title": "Finished: Multi-Factor Authentication"
410
+ }
411
+ }
412
+ }
413
+ }
414
  }
415
  }
src/config/feature-plugin.php CHANGED
@@ -1,460 +1,521 @@
1
  {
2
- "properties": {
3
- "slug": "plugin",
4
- "name": "Dashboard",
5
  "show_feature_menu_item": true,
6
- "storage_key": "plugin",
7
- "tagline": "Overview of the plugin settings",
8
- "show_central": true,
9
- "access_restricted": true,
10
- "premium": false,
11
- "has_custom_actions": true,
12
- "order": 10
13
  },
14
  "admin_notices": {
15
- "override-forceoff": {
16
- "id": "override-forceoff",
17
- "schedule": "conditions",
18
  "valid_admin": true,
19
- "type": "error"
20
  },
21
- "php54_version_warning": {
22
- "id": "php54_version_warning",
23
- "schedule": "once",
24
  "valid_admin": true,
25
- "type": "warning"
26
  },
27
- "plugin-update-available": {
28
- "id": "plugin-update-available",
29
- "schedule": "version",
30
  "valid_admin": true,
31
- "type": "warning"
 
32
  },
33
- "wizard_welcome": {
34
- "id": "wizard_welcome",
35
- "schedule": "once",
36
  "valid_admin": true,
37
- "delay_days": 0,
38
- "type": "promo"
39
- },
40
- "allow-tracking": {
41
- "id": "allow-tracking",
42
- "schedule": "never",
43
- "valid_admin": true,
44
- "delay_days": 0,
45
- "type": "promo"
46
  },
47
  "plugin-mailing-list-signup": {
48
- "id": "plugin-mailing-list-signup",
49
- "schedule": "once",
50
  "valid_admin": true,
51
- "delay_days": 15,
52
- "type": "promo"
53
  },
54
- "rate-plugin": {
55
- "id": "rate-plugin",
56
- "schedule": "once",
57
  "valid_admin": true,
58
- "delay_days": 30,
59
- "type": "promo"
60
  },
61
- "translate-plugin": {
62
- "id": "translate-plugin",
63
- "schedule": "once",
64
  "valid_admin": true,
65
- "delay_days": 45,
66
- "type": "promo"
67
  }
68
  },
69
- "sections": [
70
  {
71
- "slug": "section_global_security_options",
72
- "primary": true,
73
- "title": "Global Plugin Security Options",
74
  "title_short": "Global Options"
75
  },
76
  {
77
- "slug": "section_defaults",
78
- "title": "Plugin Defaults",
79
  "title_short": "Plugin Defaults"
80
  },
81
  {
82
- "slug": "section_importexport",
83
- "title": "Import / Export",
84
  "title_short": "Import / Export"
85
  },
86
  {
87
- "slug": "section_general_plugin_options",
88
- "title": "General Plugin Options",
89
  "title_short": "General Options"
90
  },
91
  {
92
- "slug": "section_third_party_google",
93
- "title": "Google",
94
  "title_short": "Google"
95
  },
96
  {
97
- "slug": "section_non_ui",
98
  "hidden": true
99
  }
100
  ],
101
- "options": [
102
  {
103
- "key": "global_enable_plugin_features",
104
- "section": "section_global_security_options",
105
- "default": "Y",
106
- "type": "checkbox",
107
- "link_info": "",
108
- "link_blog": "",
109
- "name": "Enable Plugin Features",
110
- "summary": "Global Plugin On/Off Switch",
111
  "description": "Uncheck this option to disable all Shield features"
112
  },
113
  {
114
- "key": "enable_tracking",
115
- "section": "section_general_plugin_options",
116
- "default": "N",
117
- "type": "checkbox",
118
- "link_info": "http://icwp.io/7i",
119
- "link_blog": "",
120
- "name": "Enable Information Gathering",
121
- "summary": "Permit Anonymous Usage Information Gathering",
122
  "description": "Allows us to gather information on statistics and features in-use across our client installations. This information is strictly anonymous and contains no personally, or otherwise, identifiable data."
123
  },
124
  {
125
- "key": "visitor_address_source",
126
- "section": "section_defaults",
127
- "sensitive": false,
128
- "type": "select",
129
- "default": "AUTO_DETECT_IP",
130
  "value_options": [
131
  {
132
  "value_key": "AUTO_DETECT_IP",
133
- "text": "Automatically Detect Visitor IP"
134
  },
135
  {
136
  "value_key": "REMOTE_ADDR",
137
- "text": "REMOTE_ADDR"
138
  },
139
  {
140
  "value_key": "HTTP_CF_CONNECTING_IP",
141
- "text": "HTTP_CF_CONNECTING_IP"
142
  },
143
  {
144
  "value_key": "HTTP_X_FORWARDED_FOR",
145
- "text": "HTTP_X_FORWARDED_FOR"
146
  },
147
  {
148
  "value_key": "HTTP_X_FORWARDED",
149
- "text": "HTTP_X_FORWARDED"
150
  },
151
  {
152
  "value_key": "HTTP_X_REAL_IP",
153
- "text": "HTTP_X_REAL_IP"
154
  },
155
  {
156
  "value_key": "HTTP_X_SUCURI_CLIENTIP",
157
- "text": "HTTP_X_SUCURI_CLIENTIP"
158
  },
159
  {
160
  "value_key": "HTTP_INCAP_CLIENT_IP",
161
- "text": "HTTP_INCAP_CLIENT_IP"
162
  },
163
  {
164
  "value_key": "HTTP_FORWARDED",
165
- "text": "HTTP_FORWARDED"
166
  },
167
  {
168
  "value_key": "HTTP_CLIENT_IP",
169
- "text": "HTTP_CLIENT_IP"
170
  }
171
  ],
172
- "link_info": "",
173
- "link_blog": "",
174
- "name": "Visitor IP Address",
175
- "summary": "Which Address Is Yours",
176
- "description": "There are many way to detect visitor IP addresses. Please select yours from the list."
177
  },
178
  {
179
- "key": "block_send_email_address",
180
- "section": "section_defaults",
181
- "sensitive": true,
182
- "default": "",
183
- "type": "email",
184
- "link_info": "",
185
- "link_blog": "",
186
- "name": "Report Email",
187
- "summary": "Where to send email reports",
188
  "description": "If this is empty, it will default to the blog admin email address."
189
  },
190
  {
191
- "key": "enable_upgrade_admin_notice",
192
- "section": "section_general_plugin_options",
193
- "default": "Y",
194
- "type": "checkbox",
195
- "link_info": "",
196
- "link_blog": "",
197
- "name": "In-Plugin Notices",
198
- "summary": "Display Plugin Specific Notices",
199
  "description": "Disable this option to hide certain plugin admin notices about available updates and post-update notices."
200
  },
201
  {
202
- "key": "display_plugin_badge",
203
- "section": "section_general_plugin_options",
204
- "default": "N",
205
- "type": "checkbox",
206
- "link_info": "http://icwp.io/5v",
207
- "link_blog": "http://icwp.io/wpsf20",
208
- "name": "Show Plugin Badge",
209
- "summary": "Display Plugin Badge On Your Site",
210
  "description": "Enabling this option helps support the plugin by spreading the word about it on your website. The plugin badge also demonstrates to visitors that you take your website security seriously."
211
  },
212
  {
213
- "key": "delete_on_deactivate",
214
- "section": "section_defaults",
215
- "default": "N",
216
- "type": "checkbox",
217
- "link_info": "",
218
- "link_blog": "",
219
- "name": "Delete Plugin Settings",
220
- "summary": "Delete All Plugin Settings Upon Plugin Deactivation",
221
  "description": "Careful: Removes all plugin options when you deactivate the plugin."
222
  },
223
  {
224
- "key": "importexport_enable",
225
- "section": "section_importexport",
226
- "premium": true,
227
- "default": "Y",
228
- "type": "checkbox",
229
- "link_info": "",
230
- "link_blog": "",
231
- "name": "Allow Import/Export",
232
- "summary": "Allow Import Of Options To, And Export Of Options From, This Site",
233
  "description": "Uncheck this box to completely disable import and export of options."
234
  },
235
  {
236
- "key": "importexport_masterurl",
237
- "section": "section_importexport",
238
- "default": "",
239
- "type": "text",
240
- "link_info": "",
241
- "link_blog": "",
242
- "name": "Auto-Import URL",
243
- "summary": "Automatically Import Options From This Site",
244
  "description": "Supplying a valid site URL here will make this site an 'Options Slave' and will automatically import options daily."
245
  },
246
  {
247
- "key": "importexport_whitelist",
248
- "section": "section_importexport",
249
  "transferable": false,
250
- "default": [],
251
- "type": "array",
252
- "link_info": "",
253
- "link_blog": "",
254
- "name": "Export Whitelist",
255
- "summary": "Whitelisted Sites Which Do Not Need The Secret Key To Export Options",
256
- "description": "Each site on this list will be able to export options from this site without providing the secret key. Take a new line for each URL."
257
  },
258
  {
259
- "key": "importexport_whitelist_notify",
260
- "section": "section_importexport",
261
- "default": "N",
262
- "type": "checkbox",
263
- "link_info": "",
264
- "link_blog": "",
265
- "name": "Notify Whitelist",
266
- "summary": "Notify Sites On The Whitelist To Update Options From Master",
267
  "description": "When enabled, manual options saving will notify sites on the whitelist to export options from the Master site."
268
  },
269
  {
270
- "key": "importexport_secretkey",
271
- "section": "section_importexport",
272
  "transferable": false,
273
- "default": "",
274
- "type": "noneditable_text",
275
- "link_info": "",
276
- "link_blog": "",
277
- "name": "Secret Key",
278
- "summary": "Import/Export Secret Key",
279
- "description": "Keep this Secret Key private as it will allow the import and export of options."
 
280
  },
281
  {
282
- "key": "unique_installation_id",
283
- "section": "section_general_plugin_options",
284
  "transferable": false,
285
- "default": "",
286
- "type": "noneditable_text",
287
- "link_info": "",
288
- "link_blog": "",
289
- "name": "Installation ID",
290
- "summary": "Unique Plugin Installation ID",
291
- "description": "Keep this ID private."
292
  },
293
  {
294
- "key": "google_recaptcha_style",
295
- "section": "section_third_party_google",
296
- "premium": true,
297
- "default": "light",
298
- "type": "select",
299
  "value_options": [
300
  {
301
  "value_key": "light",
302
- "text": "Light Theme"
303
  },
304
  {
305
  "value_key": "dark",
306
- "text": "Dark Theme"
307
  },
308
  {
309
  "value_key": "invisible",
310
- "text": "Invisible reCAPTCHA"
311
  }
312
  ],
313
- "link_info": "",
314
- "link_blog": "",
315
- "name": "reCAPTCHA Style",
316
- "summary": "How Google reCAPTCHA Will Be Displayed By Default",
317
- "description": "You can choose the reCAPTCHA display format that best suits your site, including the new Invisible Recaptcha."
318
  },
319
  {
320
- "key": "google_recaptcha_site_key",
321
- "section": "section_third_party_google",
322
- "sensitive": true,
323
- "default": "",
324
- "type": "text",
325
- "link_info": "http://icwp.io/shld5",
326
- "link_blog": "",
327
- "name": "reCAPTCHA Secret",
328
- "summary": "Google reCAPTCHA Secret Key",
329
  "description": "Enter your Google reCAPTCHA secret key for use throughout the plugin."
330
  },
331
  {
332
- "key": "google_recaptcha_secret_key",
333
- "section": "section_third_party_google",
334
- "sensitive": true,
335
- "default": "",
336
- "type": "text",
337
- "link_info": "http://icwp.io/shld5",
338
- "link_blog": "",
339
- "name": "reCAPTCHA Site Key",
340
- "summary": "Google reCAPTCHA Site Key",
341
  "description": "Enter your Google reCAPTCHA site key for use throughout the plugin."
342
  },
343
  {
344
- "key": "tracking_last_sent_at",
345
  "transferable": false,
346
- "default": 0,
347
- "section": "section_non_ui"
348
  },
349
  {
350
- "key": "tracking_permission_set_at",
351
  "default": 0,
352
  "section": "section_non_ui"
353
  },
354
  {
355
- "key": "installation_time",
356
  "transferable": false,
357
- "section": "section_non_ui"
358
  },
359
  {
360
- "key": "importexport_secretkey_expires_at",
361
  "transferable": false,
362
- "section": "section_non_ui"
363
  },
364
  {
365
- "key": "importexport_handshake_expires_at",
366
  "transferable": false,
367
- "section": "section_non_ui"
368
  },
369
  {
370
- "key": "importexport_last_import_hash",
371
  "transferable": false,
372
- "section": "section_non_ui"
373
  },
374
  {
375
- "key": "this_server_ip",
376
  "transferable": false,
377
- "sensitive": true,
378
- "section": "section_non_ui",
379
- "value": ""
380
  },
381
  {
382
- "key": "this_server_ip_last_check_at",
383
  "transferable": false,
384
- "section": "section_non_ui",
385
- "value": 0
386
  }
387
  ],
388
- "definitions": {
389
- "help_video_id": "",
390
- "tracking_cron_handle": "plugin_tracking_cron",
391
- "tracking_post_url": "https://tracking.icontrolwp.com/track/plugin/shield",
392
  "importexport_cron_name": "autoimport",
393
  "active_plugin_features": [
394
  {
395
- "slug": "admin_access_restriction",
396
- "storage_key": "admin_access_restriction",
397
  "load_priority": 20
398
  },
399
  {
400
- "slug": "firewall",
401
- "storage_key": "firewall",
402
  "load_priority": 13
403
  },
404
  {
405
- "slug": "login_protect",
406
  "storage_key": "loginprotect"
407
  },
408
  {
409
- "slug": "user_management",
410
  "storage_key": "user_management"
411
  },
412
  {
413
- "slug": "comments_filter",
414
  "storage_key": "commentsfilter"
415
  },
416
  {
417
- "slug": "autoupdates",
418
  "storage_key": "autoupdates"
419
  },
420
  {
421
- "slug": "hack_protect",
422
  "storage_key": "hack_protect"
423
  },
424
  {
425
- "slug": "headers",
426
  "storage_key": "headers"
427
  },
428
  {
429
- "slug": "lockdown",
430
  "storage_key": "lockdown"
431
  },
432
  {
433
- "slug": "ips",
434
- "storage_key": "ips",
435
  "load_priority": 12
436
  },
437
  {
438
- "slug": "statistics",
439
- "storage_key": "statistics",
440
  "load_priority": 11,
441
- "hidden": false
442
  },
443
  {
444
- "slug": "audit_trail",
445
- "storage_key": "audit_trail",
446
  "load_priority": 11,
447
- "hidden": false
448
  },
449
  {
450
- "slug": "license",
451
- "storage_key": "license",
452
  "load_priority": 10
453
  },
454
  {
455
- "slug": "email",
456
  "storage_key": "email"
457
  }
458
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
459
  }
460
  }
1
  {
2
+ "properties": {
3
+ "slug": "plugin",
4
+ "name": "Dashboard",
5
  "show_feature_menu_item": true,
6
+ "storage_key": "plugin",
7
+ "tagline": "Overview of the plugin settings",
8
+ "show_central": true,
9
+ "access_restricted": true,
10
+ "premium": false,
11
+ "has_custom_actions": true,
12
+ "order": 10
13
  },
14
  "admin_notices": {
15
+ "override-forceoff": {
16
+ "id": "override-forceoff",
17
+ "schedule": "conditions",
18
  "valid_admin": true,
19
+ "type": "error"
20
  },
21
+ "plugin-update-available": {
22
+ "id": "plugin-update-available",
23
+ "schedule": "version",
24
  "valid_admin": true,
25
+ "type": "warning"
26
  },
27
+ "wizard_welcome": {
28
+ "id": "wizard_welcome",
29
+ "schedule": "once",
30
  "valid_admin": true,
31
+ "delay_days": 0,
32
+ "type": "promo"
33
  },
34
+ "allow-tracking": {
35
+ "id": "allow-tracking",
36
+ "schedule": "never",
37
  "valid_admin": true,
38
+ "delay_days": 0,
39
+ "type": "promo"
 
 
 
 
 
 
 
40
  },
41
  "plugin-mailing-list-signup": {
42
+ "id": "plugin-mailing-list-signup",
43
+ "schedule": "once",
44
  "valid_admin": true,
45
+ "delay_days": 15,
46
+ "type": "promo"
47
  },
48
+ "rate-plugin": {
49
+ "id": "rate-plugin",
50
+ "schedule": "once",
51
  "valid_admin": true,
52
+ "delay_days": 30,
53
+ "type": "promo"
54
  },
55
+ "translate-plugin": {
56
+ "id": "translate-plugin",
57
+ "schedule": "once",
58
  "valid_admin": true,
59
+ "delay_days": 45,
60
+ "type": "promo"
61
  }
62
  },
63
+ "sections": [
64
  {
65
+ "slug": "section_global_security_options",
66
+ "primary": true,
67
+ "title": "Global Plugin Security Options",
68
  "title_short": "Global Options"
69
  },
70
  {
71
+ "slug": "section_defaults",
72
+ "title": "Plugin Defaults",
73
  "title_short": "Plugin Defaults"
74
  },
75
  {
76
+ "slug": "section_importexport",
77
+ "title": "Import / Export",
78
  "title_short": "Import / Export"
79
  },
80
  {
81
+ "slug": "section_general_plugin_options",
82
+ "title": "General Plugin Options",
83
  "title_short": "General Options"
84
  },
85
  {
86
+ "slug": "section_third_party_google",
87
+ "title": "Google",
88
  "title_short": "Google"
89
  },
90
  {
91
+ "slug": "section_non_ui",
92
  "hidden": true
93
  }
94
  ],
95
+ "options": [
96
  {
97
+ "key": "global_enable_plugin_features",
98
+ "section": "section_global_security_options",
99
+ "default": "Y",
100
+ "type": "checkbox",
101
+ "link_info": "",
102
+ "link_blog": "",
103
+ "name": "Enable Plugin Features",
104
+ "summary": "Global Plugin On/Off Switch",
105
  "description": "Uncheck this option to disable all Shield features"
106
  },
107
  {
108
+ "key": "enable_tracking",
109
+ "section": "section_general_plugin_options",
110
+ "default": "N",
111
+ "type": "checkbox",
112
+ "link_info": "http://icwp.io/7i",
113
+ "link_blog": "",
114
+ "name": "Enable Information Gathering",
115
+ "summary": "Permit Anonymous Usage Information Gathering",
116
  "description": "Allows us to gather information on statistics and features in-use across our client installations. This information is strictly anonymous and contains no personally, or otherwise, identifiable data."
117
  },
118
  {
119
+ "key": "visitor_address_source",
120
+ "section": "section_defaults",
121
+ "sensitive": false,
122
+ "type": "select",
123
+ "default": "AUTO_DETECT_IP",
124
  "value_options": [
125
  {
126
  "value_key": "AUTO_DETECT_IP",
127
+ "text": "Automatically Detect Visitor IP"
128
  },
129
  {
130
  "value_key": "REMOTE_ADDR",
131
+ "text": "REMOTE_ADDR"
132
  },
133
  {
134
  "value_key": "HTTP_CF_CONNECTING_IP",
135
+ "text": "HTTP_CF_CONNECTING_IP"
136
  },
137
  {
138
  "value_key": "HTTP_X_FORWARDED_FOR",
139
+ "text": "HTTP_X_FORWARDED_FOR"
140
  },
141
  {
142
  "value_key": "HTTP_X_FORWARDED",
143
+ "text": "HTTP_X_FORWARDED"
144
  },
145
  {
146
  "value_key": "HTTP_X_REAL_IP",
147
+ "text": "HTTP_X_REAL_IP"
148
  },
149
  {
150
  "value_key": "HTTP_X_SUCURI_CLIENTIP",
151
+ "text": "HTTP_X_SUCURI_CLIENTIP"
152
  },
153
  {
154
  "value_key": "HTTP_INCAP_CLIENT_IP",
155
+ "text": "HTTP_INCAP_CLIENT_IP"
156
  },
157
  {
158
  "value_key": "HTTP_FORWARDED",
159
+ "text": "HTTP_FORWARDED"
160
  },
161
  {
162
  "value_key": "HTTP_CLIENT_IP",
163
+ "text": "HTTP_CLIENT_IP"
164
  }
165
  ],
166
+ "link_info": "",
167
+ "link_blog": "",
168
+ "name": "Visitor IP Address",
169
+ "summary": "Which Address Is Yours",
170
+ "description": "There are many way to detect visitor IP addresses. Please select yours from the list."
171
  },
172
  {
173
+ "key": "block_send_email_address",
174
+ "section": "section_defaults",
175
+ "sensitive": true,
176
+ "default": "",
177
+ "type": "email",
178
+ "link_info": "",
179
+ "link_blog": "",
180
+ "name": "Report Email",
181
+ "summary": "Where to send email reports",
182
  "description": "If this is empty, it will default to the blog admin email address."
183
  },
184
  {
185
+ "key": "enable_upgrade_admin_notice",
186
+ "section": "section_general_plugin_options",
187
+ "default": "Y",
188
+ "type": "checkbox",
189
+ "link_info": "",
190
+ "link_blog": "",
191
+ "name": "In-Plugin Notices",
192
+ "summary": "Display Plugin Specific Notices",
193
  "description": "Disable this option to hide certain plugin admin notices about available updates and post-update notices."
194
  },
195
  {
196
+ "key": "display_plugin_badge",
197
+ "section": "section_general_plugin_options",
198
+ "default": "N",
199
+ "type": "checkbox",
200
+ "link_info": "http://icwp.io/5v",
201
+ "link_blog": "http://icwp.io/wpsf20",
202
+ "name": "Show Plugin Badge",
203
+ "summary": "Display Plugin Badge On Your Site",
204
  "description": "Enabling this option helps support the plugin by spreading the word about it on your website. The plugin badge also demonstrates to visitors that you take your website security seriously."
205
  },
206
  {
207
+ "key": "delete_on_deactivate",
208
+ "section": "section_defaults",
209
+ "default": "N",
210
+ "type": "checkbox",
211
+ "link_info": "",
212
+ "link_blog": "",
213
+ "name": "Delete Plugin Settings",
214
+ "summary": "Delete All Plugin Settings Upon Plugin Deactivation",
215
  "description": "Careful: Removes all plugin options when you deactivate the plugin."
216
  },
217
  {
218
+ "key": "importexport_enable",
219
+ "section": "section_importexport",
220
+ "premium": true,
221
+ "default": "Y",
222
+ "type": "checkbox",
223
+ "link_info": "",
224
+ "link_blog": "",
225
+ "name": "Allow Import/Export",
226
+ "summary": "Allow Import Of Options To, And Export Of Options From, This Site",
227
  "description": "Uncheck this box to completely disable import and export of options."
228
  },
229
  {
230
+ "key": "importexport_masterurl",
231
+ "section": "section_importexport",
232
+ "default": "",
233
+ "type": "text",
234
+ "link_info": "",
235
+ "link_blog": "",
236
+ "name": "Auto-Import URL",
237
+ "summary": "Automatically Import Options From This Site",
238
  "description": "Supplying a valid site URL here will make this site an 'Options Slave' and will automatically import options daily."
239
  },
240
  {
241
+ "key": "importexport_whitelist",
242
+ "section": "section_importexport",
243
  "transferable": false,
244
+ "default": [],
245
+ "type": "array",
246
+ "link_info": "",
247
+ "link_blog": "",
248
+ "name": "Export Whitelist",
249
+ "summary": "Whitelisted Sites Which Do Not Need The Secret Key To Export Options",
250
+ "description": "Each site on this list will be able to export options from this site without providing the secret key. Take a new line for each URL."
251
  },
252
  {
253
+ "key": "importexport_whitelist_notify",
254
+ "section": "section_importexport",
255
+ "default": "N",
256
+ "type": "checkbox",
257
+ "link_info": "",
258
+ "link_blog": "",
259
+ "name": "Notify Whitelist",
260
+ "summary": "Notify Sites On The Whitelist To Update Options From Master",
261
  "description": "When enabled, manual options saving will notify sites on the whitelist to export options from the Master site."
262
  },
263
  {
264
+ "key": "importexport_secretkey",
265
+ "section": "section_importexport",
266
  "transferable": false,
267
+ "sensitive": true,
268
+ "default": "",
269
+ "type": "noneditable_text",
270
+ "link_info": "",
271
+ "link_blog": "",
272
+ "name": "Secret Key",
273
+ "summary": "Import/Export Secret Key",
274
+ "description": "Keep this Secret Key private as it will allow the import and export of options."
275
  },
276
  {
277
+ "key": "unique_installation_id",
278
+ "section": "section_general_plugin_options",
279
  "transferable": false,
280
+ "default": "",
281
+ "type": "noneditable_text",
282
+ "link_info": "",
283
+ "link_blog": "",
284
+ "name": "Installation ID",
285
+ "summary": "Unique Plugin Installation ID",
286
+ "description": "Keep this ID private."
287
  },
288
  {
289
+ "key": "google_recaptcha_style",
290
+ "section": "section_third_party_google",
291
+ "premium": true,
292
+ "default": "light",
293
+ "type": "select",
294
  "value_options": [
295
  {
296
  "value_key": "light",
297
+ "text": "Light Theme"
298
  },
299
  {
300
  "value_key": "dark",
301
+ "text": "Dark Theme"
302
  },
303
  {
304
  "value_key": "invisible",
305
+ "text": "Invisible reCAPTCHA"
306
  }
307
  ],
308
+ "link_info": "",
309
+ "link_blog": "",
310
+ "name": "reCAPTCHA Style",
311
+ "summary": "How Google reCAPTCHA Will Be Displayed By Default",
312
+ "description": "You can choose the reCAPTCHA display format that best suits your site, including the new Invisible Recaptcha."
313
  },
314
  {
315
+ "key": "google_recaptcha_site_key",
316
+ "section": "section_third_party_google",
317
+ "sensitive": true,
318
+ "default": "",
319
+ "type": "text",
320
+ "link_info": "http://icwp.io/shld5",
321
+ "link_blog": "",
322
+ "name": "reCAPTCHA Secret",
323
+ "summary": "Google reCAPTCHA Secret Key",
324
  "description": "Enter your Google reCAPTCHA secret key for use throughout the plugin."
325
  },
326
  {
327
+ "key": "google_recaptcha_secret_key",
328
+ "section": "section_third_party_google",
329
+ "sensitive": true,
330
+ "default": "",
331
+ "type": "text",
332
+ "link_info": "http://icwp.io/shld5",
333
+ "link_blog": "",
334
+ "name": "reCAPTCHA Site Key",
335
+ "summary": "Google reCAPTCHA Site Key",
336
  "description": "Enter your Google reCAPTCHA site key for use throughout the plugin."
337
  },
338
  {
339
+ "key": "tracking_last_sent_at",
340
  "transferable": false,
341
+ "default": 0,
342
+ "section": "section_non_ui"
343
  },
344
  {
345
+ "key": "tracking_permission_set_at",
346
  "default": 0,
347
  "section": "section_non_ui"
348
  },
349
  {
350
+ "key": "installation_time",
351
  "transferable": false,
352
+ "section": "section_non_ui"
353
  },
354
  {
355
+ "key": "importexport_secretkey_expires_at",
356
  "transferable": false,
357
+ "section": "section_non_ui"
358
  },
359
  {
360
+ "key": "importexport_handshake_expires_at",
361
  "transferable": false,
362
+ "section": "section_non_ui"
363
  },
364
  {
365
+ "key": "importexport_last_import_hash",
366
  "transferable": false,
367
+ "section": "section_non_ui"
368
  },
369
  {
370
+ "key": "this_server_ip",
371
  "transferable": false,
372
+ "sensitive": true,
373
+ "section": "section_non_ui",
374
+ "value": ""
375
  },
376
  {
377
+ "key": "this_server_ip_last_check_at",
378
  "transferable": false,
379
+ "section": "section_non_ui",
380
+ "value": 0
381
  }
382
  ],
383
+ "definitions": {
384
+ "help_video_id": "",
385
+ "tracking_cron_handle": "plugin_tracking_cron",
386
+ "tracking_post_url": "https://tracking.icontrolwp.com/track/plugin/shield",
387
  "importexport_cron_name": "autoimport",
388
  "active_plugin_features": [
389
  {
390
+ "slug": "admin_access_restriction",
391
+ "storage_key": "admin_access_restriction",
392
  "load_priority": 20
393
  },
394
  {
395
+ "slug": "firewall",
396
+ "storage_key": "firewall",
397
  "load_priority": 13
398
  },
399
  {
400
+ "slug": "login_protect",
401
  "storage_key": "loginprotect"
402
  },
403
  {
404
+ "slug": "user_management",
405
  "storage_key": "user_management"
406
  },
407
  {
408
+ "slug": "comments_filter",
409
  "storage_key": "commentsfilter"
410
  },
411
  {
412
+ "slug": "autoupdates",
413
  "storage_key": "autoupdates"
414
  },
415
  {
416
+ "slug": "hack_protect",
417
  "storage_key": "hack_protect"
418
  },
419
  {
420
+ "slug": "headers",
421
  "storage_key": "headers"
422
  },
423
  {
424
+ "slug": "lockdown",
425
  "storage_key": "lockdown"
426
  },
427
  {
428
+ "slug": "ips",
429
+ "storage_key": "ips",
430
  "load_priority": 12
431
  },
432
  {
433
+ "slug": "statistics",
434
+ "storage_key": "statistics",
435
  "load_priority": 11,
436
+ "hidden": false
437
  },
438
  {
439
+ "slug": "audit_trail",
440
+ "storage_key": "audit_trail",
441
  "load_priority": 11,
442
+ "hidden": false
443
  },
444
  {
445
+ "slug": "license",
446
+ "storage_key": "license",
447
  "load_priority": 10
448
  },
449
  {
450
+ "slug": "email",
451
  "storage_key": "email"
452
  }
453
+ ],
454
+ "wizards": {
455
+ "welcome": {
456
+ "title": "Getting Started Setup Wizard",
457
+ "desc": "An introduction to this security plugin, helping you get setup and started quickly with the core features.",
458
+ "min_user_permissions": "manage_options",
459
+ "steps": {
460
+ "welcome": {
461
+ "security_admin": false,
462
+ "title": "Welcome"
463
+ },
464
+ "ip_detect": {
465
+ "title": "IP Detection"
466
+ },
467
+ "license": {
468
+ "title": "Go Pro"
469
+ },
470
+ "import": {
471
+ "title": "Import"
472
+ },
473
+ "admin_access_restriction": {
474
+ "title": "Security Admin"
475
+ },
476
+ "audit_trail": {
477
+ "title": "Audit Trail"
478
+ },
479
+ "ips": {
480
+ "title": "IP Blacklist"
481
+ },
482
+ "login_protect": {
483
+ "title": "Login Protection"
484
+ },
485
+ "comments_filter": {
486
+ "title": "Comment SPAM"
487
+ },
488
+ "how_shield_works": {
489
+ "title": "How Shield Works"
490
+ },
491
+ "optin": {
492
+ "title": "Join Us!"
493
+ },
494
+ "thankyou": {
495
+ "security_admin": false,
496
+ "title": "Thank You!"
497
+ }
498
+ }
499
+ },
500
+ "importexport": {
501
+ "title": "Options Import/Export Wizard",
502
+ "desc": "Walks you through the import and export of options, as well as configuring ongoing automated options-sync.",
503
+ "min_user_permissions": "manage_options",
504
+ "has_premium": true,
505
+ "steps": {
506
+ "start": {
507
+ "security_admin": false,
508
+ "title": "Start: Options Import"
509
+ },
510
+ "import": {
511
+ "title": "Run Options Import"
512
+ },
513
+ "finished": {
514
+ "security_admin": false,
515
+ "title": "Finished: Options Import"
516
+ }
517
+ }
518
+ }
519
+ }
520
  }
521
  }
src/features/admin_access_restriction.php CHANGED
@@ -1,8 +1,10 @@
1
  <?php
2
 
3
- if ( !class_exists('ICWP_WPSF_FeatureHandler_AdminAccessRestriction') ):
 
 
4
 
5
- require_once( dirname(__FILE__).DIRECTORY_SEPARATOR.'base_wpsf.php' );
6
 
7
  class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureHandler_BaseWpsf {
8
 
@@ -47,7 +49,7 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
47
  $bSuccess = $this->checkAdminAccessKeySubmission();
48
  if ( $bSuccess ) {
49
  $this->setPermissionToSubmit( true );
50
- $sResponseData[ 'html' ] = _wpsf__( 'Security Admin Access Key Accepted.' ). ' '. _wpsf__('Please wait').' ...';
51
  }
52
  else {
53
  $sResponseData[ 'html' ] = $this->renderAdminAccessAjaxLoginForm( _wpsf__( 'Error - Invalid Key' ) );
@@ -72,16 +74,14 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
72
  return $this->bHasPermissionToSubmit;
73
  }
74
 
75
- $oDp = $this->loadDataProcessor();
76
-
77
  $this->bHasPermissionToSubmit = $fHasPermission;
78
- if ( $this->getIsMainFeatureEnabled() ) {
79
 
80
  $sAccessKey = $this->getOpt( 'admin_access_key' );
81
  if ( !empty( $sAccessKey ) ) {
82
- $sHash = md5( $sAccessKey );
83
- $sCookieValue = $oDp->FetchCookie( $this->getAdminAccessKeyCookieName() );
84
- $this->bHasPermissionToSubmit = ( $sCookieValue === $sHash );
85
  }
86
  }
87
  return $this->bHasPermissionToSubmit;
@@ -134,14 +134,13 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
134
 
135
  /**
136
  * TODO: Bug where if $sType is defined, it'll be set to 'wp' anyway
137
- *
138
  * @param string $sType - wp or wpms
139
  * @return array
140
  */
141
  public function getOptionsToRestrict( $sType = '' ) {
142
  $sType = empty( $sType ) ? ( $this->loadWp()->isMultisite() ? 'wpms' : 'wp' ) : 'wp';
143
  $aOptions = $this->getRestrictedOptions();
144
- return ( isset( $aOptions[$sType.'_options'] ) && is_array( $aOptions[$sType.'_options'] ) ) ? $aOptions[$sType.'_options'] : array();
145
  }
146
 
147
  /**
@@ -151,7 +150,7 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
151
  public function getOptionsPagesToRestrict( $sType = '' ) {
152
  $sType = empty( $sType ) ? ( $this->loadWp()->isMultisite() ? 'wpms' : 'wp' ) : 'wp';
153
  $aOptions = $this->getRestrictedOptions();
154
- return ( isset( $aOptions[$sType.'_pages'] ) && is_array( $aOptions[$sType.'_pages'] ) ) ? $aOptions[$sType.'_pages'] : array();
155
  }
156
 
157
  /**
@@ -159,21 +158,19 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
159
  protected function setAdminAccessCookie() {
160
  $sAccessKey = $this->getOpt( 'admin_access_key' );
161
  if ( !empty( $sAccessKey ) ) {
162
- $sValue = md5( $sAccessKey );
163
- $sTimeout = $this->getOpt( 'admin_access_timeout' ) * 60;
164
- $_COOKIE[ $this->getAdminAccessKeyCookieName() ] = $sValue;
165
- $this->loadDataProcessor()->setCookie(
166
- $this->getAdminAccessKeyCookieName(),
167
- $sValue,
168
- $sTimeout
169
- );
170
  }
171
  }
172
 
173
  /**
174
  */
175
  protected function clearAdminAccessCookie() {
176
- $this->loadDataProcessor()->setDeleteCookie( $this->getAdminAccessKeyCookieName() );
177
  }
178
 
179
  /**
@@ -189,8 +186,8 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
189
  /**
190
  * @return string
191
  */
192
- public function getAdminAccessKeyCookieName() {
193
- return $this->getDefinition( 'admin_access_key_cookie_name' );
194
  }
195
 
196
  /**
@@ -253,7 +250,7 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
253
  protected function loadStrings_SectionTitles( $aOptionsParams ) {
254
 
255
  $sSectionSlug = $aOptionsParams[ 'slug' ];
256
- switch( $sSectionSlug ) {
257
 
258
  case 'section_enable_plugin_feature_admin_access_restriction' :
259
  $sTitle = sprintf( _wpsf__( 'Enable Plugin Feature: %s' ), $this->getMainFeatureName() );
@@ -286,9 +283,9 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
286
  default:
287
  throw new Exception( sprintf( 'A section slug was defined but with no associated strings. Slug: "%s".', $sSectionSlug ) );
288
  }
289
- $aOptionsParams['title'] = $sTitle;
290
- $aOptionsParams['summary'] = ( isset( $aSummary ) && is_array( $aSummary ) ) ? $aSummary : array();
291
- $aOptionsParams['title_short'] = $sTitleShort;
292
  return $aOptionsParams;
293
  }
294
 
@@ -299,8 +296,8 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
299
  */
300
  protected function loadStrings_Options( $aOptionsParams ) {
301
 
302
- $sKey = $aOptionsParams['key'];
303
- switch( $sKey ) {
304
 
305
  case 'enable_admin_access_restriction' :
306
  $sName = sprintf( _wpsf__( 'Enable %s' ), _wpsf__( 'Security Admin' ) );
@@ -314,27 +311,27 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
314
  $sDescription = sprintf( _wpsf__( 'Careful: %s' ), _wpsf__( 'If you forget this, you could potentially lock yourself out from using this plugin.' ) );
315
  break;
316
 
317
-
318
  case 'admin_access_timeout' :
319
  $sName = _wpsf__( 'Security Admin Timeout' );
320
  $sSummary = _wpsf__( 'Specify An Automatic Timeout Interval For Security Admin Access' );
321
- $sDescription = _wpsf__( 'This will automatically expire your Security Admin Session.')
322
- .' '._wpsf__( 'Does not apply until you enter the access key again.' )
323
- .'<br />'.sprintf( _wpsf__( 'Default: %s minutes.' ), $this->getOptionsVo()->getOptDefault( 'admin_access_timeout' ) );
 
324
  break;
325
 
326
  case 'admin_access_restrict_posts' :
327
  $sName = _wpsf__( 'Pages' );
328
  $sSummary = _wpsf__( 'Restrict Access To Key WordPress Posts And Pages Actions' );
329
  $sDescription = sprintf( _wpsf__( 'Careful: %s' ), _wpsf__( 'This will restrict access to page/post creation, editing and deletion.' ) )
330
- .'<br />'.sprintf(_wpsf__( 'Note: %s' ), sprintf( _wpsf__( 'Selecting "%s" will also restrict all other options.' ), _wpsf__('Edit') ) );
331
  break;
332
 
333
  case 'admin_access_restrict_plugins' :
334
  $sName = _wpsf__( 'Plugins' );
335
  $sSummary = _wpsf__( 'Restrict Access To Key WordPress Plugin Actions' );
336
  $sDescription = sprintf( _wpsf__( 'Careful: %s' ), _wpsf__( 'This will restrict access to plugin installation, update, activation and deletion.' ) )
337
- . '<br />' . sprintf( _wpsf__( 'Note: %s' ), sprintf( _wpsf__( 'Selecting "%s" will also restrict all other options.' ), _wpsf__( 'Activate' ) ) );
338
  break;
339
 
340
  case 'admin_access_restrict_options' :
@@ -359,7 +356,7 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
359
  sprintf(
360
  _wpsf__( 'Selecting "%s" will also restrict all other options.' ),
361
  sprintf(
362
- _wpsf__('%s and %s'),
363
  _wpsf__( 'Activate' ),
364
  _wpsf__( 'Edit Theme Options' )
365
  )
@@ -371,9 +368,9 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
371
  throw new Exception( sprintf( 'An option has been defined but without strings assigned to it. Option key: "%s".', $sKey ) );
372
  }
373
 
374
- $aOptionsParams['name'] = $sName;
375
- $aOptionsParams['summary'] = $sSummary;
376
- $aOptionsParams['description'] = $sDescription;
377
  return $aOptionsParams;
378
  }
379
 
@@ -396,7 +393,11 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
396
  if ( in_array( 'activate_plugins', $aPluginsRestrictions ) ) {
397
  $this->setOpt(
398
  'admin_access_restrict_plugins',
399
- array_unique( array_merge( $aPluginsRestrictions, array( 'install_plugins', 'update_plugins', 'delete_plugins' ) ) )
 
 
 
 
400
  );
401
  }
402
 
@@ -405,7 +406,11 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
405
  if ( in_array( 'switch_themes', $aThemesRestrictions ) && in_array( 'edit_theme_options', $aThemesRestrictions ) ) {
406
  $this->setOpt(
407
  'admin_access_restrict_themes',
408
- array_unique( array_merge( $aThemesRestrictions, array( 'install_themes', 'update_themes', 'delete_themes' ) ) )
 
 
 
 
409
  );
410
  }
411
 
@@ -417,5 +422,4 @@ class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureH
417
  );
418
  }
419
  }
420
- }
421
- endif;
1
  <?php
2
 
3
+ if ( class_exists( 'ICWP_WPSF_FeatureHandler_AdminAccessRestriction' ) ) {
4
+ return;
5
+ }
6
 
7
+ require_once( dirname( __FILE__ ).DIRECTORY_SEPARATOR.'base_wpsf.php' );
8
 
9
  class ICWP_WPSF_FeatureHandler_AdminAccessRestriction extends ICWP_WPSF_FeatureHandler_BaseWpsf {
10
 
49
  $bSuccess = $this->checkAdminAccessKeySubmission();
50
  if ( $bSuccess ) {
51
  $this->setPermissionToSubmit( true );
52
+ $sResponseData[ 'html' ] = _wpsf__( 'Security Admin Access Key Accepted.' ).' '._wpsf__( 'Please wait' ).' ...';
53
  }
54
  else {
55
  $sResponseData[ 'html' ] = $this->renderAdminAccessAjaxLoginForm( _wpsf__( 'Error - Invalid Key' ) );
74
  return $this->bHasPermissionToSubmit;
75
  }
76
 
 
 
77
  $this->bHasPermissionToSubmit = $fHasPermission;
78
+ if ( $this->getIsMainFeatureEnabled() ) {
79
 
80
  $sAccessKey = $this->getOpt( 'admin_access_key' );
81
  if ( !empty( $sAccessKey ) ) {
82
+ $oDp = $this->loadDP();
83
+ $sCookieValue = $oDp->cookie( $this->getSecurityAdminCookieName() );
84
+ $this->bHasPermissionToSubmit = ( $sCookieValue === md5( $sAccessKey ) );
85
  }
86
  }
87
  return $this->bHasPermissionToSubmit;
134
 
135
  /**
136
  * TODO: Bug where if $sType is defined, it'll be set to 'wp' anyway
 
137
  * @param string $sType - wp or wpms
138
  * @return array
139
  */
140
  public function getOptionsToRestrict( $sType = '' ) {
141
  $sType = empty( $sType ) ? ( $this->loadWp()->isMultisite() ? 'wpms' : 'wp' ) : 'wp';
142
  $aOptions = $this->getRestrictedOptions();
143
+ return ( isset( $aOptions[ $sType.'_options' ] ) && is_array( $aOptions[ $sType.'_options' ] ) ) ? $aOptions[ $sType.'_options' ] : array();
144
  }
145
 
146
  /**
150
  public function getOptionsPagesToRestrict( $sType = '' ) {
151
  $sType = empty( $sType ) ? ( $this->loadWp()->isMultisite() ? 'wpms' : 'wp' ) : 'wp';
152
  $aOptions = $this->getRestrictedOptions();
153
+ return ( isset( $aOptions[ $sType.'_pages' ] ) && is_array( $aOptions[ $sType.'_pages' ] ) ) ? $aOptions[ $sType.'_pages' ] : array();
154
  }
155
 
156
  /**
158
  protected function setAdminAccessCookie() {
159
  $sAccessKey = $this->getOpt( 'admin_access_key' );
160
  if ( !empty( $sAccessKey ) ) {
161
+ $this->loadDP()
162
+ ->setCookie(
163
+ $this->getSecurityAdminCookieName(),
164
+ md5( $sAccessKey ),
165
+ $this->getOpt( 'admin_access_timeout' )*60
166
+ );
 
 
167
  }
168
  }
169
 
170
  /**
171
  */
172
  protected function clearAdminAccessCookie() {
173
+ $this->loadDataProcessor()->setDeleteCookie( $this->getSecurityAdminCookieName() );
174
  }
175
 
176
  /**
186
  /**
187
  * @return string
188
  */
189
+ public function getSecurityAdminCookieName() {
190
+ return $this->getDefinition( 'security_admin_cookie_name' );
191
  }
192
 
193
  /**
250
  protected function loadStrings_SectionTitles( $aOptionsParams ) {
251
 
252
  $sSectionSlug = $aOptionsParams[ 'slug' ];
253
+ switch ( $sSectionSlug ) {
254
 
255
  case 'section_enable_plugin_feature_admin_access_restriction' :
256
  $sTitle = sprintf( _wpsf__( 'Enable Plugin Feature: %s' ), $this->getMainFeatureName() );
283
  default:
284
  throw new Exception( sprintf( 'A section slug was defined but with no associated strings. Slug: "%s".', $sSectionSlug ) );
285
  }
286
+ $aOptionsParams[ 'title' ] = $sTitle;
287
+ $aOptionsParams[ 'summary' ] = ( isset( $aSummary ) && is_array( $aSummary ) ) ? $aSummary : array();
288
+ $aOptionsParams[ 'title_short' ] = $sTitleShort;
289
  return $aOptionsParams;
290
  }
291
 
296
  */
297
  protected function loadStrings_Options( $aOptionsParams ) {
298
 
299
+ $sKey = $aOptionsParams[ 'key' ];
300
+ switch ( $sKey ) {
301
 
302
  case 'enable_admin_access_restriction' :
303
  $sName = sprintf( _wpsf__( 'Enable %s' ), _wpsf__( 'Security Admin' ) );
311
  $sDescription = sprintf( _wpsf__( 'Careful: %s' ), _wpsf__( 'If you forget this, you could potentially lock yourself out from using this plugin.' ) );
312
  break;
313
 
 
314
  case 'admin_access_timeout' :
315
  $sName = _wpsf__( 'Security Admin Timeout' );
316
  $sSummary = _wpsf__( 'Specify An Automatic Timeout Interval For Security Admin Access' );
317
+ $sDescription = _wpsf__( 'This will automatically expire your Security Admin Session.' )
318
+ .' '._wpsf__( 'Does not apply until you enter the access key again.' )
319
+ .'<br />'.sprintf( _wpsf__( 'Default: %s minutes.' ), $this->getOptionsVo()
320
+ ->getOptDefault( 'admin_access_timeout' ) );
321
  break;
322
 
323
  case 'admin_access_restrict_posts' :
324
  $sName = _wpsf__( 'Pages' );
325
  $sSummary = _wpsf__( 'Restrict Access To Key WordPress Posts And Pages Actions' );
326
  $sDescription = sprintf( _wpsf__( 'Careful: %s' ), _wpsf__( 'This will restrict access to page/post creation, editing and deletion.' ) )
327
+ .'<br />'.sprintf( _wpsf__( 'Note: %s' ), sprintf( _wpsf__( 'Selecting "%s" will also restrict all other options.' ), _wpsf__( 'Edit' ) ) );
328
  break;
329
 
330
  case 'admin_access_restrict_plugins' :
331
  $sName = _wpsf__( 'Plugins' );
332
  $sSummary = _wpsf__( 'Restrict Access To Key WordPress Plugin Actions' );
333
  $sDescription = sprintf( _wpsf__( 'Careful: %s' ), _wpsf__( 'This will restrict access to plugin installation, update, activation and deletion.' ) )
334
+ .'<br />'.sprintf( _wpsf__( 'Note: %s' ), sprintf( _wpsf__( 'Selecting "%s" will also restrict all other options.' ), _wpsf__( 'Activate' ) ) );
335
  break;
336
 
337
  case 'admin_access_restrict_options' :
356
  sprintf(
357
  _wpsf__( 'Selecting "%s" will also restrict all other options.' ),
358
  sprintf(
359
+ _wpsf__( '%s and %s' ),
360
  _wpsf__( 'Activate' ),
361
  _wpsf__( 'Edit Theme Options' )
362
  )
368
  throw new Exception( sprintf( 'An option has been defined but without strings assigned to it. Option key: "%s".', $sKey ) );
369
  }
370
 
371
+ $aOptionsParams[ 'name' ] = $sName;
372
+ $aOptionsParams[ 'summary' ] = $sSummary;
373
+ $aOptionsParams[ 'description' ] = $sDescription;
374
  return $aOptionsParams;
375
  }
376
 
393
  if ( in_array( 'activate_plugins', $aPluginsRestrictions ) ) {
394
  $this->setOpt(
395
  'admin_access_restrict_plugins',
396
+ array_unique( array_merge( $aPluginsRestrictions, array(
397
+ 'install_plugins',
398
+ 'update_plugins',
399
+ 'delete_plugins'
400
+ ) ) )
401
  );
402
  }
403
 
406
  if ( in_array( 'switch_themes', $aThemesRestrictions ) && in_array( 'edit_theme_options', $aThemesRestrictions ) ) {
407
  $this->setOpt(
408
  'admin_access_restrict_themes',
409
+ array_unique( array_merge( $aThemesRestrictions, array(
410
+ 'install_themes',
411
+ 'update_themes',
412
+ 'delete_themes'
413
+ ) ) )
414
  );
415
  }
416
 
422
  );
423
  }
424
  }
425
+ }
 
src/features/base.php CHANGED
@@ -70,6 +70,11 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_Foundation {
70
  */
71
  protected $oProcessor;
72
 
 
 
 
 
 
73
  /**
74
  * @var string
75
  */
@@ -101,7 +106,7 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_Foundation {
101
 
102
  $nRunPriority = isset( $aFeatureProperties[ 'load_priority' ] ) ? $aFeatureProperties[ 'load_priority' ] : 100;
103
  // Handle any upgrades as necessary (only go near this if it's the admin area)
104
- add_action( 'plugins_loaded', array( $this, 'onWpPluginsLoaded' ), $nRunPriority );
105
  add_action( 'init', array( $this, 'onWpInit' ), 1 );
106
  add_action( $this->prefix( 'import_options' ), array( $this, 'processImportOptions' ) );
107
  add_action( $this->prefix( 'form_submit' ), array( $this, 'handleFormSubmit' ) );
@@ -185,9 +190,8 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_Foundation {
185
  }
186
 
187
  /**
188
- * Added to WordPress 'plugins_loaded' hook
189
  */
190
- public function onWpPluginsLoaded() {
191
  $this->getOptionsVo()
192
  ->setIsPremiumLicensed( $this->isPremium() );
193
 
@@ -242,6 +246,7 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_Foundation {
242
  * A action added to WordPress 'init' hook
243
  */
244
  public function onWpInit() {
 
245
  $this->updateHandler();
246
  $this->setupAjaxHandlers();
247
  }
@@ -272,6 +277,15 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_Foundation {
272
  str_replace( ' ', '', ucwords( str_replace( '_', ' ', $this->getFeatureSlug() ) ) );
273
  }
274
 
 
 
 
 
 
 
 
 
 
275
  /**
276
  * @return ICWP_WPSF_OptionsVO
277
  */
@@ -343,7 +357,7 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_Foundation {
343
  /**
344
  * @return string
345
  */
346
- public function getFeatureAdminPageUrl() {
347
  return $this->loadWp()
348
  ->getUrl_AdminPage(
349
  $this->prefix( $this->getFeatureSlug() ),
@@ -683,16 +697,16 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_Foundation {
683
  $oDp = $this->loadDataProcessor();
684
 
685
  $bValid = $this->loadWp()->isAjax()
686
- && ( $this->prefix( $this->getFeatureSlug() ) == $oDp->FetchPost( 'icwp_action_module', '' ) );
687
  if ( $bValid ) {
688
  $aItems = array_keys( $this->getBaseAjaxActionRenderData() );
689
  foreach ( $aItems as $sKey ) {
690
  if ( strpos( $sKey, 'icwp_' ) === 0 ) {
691
- $bValid = $bValid && ( strlen( $oDp->FetchPost( $sKey, '' ) ) > 0 );
692
  }
693
  }
694
  }
695
- return $bValid && $this->checkNonceAction( $oDp->FetchPost( 'icwp_nonce' ), $oDp->FetchPost( 'icwp_nonce_action' ) );
696
  }
697
 
698
  /**
@@ -714,6 +728,21 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_Foundation {
714
 
715
  protected function adminAjaxHandlers() {
716
  add_action( 'wp_ajax_icwp_OptionsFormSave', array( $this, 'ajaxOptionsFormSave' ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
717
  }
718
 
719
  protected function frontEndAjaxHandlers() {
@@ -775,6 +804,21 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_Foundation {
775
  return $sDefault;
776
  }
777
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
778
  /**
779
  * @param $bSuccess
780
  * @param array $aData
@@ -884,7 +928,7 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_Foundation {
884
  }
885
 
886
  $aOptParams[ 'rows' ] = count( $mCurrentVal ) + 2;
887
- $mCurrentVal = implode( "\n", $mCurrentVal );
888
 
889
  break;
890
 
@@ -1137,6 +1181,31 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_Foundation {
1137
  protected function updateHandler() {
1138
  }
1139
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1140
  /**
1141
  * @return boolean
1142
  */
@@ -1263,9 +1332,15 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_Foundation {
1263
  'show_standard_options' => true,
1264
  'show_content_actions' => $this->hasCustomActions(),
1265
  'show_alt_content' => false,
 
 
1266
  ),
1267
  'hrefs' => array(
1268
- 'go_pro' => 'http://icwp.io/shieldgoprofeature'
 
 
 
 
1269
  ),
1270
  'content' => array(
1271
  'alt' => '',
@@ -1284,11 +1359,72 @@ abstract class ICWP_WPSF_FeatureHandler_Base extends ICWP_WPSF_Foundation {
1284
  return '<h3 style="margin: 10px 0 100px">'._wpsf__( 'No Actions For This Module' ).'</h3>';
1285
  }
1286
 
 
 
 
 
 
 
 
1287
  /**
1288
  * @return string
1289
  */
1290
  protected function getContentHelp() {
1291
- return $this->renderTemplate( 'snippets/module-help-'.$this->getFeatureSlug().'.php', array(), true );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1292
  }
1293
 
1294
  /**
70
  */
71
  protected $oProcessor;
72
 
73
+ /**
74
+ * @var ICWP_WPSF_Wizard_Base
75
+ */
76
+ protected $oWizard;
77
+
78
  /**
79
  * @var string
80
  */
106
 
107
  $nRunPriority = isset( $aFeatureProperties[ 'load_priority' ] ) ? $aFeatureProperties[ 'load_priority' ] : 100;
108
  // Handle any upgrades as necessary (only go near this if it's the admin area)
109
+ add_action( $this->prefix( 'run_processors' ), array( $this, 'onRunProcessors' ), $nRunPriority );
110
  add_action( 'init', array( $this, 'onWpInit' ), 1 );
111
  add_action( $this->prefix( 'import_options' ), array( $this, 'processImportOptions' ) );
112
  add_action( $this->prefix( 'form_submit' ), array( $this, 'handleFormSubmit' ) );
190
  }
191
 
192
  /**
 
193
  */
194
+ public function onRunProcessors() {
195
  $this->getOptionsVo()
196
  ->setIsPremiumLicensed( $this->isPremium() );
197
 
246
  * A action added to WordPress 'init' hook
247
  */
248
  public function onWpInit() {
249
+ $this->runWizards();
250
  $this->updateHandler();
251
  $this->setupAjaxHandlers();
252
  }
277
  str_replace( ' ', '', ucwords( str_replace( '_', ' ', $this->getFeatureSlug() ) ) );
278
  }
279
 
280
+ /**
281
+ * Override this and adapt per feature
282
+ * @return string
283
+ */
284
+ protected function getWizardClassName() {
285
+ return ucwords( self::getConn()->getOptionStoragePrefix() ).'Wizard_'.
286
+ str_replace( ' ', '', ucwords( str_replace( '_', ' ', $this->getFeatureSlug() ) ) );
287
+ }
288
+
289
  /**
290
  * @return ICWP_WPSF_OptionsVO
291
  */
357
  /**
358
  * @return string
359
  */
360
+ public function getUrl_AdminPage() {
361
  return $this->loadWp()
362
  ->getUrl_AdminPage(
363
  $this->prefix( $this->getFeatureSlug() ),
697
  $oDp = $this->loadDataProcessor();
698
 
699
  $bValid = $this->loadWp()->isAjax()
700
+ && ( $this->prefix( $this->getFeatureSlug() ) == $oDp->post( 'icwp_action_module', '' ) );
701
  if ( $bValid ) {
702
  $aItems = array_keys( $this->getBaseAjaxActionRenderData() );
703
  foreach ( $aItems as $sKey ) {
704
  if ( strpos( $sKey, 'icwp_' ) === 0 ) {
705
+ $bValid = $bValid && ( strlen( $oDp->post( $sKey, '' ) ) > 0 );
706
  }
707
  }
708
  }
709
+ return $bValid && $this->checkNonceAction( $oDp->post( 'icwp_nonce' ), $oDp->post( 'icwp_nonce_action' ) );
710
  }
711
 
712
  /**
728
 
729
  protected function adminAjaxHandlers() {
730
  add_action( 'wp_ajax_icwp_OptionsFormSave', array( $this, 'ajaxOptionsFormSave' ) );
731
+
732
+ // TODO: move this to the wizard handler itself
733
+ if ( $this->getCanRunWizards() && $this->hasWizard() ) {
734
+ $oWiz = $this->getWizardHandler();
735
+ if ( !is_null( $oWiz ) ) {
736
+ add_action( $this->prefixWpAjax( 'WizardProcessStepSubmit' ), array(
737
+ $oWiz,
738
+ 'ajaxWizardProcessStepSubmit'
739
+ ) );
740
+ add_action( $this->prefixWpAjax( 'WizardRenderStep' ), array(
741
+ $oWiz,
742
+ 'ajaxWizardRenderStep'
743
+ ) );
744
+ }
745
+ }
746
  }
747
 
748
  protected function frontEndAjaxHandlers() {
804
  return $sDefault;
805
  }
806
 
807
+ /**
808
+ * @return ICWP_WPSF_Wizard_Base|null
809
+ */
810
+ protected function getWizardHandler() {
811
+ if ( !isset( $this->oWizard ) ) {
812
+ include_once( self::getConn()->getPath_SourceFile( sprintf( 'wizards/%s.php', $this->getFeatureSlug() ) ) );
813
+ $sClassName = $this->getWizardClassName();
814
+ if ( !class_exists( $sClassName, false ) ) {
815
+ return null;
816
+ }
817
+ $this->oWizard = new $sClassName( $this );
818
+ }
819
+ return $this->oWizard;
820
+ }
821
+
822
  /**
823
  * @param $bSuccess
824
  * @param array $aData
928
  }
929
 
930
  $aOptParams[ 'rows' ] = count( $mCurrentVal ) + 2;
931
+ $mCurrentVal = stripslashes( implode( "\n", $mCurrentVal ) );
932
 
933
  break;
934
 
1181
  protected function updateHandler() {
1182
  }
1183
 
1184
+ /**
1185
+ */
1186
+ protected function runWizards() {
1187
+ if ( $this->getCanRunWizards() && $this->isWizardPage() && $this->hasWizard() ) {
1188
+ $oWiz = $this->getWizardHandler();
1189
+ if ( $oWiz instanceof ICWP_WPSF_Wizard_Base ) {
1190
+ $oWiz->init();
1191
+ }
1192
+ }
1193
+ }
1194
+
1195
+ /**
1196
+ * @return bool
1197
+ */
1198
+ protected function isModulePage() {
1199
+ return $this->loadDP()->query( 'page' ) == $this->prefix( $this->getFeatureSlug() );
1200
+ }
1201
+
1202
+ /**
1203
+ * @return bool
1204
+ */
1205
+ protected function isWizardPage() {
1206
+ return ( $this->loadDP()->query( 'shield_action' ) == 'wizard' && $this->isModulePage() );
1207
+ }
1208
+
1209
  /**
1210
  * @return boolean
1211
  */
1332
  'show_standard_options' => true,
1333
  'show_content_actions' => $this->hasCustomActions(),
1334
  'show_alt_content' => false,
1335
+ 'can_wizard' => $this->getCanRunWizards(),
1336
+ 'has_wizard' => $this->hasWizard(),
1337
  ),
1338
  'hrefs' => array(
1339
+ 'go_pro' => 'http://icwp.io/shieldgoprofeature',
1340
+ 'img_wizard_wand' => $oCon->getPluginUrl_Image( 'wand.png' ),
1341
+ 'wizard_link' => $this->getUrl_WizardLanding(),
1342
+ 'wizard_landing' => $this->getUrl_WizardLanding(),
1343
+ 'primary_wizard' => $this->getUrl_WizardPrimary(),
1344
  ),
1345
  'content' => array(
1346
  'alt' => '',
1359
  return '<h3 style="margin: 10px 0 100px">'._wpsf__( 'No Actions For This Module' ).'</h3>';
1360
  }
1361
 
1362
+ /**
1363
+ * @return bool
1364
+ */
1365
+ public function getCanRunWizards() {
1366
+ return $this->loadDP()->getPhpVersionIsAtLeast( '5.4.0' );
1367
+ }
1368
+
1369
  /**
1370
  * @return string
1371
  */
1372
  protected function getContentHelp() {
1373
+ return $this->renderTemplate( 'snippets/module-help-template.php', array( 'slug' => $this->getFeatureSlug() ) );
1374
+ }
1375
+
1376
+ /**
1377
+ * @return string|null
1378
+ */
1379
+ protected function getPrimaryWizard() {
1380
+ return $this->hasWizard() ? key( $this->getWizardDefinitions() ) : null;
1381
+ }
1382
+
1383
+ /**
1384
+ * @uses nonce
1385
+ * @param string $sWizardSlug
1386
+ * @return string
1387
+ */
1388
+ public function getUrl_Wizard( $sWizardSlug ) {
1389
+ return add_query_arg(
1390
+ array(
1391
+ 'page' => $this->prefix( $this->getFeatureSlug() ),
1392
+ 'shield_action' => 'wizard',
1393
+ 'wizard' => $sWizardSlug,
1394
+ 'nonwizard' => wp_create_nonce( 'wizard'.$sWizardSlug )
1395
+ ),
1396
+ $this->loadWp()->getHomeUrl()
1397
+ );
1398
+ }
1399
+
1400
+ /**
1401
+ * @return string
1402
+ */
1403
+ protected function getUrl_WizardLanding() {
1404
+ return $this->getUrl_Wizard( 'landing' );
1405
+ }
1406
+
1407
+ /**
1408
+ * @return string
1409
+ */
1410
+ protected function getUrl_WizardPrimary() {
1411
+ $sPrimary = $this->getPrimaryWizard();
1412
+ return $this->getUrl_Wizard( $sPrimary );
1413
+ }
1414
+
1415
+ /**
1416
+ * @return array
1417
+ */
1418
+ public function getWizardDefinitions() {
1419
+ $aW = $this->getDefinition( 'wizards' );
1420
+ return is_array( $aW ) ? $aW : array();
1421
+ }
1422
+
1423
+ /**
1424
+ * @return bool
1425
+ */
1426
+ public function hasWizard() {
1427
+ return ( count( $this->getWizardDefinitions() ) > 0 );
1428
  }
1429
 
1430
  /**
src/features/base_wpsf.php CHANGED
@@ -8,13 +8,6 @@ require_once( dirname( __FILE__ ).DIRECTORY_SEPARATOR.'base.php' );
8
 
9
  class ICWP_WPSF_FeatureHandler_BaseWpsf extends ICWP_WPSF_FeatureHandler_Base {
10
 
11
- /**
12
- * @return bool
13
- */
14
- public function getCanRunWizards() {
15
- return $this->loadDP()->getPhpVersionIsAtLeast( '5.4.0' );
16
- }
17
-
18
  /**
19
  * @return array
20
  */
@@ -95,7 +88,7 @@ class ICWP_WPSF_FeatureHandler_BaseWpsf extends ICWP_WPSF_FeatureHandler_Base {
95
  'aar_must_supply_key_first' => _wpsf__( 'At some point you entered a Security Admin Access Key - to manage this plugin, you must supply it here first.' ),
96
  'aar_to_manage_must_enter_key' => _wpsf__( 'To manage this plugin you must enter the access key.' ),
97
  'aar_enter_access_key' => _wpsf__( 'Enter Access Key' ),
98
- 'aar_submit_access_key' => _wpsf__( 'Submit Access Key' )
99
  )
100
  );
101
  $aData[ 'flags' ][ 'show_summary' ] = true;
@@ -110,20 +103,6 @@ class ICWP_WPSF_FeatureHandler_BaseWpsf extends ICWP_WPSF_FeatureHandler_Base {
110
  return ( isset( $aStrings[ $sKey ] ) ? $aStrings[ $sKey ] : $sDefault );
111
  }
112
 
113
- /**
114
- * @param string $sWizardSlug
115
- * @return string
116
- */
117
- public function getWizardUrl( $sWizardSlug ) {
118
- return add_query_arg(
119
- array(
120
- 'shield_action' => 'wizard',
121
- 'wizard' => $sWizardSlug
122
- ),
123
- $this->getFeatureAdminPageUrl()
124
- );
125
- }
126
-
127
  /**
128
  * @return bool
129
  */
8
 
9
  class ICWP_WPSF_FeatureHandler_BaseWpsf extends ICWP_WPSF_FeatureHandler_Base {
10
 
 
 
 
 
 
 
 
11
  /**
12
  * @return array
13
  */
88
  'aar_must_supply_key_first' => _wpsf__( 'At some point you entered a Security Admin Access Key - to manage this plugin, you must supply it here first.' ),
89
  'aar_to_manage_must_enter_key' => _wpsf__( 'To manage this plugin you must enter the access key.' ),
90
  'aar_enter_access_key' => _wpsf__( 'Enter Access Key' ),
91
+ 'aar_submit_access_key' => _wpsf__( 'Submit Security Admin Key' )
92
  )
93
  );
94
  $aData[ 'flags' ][ 'show_summary' ] = true;
103
  return ( isset( $aStrings[ $sKey ] ) ? $aStrings[ $sKey ] : $sDefault );
104
  }
105
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  /**
107
  * @return bool
108
  */
src/features/hack_protect.php CHANGED
@@ -15,6 +15,14 @@ class ICWP_WPSF_FeatureHandler_HackProtect extends ICWP_WPSF_FeatureHandler_Base
15
  return $this->getOpt( 'enable_unrecognised_file_cleaner_scan', 'disabled' );
16
  }
17
 
 
 
 
 
 
 
 
 
18
  /**
19
  * @return array
20
  */
@@ -26,6 +34,17 @@ class ICWP_WPSF_FeatureHandler_HackProtect extends ICWP_WPSF_FeatureHandler_Base
26
  return $aExclusions;
27
  }
28
 
 
 
 
 
 
 
 
 
 
 
 
29
  /**
30
  */
31
  protected function doExtraSubmitProcessing() {
@@ -42,7 +61,10 @@ class ICWP_WPSF_FeatureHandler_HackProtect extends ICWP_WPSF_FeatureHandler_Base
42
  foreach ( $this->getUfcFileExclusions() as $nKey => $sExclusion ) {
43
  $sExclusion = $oFS->normalizeFilePathDS( trim( $sExclusion ) );
44
 
45
- if ( strpos( $sExclusion, '/' ) === false ) { // filename only
 
 
 
46
  $sExclusion = trim( preg_replace( '#[^\.0-9a-z_-]#i', '', $sExclusion ) );
47
  }
48
 
@@ -51,7 +73,7 @@ class ICWP_WPSF_FeatureHandler_HackProtect extends ICWP_WPSF_FeatureHandler_Base
51
  }
52
  }
53
 
54
- return $this->setOpt( 'ufc_exclusions', $aExclusions );
55
  }
56
 
57
  /**
@@ -88,6 +110,36 @@ class ICWP_WPSF_FeatureHandler_HackProtect extends ICWP_WPSF_FeatureHandler_Base
88
  ) );
89
  }
90
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  /**
92
  * @param int $nId
93
  * @return $this
15
  return $this->getOpt( 'enable_unrecognised_file_cleaner_scan', 'disabled' );
16
  }
17
 
18
+ /**
19
+ * @param string $sOption
20
+ * @return $this
21
+ */
22
+ public function setUfcOption( $sOption ) {
23
+ return $this->setOpt( 'enable_unrecognised_file_cleaner_scan', $sOption );
24
+ }
25
+
26
  /**
27
  * @return array
28
  */
34
  return $aExclusions;
35
  }
36
 
37
+ /**
38
+ * @param array $aExclusions
39
+ * @return $this
40
+ */
41
+ public function setUfcFileExclusions( $aExclusions ) {
42
+ if ( !is_array( $aExclusions ) ) {
43
+ $aExclusions = array();
44
+ }
45
+ return $this->setOpt( 'ufc_exclusions', array_filter( array_map( 'trim', $aExclusions ) ) );
46
+ }
47
+
48
  /**
49
  */
50
  protected function doExtraSubmitProcessing() {
61
  foreach ( $this->getUfcFileExclusions() as $nKey => $sExclusion ) {
62
  $sExclusion = $oFS->normalizeFilePathDS( trim( $sExclusion ) );
63
 
64
+ if ( preg_match( '/^#(.+)#$/', $sExclusion, $aMatches ) ) { // it's regex
65
+ // ignore it
66
+ }
67
+ else if ( strpos( $sExclusion, '/' ) === false ) { // filename only
68
  $sExclusion = trim( preg_replace( '#[^\.0-9a-z_-]#i', '', $sExclusion ) );
69
  }
70
 
73
  }
74
  }
75
 
76
+ return $this->setOpt( 'ufc_exclusions', array_unique( $aExclusions ) );
77
  }
78
 
79
  /**
110
  ) );
111
  }
112
 
113
+ /**
114
+ * @return bool
115
+ */
116
+ public function isWcfScanAutoRepair() {
117
+ return $this->getOptIs( 'attempt_auto_file_repair', 'Y' );
118
+ }
119
+
120
+ /**
121
+ * @return bool
122
+ */
123
+ public function isWcfScanEnabled() {
124
+ return $this->getOptIs( 'enable_core_file_integrity_scan', 'Y' );
125
+ }
126
+
127
+ /**
128
+ * @param bool $bEnabled
129
+ * @return $this
130
+ */
131
+ public function setWcfScanEnabled( $bEnabled ) {
132
+ return $this->setOpt( 'enable_core_file_integrity_scan', $bEnabled ? 'Y' : 'N' );
133
+ }
134
+
135
+ /**
136
+ * @param bool $bEnabled
137
+ * @return $this
138
+ */
139
+ public function setWcfScanAutoRepair( $bEnabled ) {
140
+ return $this->setOpt( 'attempt_auto_file_repair', $bEnabled ? 'Y' : 'N' );
141
+ }
142
+
143
  /**
144
  * @param int $nId
145
  * @return $this
src/features/license.php CHANGED
@@ -442,7 +442,7 @@ class ICWP_WPSF_FeatureHandler_License extends ICWP_WPSF_FeatureHandler_BaseWpsf
442
  * @return bool
443
  */
444
  protected function isLastCheckExpired() {
445
- return ( $this->loadDataProcessor()->time() - $this->getLicenseLastCheckedAt()
446
  > $this->getDefinition( 'license_lack_check_expire_days' )*DAY_IN_SECONDS*( mt_rand( 20, 30 )/10 ) );
447
  }
448
 
442
  * @return bool
443
  */
444
  protected function isLastCheckExpired() {
445
+ return ( $this->loadDP()->time() - $this->getLicenseLastCheckedAt()
446
  > $this->getDefinition( 'license_lack_check_expire_days' )*DAY_IN_SECONDS*( mt_rand( 20, 30 )/10 ) );
447
  }
448
 
src/features/login_protect.php CHANGED
@@ -14,12 +14,11 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
14
  public function onWpInit() {
15
  parent::onWpInit();
16
 
17
- $oDp = $this->loadDataProcessor();
18
  // User has clicked a link in their email to verify they can send email.
19
- if ( $oDp->FetchGet( 'wpsf-action' ) == 'emailsendverify' ) {
20
- if ( $this->getTwoAuthSecretKey() == $oDp->FetchGet( 'authkey' ) ) {
21
  $this->setIfCanSendEmail( true )
22
- ->setBypassAdminProtection( true )
23
  ->savePluginOptions();
24
  $this->loadWp()->redirectToLogin();
25
  }
@@ -91,20 +90,32 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
91
  }
92
 
93
  /**
 
 
94
  * @return boolean
95
  */
96
- public function sendEmailVerifyCanSend() {
 
 
 
 
 
 
 
 
 
 
 
97
 
98
  $aMessage = array(
99
  _wpsf__( 'Before enabling 2-factor email authentication for your WordPress site, you must verify you can receive this email.' ),
100
  _wpsf__( 'This verifies your website can send email and that your account can receive emails sent from your site.' ),
101
- sprintf( _wpsf__( 'Verify Link: %s' ), $this->generateCanSendEmailVerifyLink() ),
102
  );
103
- $sEmailSubject = sprintf( _wpsf__( 'Email Sending Verification For %s' ), $this->loadWp()
104
- ->getHomeUrl() );
105
 
106
  $bResult = $this->getEmailProcessor()
107
- ->sendEmailTo( get_bloginfo( 'admin_email' ), $sEmailSubject, $aMessage );
108
  return $bResult;
109
  }
110
 
@@ -180,6 +191,13 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
180
  return $this->prefix( $this->getDefinition( 'two_factor_auth_table_name' ), '_' );
181
  }
182
 
 
 
 
 
 
 
 
183
  /**
184
  * @return string
185
  */
@@ -207,6 +225,13 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
207
  return $this->getIfCanSendEmail() && $this->getIsEmailAuthenticationOptionOn();
208
  }
209
 
 
 
 
 
 
 
 
210
  /**
211
  * @return bool
212
  */
@@ -253,6 +278,14 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
253
  return $this->getOptIs( 'enable_chained_authentication', 'Y' );
254
  }
255
 
 
 
 
 
 
 
 
 
256
  /**
257
  * @param bool $bCan
258
  * @return $this
@@ -269,6 +302,22 @@ class ICWP_WPSF_FeatureHandler_LoginProtect extends ICWP_WPSF_FeatureHandler_Bas
269
  return $this;
270
  }
271
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
  /**
273
  * @return string
274
  */
14
  public function onWpInit() {
15
  parent::onWpInit();
16
 
17
+ $oDp = $this->loadDP();
18
  // User has clicked a link in their email to verify they can send email.
19
+ if ( $oDp->query( 'wpsf-action' ) == 'emailsendverify' ) {
20
+ if ( $oDp->query( 'authkey' ) == $this->getCanEmailVerifyCode() ) {
21
  $this->setIfCanSendEmail( true )
 
22
  ->savePluginOptions();
23
  $this->loadWp()->redirectToLogin();
24
  }
90
  }
91
 
92
  /**
93
+ * @param string $sEmail
94
+ * @param bool $bSendAsLink
95
  * @return boolean
96
  */
97
+ public function sendEmailVerifyCanSend( $sEmail = null, $bSendAsLink = true ) {
98
+
99
+ if ( !$this->loadDP()->validEmail( $sEmail ) ) {
100
+ $sEmail = get_bloginfo( 'admin_email' );
101
+ }
102
+
103
+ if ( $bSendAsLink ) {
104
+ $sVerify = $this->generateCanSendEmailVerifyLink();
105
+ }
106
+ else {
107
+ $sVerify = $this->getCanEmailVerifyCode();
108
+ }
109
 
110
  $aMessage = array(
111
  _wpsf__( 'Before enabling 2-factor email authentication for your WordPress site, you must verify you can receive this email.' ),
112
  _wpsf__( 'This verifies your website can send email and that your account can receive emails sent from your site.' ),
113
+ sprintf( _wpsf__( 'Verify Code: %s' ), $sVerify ),
114
  );
115
+ $sEmailSubject = sprintf( _wpsf__( 'Email Sending Verification For %s' ), $this->loadWp()->getHomeUrl() );
 
116
 
117
  $bResult = $this->getEmailProcessor()
118
+ ->sendEmailTo( $sEmail, $sEmailSubject, $aMessage );
119
  return $bResult;
120
  }
121
 
191
  return $this->prefix( $this->getDefinition( 'two_factor_auth_table_name' ), '_' );
192
  }
193
 
194
+ /**
195
+ * @return string
196
+ */
197
+ public function getCanEmailVerifyCode() {
198
+ return strtoupper( substr( $this->getTwoAuthSecretKey(), 4, 6 ) );
199
+ }
200
+
201
  /**
202
  * @return string
203
  */
225
  return $this->getIfCanSendEmail() && $this->getIsEmailAuthenticationOptionOn();
226
  }
227
 
228
+ /**
229
+ * @return bool
230
+ */
231
+ public function getIsEnabledGoogleAuthenticator() {
232
+ return $this->getOptIs( 'enable_google_authenticator', 'Y' );
233
+ }
234
+
235
  /**
236
  * @return bool
237
  */
278
  return $this->getOptIs( 'enable_chained_authentication', 'Y' );
279
  }
280
 
281
+ /**
282
+ * @param bool $bIsChained
283
+ * @return $this
284
+ */
285
+ public function setIsChainedAuth( $bIsChained ) {
286
+ return $this->setOpt( 'enable_chained_authentication', $bIsChained ? 'Y' : 'N' );
287
+ }
288
+
289
  /**
290
  * @param bool $bCan
291
  * @return $this
302
  return $this;
303
  }
304
 
305
+ /**
306
+ * @param bool $bCan
307
+ * @return $this
308
+ */
309
+ public function setEnabled2FaEmail( $bCan ) {
310
+ return $this->setOpt( 'enable_email_authentication', $bCan ? 'Y' : 'N' );
311
+ }
312
+
313
+ /**
314
+ * @param bool $bCan
315
+ * @return $this
316
+ */
317
+ public function setEnabled2FaGoogleAuthenticator( $bCan ) {
318
+ return $this->setOpt( 'enable_google_authenticator', $bCan ? 'Y' : 'N' );
319
+ }
320
+
321
  /**
322
  * @return string
323
  */
src/features/plugin.php CHANGED
@@ -28,22 +28,6 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
28
  $this->getImportExportSecretKey();
29
  }
30
 
31
- protected function adminAjaxHandlers() {
32
- parent::adminAjaxHandlers();
33
-
34
- $oWizProc = $this->getWizardProcessor();
35
- if ( !is_null( $oWizProc ) ) {
36
- add_action( $this->prefixWpAjax( 'SetupWizardContent' ), array(
37
- $this->getWizardProcessor(),
38
- 'ajaxSetupWizardContent'
39
- ) );
40
- add_action( $this->prefixWpAjax( 'SetupWizardSteps' ), array(
41
- $this->getWizardProcessor(),
42
- 'ajaxSetupWizardSteps'
43
- ) );
44
- }
45
- }
46
-
47
  /**
48
  * @return string
49
  */
@@ -59,8 +43,8 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
59
  $aData = array(
60
  'strings' => $this->getDisplayStrings(),
61
  'hrefs' => array(
62
- 'wizard_welcome' => $bCanWizardWelcome ? $this->getWizardUrl( 'welcome' ) : 'javascript:{event.preventDefault();}',
63
- 'wizard_import' => $bCanWizardImport ? $this->getWizardUrl( 'import' ) : 'javascript:{event.preventDefault();}',
64
  ),
65
  'flags' => array(
66
  'can_php54' => $bCanWizard,
@@ -74,18 +58,6 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
74
  return $this->renderTemplate( 'snippets/module-plugin-actions', $aData );
75
  }
76
 
77
- /**
78
- * @return ICWP_WPSF_Processor_Plugin_SetupWizard|null
79
- */
80
- protected function getWizardProcessor() {
81
- if ( $this->loadDP()->getPhpVersionIsAtLeast( 5.4 ) ) {
82
- /** @var ICWP_WPSF_Processor_Plugin $oP */
83
- $oP = $this->getProcessor();
84
- return $oP->getWizardProcessor();
85
- }
86
- return null;
87
- }
88
-
89
  /**
90
  * @return ICWP_WPSF_Processor_Plugin_ImportExport
91
  */
@@ -149,7 +121,7 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
149
  protected function setVisitorIp() {
150
  $sIp = null;
151
  $oIpService = $this->loadIpService();
152
- $oDp = $this->loadDataProcessor();
153
 
154
  if ( !$this->isVisitorAddressSourceAutoDetect() ) {
155
 
@@ -168,8 +140,8 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
168
  $sSource = $oIpService->setServerIpAddress( $this->getMyServerIp() )
169
  ->discoverViableRequestIpSource();
170
  if ( !empty( $sSource ) ) {
171
- $oIpService->setRequestIpAddress( $this->loadDataProcessor()->FetchServer( $sSource ) );
172
- $this->setOpt( 'visitor_address_source', $sSource );
173
  }
174
  }
175
  }
@@ -181,6 +153,14 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
181
  return $this->getOpt( 'visitor_address_source' );
182
  }
183
 
 
 
 
 
 
 
 
 
184
  /**
185
  * @return string
186
  */
@@ -643,7 +623,13 @@ class ICWP_WPSF_FeatureHandler_Plugin extends ICWP_WPSF_FeatureHandler_BaseWpsf
643
  )
644
  );
645
  $sBadgeText = apply_filters( 'icwp_shield_plugin_badge_text', $sBadgeText );
646
- return sprintf( $sContents, $oCon->getPluginUrl_Image( 'pluginlogo_32x32.png' ), $oCon->getHumanName(), $sBadgeText );
 
 
 
 
 
 
647
  }
648
 
649
  /**
28
  $this->getImportExportSecretKey();
29
  }
30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  /**
32
  * @return string
33
  */
43
  $aData = array(
44
  'strings' => $this->getDisplayStrings(),
45
  'hrefs' => array(
46
+ 'wizard_welcome' => $bCanWizardWelcome ? $this->getUrl_Wizard( 'welcome' ) : 'javascript:{event.preventDefault();}',
47
+ 'wizard_import' => $bCanWizardImport ? $this->getUrl_Wizard( 'import' ) : 'javascript:{event.preventDefault();}',
48
  ),
49
  'flags' => array(
50
  'can_php54' => $bCanWizard,
58
  return $this->renderTemplate( 'snippets/module-plugin-actions', $aData );
59
  }
60
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  /**
62
  * @return ICWP_WPSF_Processor_Plugin_ImportExport
63
  */
121
  protected function setVisitorIp() {
122
  $sIp = null;
123
  $oIpService = $this->loadIpService();
124
+ $oDp = $this->loadDP();
125
 
126
  if ( !$this->isVisitorAddressSourceAutoDetect() ) {
127
 
140
  $sSource = $oIpService->setServerIpAddress( $this->getMyServerIp() )
141
  ->discoverViableRequestIpSource();
142
  if ( !empty( $sSource ) ) {
143
+ $oIpService->setRequestIpAddress( $oDp->FetchServer( $sSource ) );
144
+ $this->setVisitorAddressSource( $sSource );
145
  }
146
  }
147
  }
153
  return $this->getOpt( 'visitor_address_source' );
154
  }
155
 
156
+ /**
157
+ * @param string $sSource
158
+ * @return $this
159
+ */
160
+ public function setVisitorAddressSource( $sSource ) {
161
+ return $this->setOpt( 'visitor_address_source', $sSource );
162
+ }
163
+
164
  /**
165
  * @return string
166
  */
623
  )
624
  );
625
  $sBadgeText = apply_filters( 'icwp_shield_plugin_badge_text', $sBadgeText );
626
+ $bNoFollow = apply_filters( 'icwp_shield_badge_relnofollow', false );
627
+ return sprintf( $sContents,
628
+ $bNoFollow ? 'rel="nofollow"' : '',
629
+ $oCon->getPluginUrl_Image( 'pluginlogo_32x32.png' ),
630
+ $oCon->getHumanName(),
631
+ $sBadgeText
632
+ );
633
  }
634
 
635
  /**
src/processors/admin_access_restriction.php CHANGED
@@ -175,7 +175,7 @@ if ( !class_exists( 'ICWP_WPSF_Processor_AdminAccessRestriction', false ) ):
175
  'hrefs' => array(
176
  'setting_page' => sprintf(
177
  '<a href="%s" title="%s">%s</a>',
178
- $oFO->getFeatureAdminPageUrl(),
179
  _wpsf__( 'Admin Access Login' ),
180
  sprintf( _wpsf__('Go here to manage settings and authenticate with the %s plugin.'), $this->getController()->getHumanName() )
181
  )
@@ -210,7 +210,7 @@ if ( !class_exists( 'ICWP_WPSF_Processor_AdminAccessRestriction', false ) ):
210
  'hrefs' => array(
211
  'setting_page' => sprintf(
212
  '<a href="%s" title="%s">%s</a>',
213
- $oFO->getFeatureAdminPageUrl(),
214
  _wpsf__( 'Security Admin Login' ),
215
  sprintf( _wpsf__('Go here to manage settings and authenticate with the %s plugin.'), $this->getController()->getHumanName() )
216
  )
175
  'hrefs' => array(
176
  'setting_page' => sprintf(
177
  '<a href="%s" title="%s">%s</a>',
178
+ $oFO->getUrl_AdminPage(),
179
  _wpsf__( 'Admin Access Login' ),
180
  sprintf( _wpsf__('Go here to manage settings and authenticate with the %s plugin.'), $this->getController()->getHumanName() )
181
  )
210
  'hrefs' => array(
211
  'setting_page' => sprintf(
212
  '<a href="%s" title="%s">%s</a>',
213
+ $oFO->getUrl_AdminPage(),
214
  _wpsf__( 'Security Admin Login' ),
215
  sprintf( _wpsf__('Go here to manage settings and authenticate with the %s plugin.'), $this->getController()->getHumanName() )
216
  )
src/processors/base.php CHANGED
@@ -122,7 +122,6 @@ abstract class ICWP_WPSF_Processor_Base extends ICWP_WPSF_Foundation {
122
  }
123
 
124
  /**
125
- * Resets the object values to be re-used anew
126
  */
127
  public function init() {
128
  }
@@ -171,8 +170,8 @@ abstract class ICWP_WPSF_Processor_Base extends ICWP_WPSF_Foundation {
171
  }
172
 
173
  /**
174
- * @param string $sKey
175
- * @param mixed $mValueToTest
176
  * @param boolean $bStrict
177
  * @return bool
178
  */
122
  }
123
 
124
  /**
 
125
  */
126
  public function init() {
127
  }
170
  }
171
 
172
  /**
173
+ * @param string $sKey
174
+ * @param mixed $mValueToTest
175
  * @param boolean $bStrict
176
  * @return bool
177
  */
src/processors/base_plugin.php CHANGED
@@ -92,7 +92,7 @@ class ICWP_WPSF_Processor_BasePlugin extends ICWP_WPSF_Processor_BaseWpsf {
92
  'no_setup' => _wpsf__( 'Unfortunately your site is running a PHP version that is too low to run the Setup Wizard. It needs to be PHP 5.4+' )
93
  ),
94
  'hrefs' => array(
95
- 'wizard' => $bCanWizardWelcome ? $oFO->getWizardUrl( 'welcome' ) : 'javascript:{event.preventDefault();}',
96
  ),
97
  'flags' => array(
98
  'can_wizard' => $bCanWizardWelcome,
@@ -102,6 +102,7 @@ class ICWP_WPSF_Processor_BasePlugin extends ICWP_WPSF_Processor_BaseWpsf {
102
  }
103
 
104
  /**
 
105
  * @see autoAddToAdminNotices()
106
  * @param array $aAttr
107
  * @throws Exception
92
  'no_setup' => _wpsf__( 'Unfortunately your site is running a PHP version that is too low to run the Setup Wizard. It needs to be PHP 5.4+' )
93
  ),
94
  'hrefs' => array(
95
+ 'wizard' => $bCanWizardWelcome ? $oFO->getUrl_Wizard( 'welcome' ) : 'javascript:{event.preventDefault();}',
96
  ),
97
  'flags' => array(
98
  'can_wizard' => $bCanWizardWelcome,
102
  }
103
 
104
  /**
105
+ * removed
106
  * @see autoAddToAdminNotices()
107
  * @param array $aAttr
108
  * @throws Exception
src/processors/base_wpsf.php CHANGED
@@ -22,6 +22,7 @@ abstract class ICWP_WPSF_Processor_BaseWpsf extends ICWP_WPSF_Processor_Base {
22
  * Resets the object values to be re-used anew
23
  */
24
  public function init() {
 
25
  $oFO = $this->getFeature();
26
  add_filter( $oFO->prefix( 'collect_audit_trail' ), array( $this, 'audit_Collect' ) );
27
  add_filter( $oFO->prefix( 'collect_stats' ), array( $this, 'stats_Collect' ) );
22
  * Resets the object values to be re-used anew
23
  */
24
  public function init() {
25
+ parent::init();
26
  $oFO = $this->getFeature();
27
  add_filter( $oFO->prefix( 'collect_audit_trail' ), array( $this, 'audit_Collect' ) );
28
  add_filter( $oFO->prefix( 'collect_stats' ), array( $this, 'stats_Collect' ) );
src/processors/email.php CHANGED
@@ -4,34 +4,39 @@ if ( class_exists( 'ICWP_WPSF_Processor_Email', false ) ) {
4
  return;
5
  }
6
 
7
- require_once( dirname(__FILE__).DIRECTORY_SEPARATOR.'base_wpsf.php' );
8
 
9
  class ICWP_WPSF_Processor_Email extends ICWP_WPSF_Processor_BaseWpsf {
10
 
11
  const Slug = 'email';
12
-
13
  protected $m_sRecipientAddress;
14
 
15
  /**
16
  * @var string
17
  */
18
  static protected $sModeFile_EmailThrottled;
 
19
  /**
20
  * @var int
21
  */
22
- static protected $nThrottleInterval = 1;
 
23
  /**
24
  * @var int
25
  */
26
  protected $m_nEmailThrottleLimit;
 
27
  /**
28
  * @var int
29
  */
30
  protected $m_nEmailThrottleTime;
 
31
  /**
32
  * @var int
33
  */
34
  protected $m_nEmailThrottleCount;
 
35
  /**
36
  * @var boolean
37
  */
@@ -43,20 +48,22 @@ class ICWP_WPSF_Processor_Email extends ICWP_WPSF_Processor_BaseWpsf {
43
  public function __construct( ICWP_WPSF_FeatureHandler_Email $oFeatureOptions ) {
44
  parent::__construct( $oFeatureOptions );
45
  }
46
-
47
  public function init() {
48
  parent::init();
49
  self::$sModeFile_EmailThrottled = dirname( __FILE__ ).'/../mode.email_throttled';
50
  }
51
 
52
- public function run() {}
 
53
 
54
  /**
55
  * @return array
56
  */
57
  protected function getEmailHeader() {
58
  return array(
59
- _wpsf__('Hi !'), '',
 
60
  );
61
  }
62
 
@@ -64,16 +71,17 @@ class ICWP_WPSF_Processor_Email extends ICWP_WPSF_Processor_BaseWpsf {
64
  * @return array
65
  */
66
  protected function getEmailFooter() {
 
67
  $sUrl = array(
68
- '', '',
69
- sprintf(
70
- _wpsf__( 'This email was sent from the %s plugin, provided by %s.' ),
71
  $this->getController()->getHumanName(),
72
- sprintf( '<a href="%s"><strong>%s</strong></a>', 'http://icwp.io/shieldicontrolwpemailfooter', 'iControlWP - WordPress Management and Backup Protection For Professionals' )
 
73
  ),
74
- '',
75
- sprintf( _wpsf__( 'WordPress Site URL- %s.' ), $this->loadWp()->getHomeUrl() )
76
- .' / ' .sprintf( _wpsf__( 'Current Plugin Version- %s.' ), $this->getController()->getVersion() ),
77
  );
78
 
79
  return apply_filters( 'icwp_shield_email_footer', $sUrl );
@@ -82,7 +90,7 @@ class ICWP_WPSF_Processor_Email extends ICWP_WPSF_Processor_BaseWpsf {
82
  /**
83
  * @param string $sEmailAddress
84
  * @param string $sEmailSubject
85
- * @param array $aMessage
86
  * @return boolean
87
  * @uses wp_mail
88
  */
@@ -94,12 +102,6 @@ class ICWP_WPSF_Processor_Email extends ICWP_WPSF_Processor_BaseWpsf {
94
 
95
  $sEmailTo = $this->verifyEmailAddress( $sEmailAddress );
96
 
97
- $aHeaders = array(
98
- 'MIME-Version: 1.0',
99
- 'Content-type: text/html;',
100
- 'X-Mailer: PHP/'.phpversion()
101
- );
102
-
103
  $this->updateEmailThrottle();
104
  // We make it appear to have "succeeded" if the throttle is applied.
105
  if ( $this->fEmailIsThrottled ) {
@@ -108,15 +110,24 @@ class ICWP_WPSF_Processor_Email extends ICWP_WPSF_Processor_BaseWpsf {
108
 
109
  $aMessage = array_merge( $this->getEmailHeader(), $aMessage, $this->getEmailFooter() );
110
 
111
- $bSuccess = wp_mail( $sEmailTo, $sEmailSubject, implode( "<br />", $aMessage ), implode( "\r\n", $aHeaders ) );
 
112
 
113
  // Remove our Filters for From
114
  remove_filter( 'wp_mail_from', array( $this, 'setMailFrom' ), 100 );
115
  remove_filter( 'wp_mail_from_name', array( $this, 'setMailFromName' ), 100 );
 
116
 
117
  return $bSuccess;
118
  }
119
 
 
 
 
 
 
 
 
120
  /**
121
  * @param string $sFrom
122
  * @return string
@@ -132,7 +143,7 @@ class ICWP_WPSF_Processor_Email extends ICWP_WPSF_Processor_BaseWpsf {
132
  if ( !$oDP->validEmail( $sFrom ) ) {
133
  $aUrlParts = @parse_url( $this->loadWp()->getWpUrl() );
134
  if ( !empty( $aUrlParts[ 'host' ] ) ) {
135
- $sProposedFrom = 'wordpress@' . $aUrlParts[ 'host' ];
136
  if ( $oDP->validEmail( $sProposedFrom ) ) {
137
  $sFrom = $sProposedFrom;
138
  }
@@ -158,9 +169,8 @@ class ICWP_WPSF_Processor_Email extends ICWP_WPSF_Processor_BaseWpsf {
158
 
159
  /**
160
  * Will send email to the default recipient setup in the object.
161
- *
162
  * @param string $sEmailSubject
163
- * @param array $aMessage
164
  * @return boolean
165
  */
166
  public function sendEmail( $sEmailSubject, $aMessage ) {
@@ -170,9 +180,7 @@ class ICWP_WPSF_Processor_Email extends ICWP_WPSF_Processor_BaseWpsf {
170
  /**
171
  * Whether we're throttled is dependent on 2 signals. The time interval has changed, or the there's a file
172
  * system object telling us we're throttled.
173
- *
174
  * The file system object takes precedence.
175
- *
176
  * @return boolean
177
  */
178
  protected function updateEmailThrottle() {
@@ -182,7 +190,7 @@ class ICWP_WPSF_Processor_Email extends ICWP_WPSF_Processor_BaseWpsf {
182
  $this->setThrottledFile( false );
183
  return $this->fEmailIsThrottled;
184
  }
185
-
186
  // Check that there is an email throttle file. If it exists and its modified time is greater than the
187
  // current $this->m_nEmailThrottleTime it suggests another process has touched the file and updated it
188
  // concurrently. So, we update our $this->m_nEmailThrottleTime accordingly.
@@ -192,19 +200,19 @@ class ICWP_WPSF_Processor_Email extends ICWP_WPSF_Processor_BaseWpsf {
192
  $this->m_nEmailThrottleTime = $nModifiedTime;
193
  }
194
  }
195
-
196
- if ( !isset($this->m_nEmailThrottleTime) || $this->m_nEmailThrottleTime > $this->time() ) {
197
  $this->m_nEmailThrottleTime = $this->time();
198
  }
199
- if ( !isset($this->m_nEmailThrottleCount) ) {
200
  $this->m_nEmailThrottleCount = 0;
201
  }
202
-
203
  // If $nNow is greater than throttle interval (1s) we turn off the file throttle and reset the count
204
  $nDiff = $this->time() - $this->m_nEmailThrottleTime;
205
  if ( $nDiff > self::$nThrottleInterval ) {
206
  $this->m_nEmailThrottleTime = $this->time();
207
- $this->m_nEmailThrottleCount = 1; //we set to 1 assuming that this was called because we're about to send, or have just sent, an email.
208
  $this->setThrottledFile( false );
209
  }
210
  else if ( is_file( self::$sModeFile_EmailThrottled ) || ( $this->m_nEmailThrottleCount >= $this->getThrottleLimit() ) ) {
@@ -214,19 +222,19 @@ class ICWP_WPSF_Processor_Email extends ICWP_WPSF_Processor_BaseWpsf {
214
  $this->m_nEmailThrottleCount++;
215
  }
216
  }
217
-
218
  public function setThrottledFile( $infOn = false ) {
219
-
220
  $this->fEmailIsThrottled = $infOn;
221
-
222
- if ( $infOn && !is_file( self::$sModeFile_EmailThrottled ) && function_exists('touch') ) {
223
  @touch( self::$sModeFile_EmailThrottled );
224
  }
225
- else if ( !$infOn && is_file(self::$sModeFile_EmailThrottled) ) {
226
  @unlink( self::$sModeFile_EmailThrottled );
227
  }
228
  }
229
-
230
  public function setDefaultRecipientAddress( $insEmailAddress ) {
231
  $this->m_sRecipientAddress = $insEmailAddress;
232
  }
@@ -236,7 +244,8 @@ class ICWP_WPSF_Processor_Email extends ICWP_WPSF_Processor_BaseWpsf {
236
  * @return string
237
  */
238
  public function verifyEmailAddress( $sEmailAddress = '' ) {
239
- return $this->loadDataProcessor()->validEmail( $sEmailAddress ) ? $sEmailAddress : $this->getPluginDefaultRecipientAddress();
 
240
  }
241
 
242
  /**
@@ -245,7 +254,7 @@ class ICWP_WPSF_Processor_Email extends ICWP_WPSF_Processor_BaseWpsf {
245
  public function getSiteName() {
246
  return $this->loadWp()->getSiteName();
247
  }
248
-
249
  public function getThrottleLimit() {
250
  if ( empty( $this->m_nEmailThrottleLimit ) ) {
251
  $this->m_nEmailThrottleLimit = $this->getOption( 'send_email_throttle_limit' );
4
  return;
5
  }
6
 
7
+ require_once( dirname( __FILE__ ).DIRECTORY_SEPARATOR.'base_wpsf.php' );
8
 
9
  class ICWP_WPSF_Processor_Email extends ICWP_WPSF_Processor_BaseWpsf {
10
 
11
  const Slug = 'email';
12
+
13
  protected $m_sRecipientAddress;
14
 
15
  /**
16
  * @var string
17
  */
18
  static protected $sModeFile_EmailThrottled;
19
+
20
  /**
21
  * @var int
22
  */
23
+ static protected $nThrottleInterval = 1;
24
+
25
  /**
26
  * @var int
27
  */
28
  protected $m_nEmailThrottleLimit;
29
+
30
  /**
31
  * @var int
32
  */
33
  protected $m_nEmailThrottleTime;
34
+
35
  /**
36
  * @var int
37
  */
38
  protected $m_nEmailThrottleCount;
39
+
40
  /**
41
  * @var boolean
42
  */
48
  public function __construct( ICWP_WPSF_FeatureHandler_Email $oFeatureOptions ) {
49
  parent::__construct( $oFeatureOptions );
50
  }
51
+
52
  public function init() {
53
  parent::init();
54
  self::$sModeFile_EmailThrottled = dirname( __FILE__ ).'/../mode.email_throttled';
55
  }
56
 
57
+ public function run() {
58
+ }
59
 
60
  /**
61
  * @return array
62
  */
63
  protected function getEmailHeader() {
64
  return array(
65
+ _wpsf__( 'Hi !' ),
66
+ '',
67
  );
68
  }
69
 
71
  * @return array
72
  */
73
  protected function getEmailFooter() {
74
+ $oWp = $this->loadWp();
75
  $sUrl = array(
76
+ '',
77
+ sprintf( _wpsf__( 'This email was sent from the %s Plugin v%s, on %s.' ),
 
78
  $this->getController()->getHumanName(),
79
+ $this->getController()->getVersion(),
80
+ $this->loadWp()->getHomeUrl()
81
  ),
82
+ _wpsf__( 'Note: delays in receiving emails are caused by your website hosting and email providers.' ),
83
+ sprintf( _wpsf__( 'Time Sent: %s' ), $oWp->getTimeStampForDisplay( time() ) )
84
+ // sprintf( '<a href="%s"><strong>%s</strong></a>', 'http://icwp.io/shieldicontrolwpemailfooter', 'iControlWP - WordPress Management and Backup Protection For Professionals' )
85
  );
86
 
87
  return apply_filters( 'icwp_shield_email_footer', $sUrl );
90
  /**
91
  * @param string $sEmailAddress
92
  * @param string $sEmailSubject
93
+ * @param array $aMessage
94
  * @return boolean
95
  * @uses wp_mail
96
  */
102
 
103
  $sEmailTo = $this->verifyEmailAddress( $sEmailAddress );
104
 
 
 
 
 
 
 
105
  $this->updateEmailThrottle();
106
  // We make it appear to have "succeeded" if the throttle is applied.
107
  if ( $this->fEmailIsThrottled ) {
110
 
111
  $aMessage = array_merge( $this->getEmailHeader(), $aMessage, $this->getEmailFooter() );
112
 
113
+ add_filter( 'wp_mail_content_type', array( $this, 'setMailContentType' ), 100, 0 );
114
+ $bSuccess = wp_mail( $sEmailTo, $sEmailSubject, '<html>'.implode( "<br />", $aMessage ).'</html>' );
115
 
116
  // Remove our Filters for From
117
  remove_filter( 'wp_mail_from', array( $this, 'setMailFrom' ), 100 );
118
  remove_filter( 'wp_mail_from_name', array( $this, 'setMailFromName' ), 100 );
119
+ remove_filter( 'wp_mail_content_type', array( $this, 'setMailContentType' ), 100 );
120
 
121
  return $bSuccess;
122
  }
123
 
124
+ /**
125
+ * @return string
126
+ */
127
+ public function setMailContentType() {
128
+ return 'text/html';
129
+ }
130
+
131
  /**
132
  * @param string $sFrom
133
  * @return string
143
  if ( !$oDP->validEmail( $sFrom ) ) {
144
  $aUrlParts = @parse_url( $this->loadWp()->getWpUrl() );
145
  if ( !empty( $aUrlParts[ 'host' ] ) ) {
146
+ $sProposedFrom = 'wordpress@'.$aUrlParts[ 'host' ];
147
  if ( $oDP->validEmail( $sProposedFrom ) ) {
148
  $sFrom = $sProposedFrom;
149
  }
169
 
170
  /**
171
  * Will send email to the default recipient setup in the object.
 
172
  * @param string $sEmailSubject
173
+ * @param array $aMessage
174
  * @return boolean
175
  */
176
  public function sendEmail( $sEmailSubject, $aMessage ) {
180
  /**
181
  * Whether we're throttled is dependent on 2 signals. The time interval has changed, or the there's a file
182
  * system object telling us we're throttled.
 
183
  * The file system object takes precedence.
 
184
  * @return boolean
185
  */
186
  protected function updateEmailThrottle() {
190
  $this->setThrottledFile( false );
191
  return $this->fEmailIsThrottled;
192
  }
193
+
194
  // Check that there is an email throttle file. If it exists and its modified time is greater than the
195
  // current $this->m_nEmailThrottleTime it suggests another process has touched the file and updated it
196
  // concurrently. So, we update our $this->m_nEmailThrottleTime accordingly.
200
  $this->m_nEmailThrottleTime = $nModifiedTime;
201
  }
202
  }
203
+
204
+ if ( !isset( $this->m_nEmailThrottleTime ) || $this->m_nEmailThrottleTime > $this->time() ) {
205
  $this->m_nEmailThrottleTime = $this->time();
206
  }
207
+ if ( !isset( $this->m_nEmailThrottleCount ) ) {
208
  $this->m_nEmailThrottleCount = 0;
209
  }
210
+
211
  // If $nNow is greater than throttle interval (1s) we turn off the file throttle and reset the count
212
  $nDiff = $this->time() - $this->m_nEmailThrottleTime;
213
  if ( $nDiff > self::$nThrottleInterval ) {
214
  $this->m_nEmailThrottleTime = $this->time();
215
+ $this->m_nEmailThrottleCount = 1; //we set to 1 assuming that this was called because we're about to send, or have just sent, an email.
216
  $this->setThrottledFile( false );
217
  }
218
  else if ( is_file( self::$sModeFile_EmailThrottled ) || ( $this->m_nEmailThrottleCount >= $this->getThrottleLimit() ) ) {
222
  $this->m_nEmailThrottleCount++;
223
  }
224
  }
225
+
226
  public function setThrottledFile( $infOn = false ) {
227
+
228
  $this->fEmailIsThrottled = $infOn;
229
+
230
+ if ( $infOn && !is_file( self::$sModeFile_EmailThrottled ) && function_exists( 'touch' ) ) {
231
  @touch( self::$sModeFile_EmailThrottled );
232
  }
233
+ else if ( !$infOn && is_file( self::$sModeFile_EmailThrottled ) ) {
234
  @unlink( self::$sModeFile_EmailThrottled );
235
  }
236
  }
237
+
238
  public function setDefaultRecipientAddress( $insEmailAddress ) {
239
  $this->m_sRecipientAddress = $insEmailAddress;
240
  }
244
  * @return string
245
  */
246
  public function verifyEmailAddress( $sEmailAddress = '' ) {
247
+ return $this->loadDataProcessor()
248
+ ->validEmail( $sEmailAddress ) ? $sEmailAddress : $this->getPluginDefaultRecipientAddress();
249
  }
250
 
251
  /**
254
  public function getSiteName() {
255
  return $this->loadWp()->getSiteName();
256
  }
257
+
258
  public function getThrottleLimit() {
259
  if ( empty( $this->m_nEmailThrottleLimit ) ) {
260
  $this->m_nEmailThrottleLimit = $this->getOption( 'send_email_throttle_limit' );
src/processors/hack_protect.php CHANGED
@@ -23,7 +23,7 @@ class ICWP_WPSF_Processor_HackProtect extends ICWP_WPSF_Processor_BaseWpsf {
23
  // not probably necessary any longer since it's patched in the Core
24
  add_filter( 'pre_comment_content', array( $this, 'secXss64kb' ), 0, 1 );
25
 
26
- if ( $this->getIsOption( 'enable_core_file_integrity_scan', 'Y' ) ) {
27
  $this->runChecksumScan();
28
  }
29
  if ( $oFO->isUfsEnabled() ) {
@@ -75,7 +75,7 @@ class ICWP_WPSF_Processor_HackProtect extends ICWP_WPSF_Processor_BaseWpsf {
75
  /**
76
  * @return ICWP_WPSF_Processor_HackProtect_CoreChecksumScan
77
  */
78
- protected function getSubProcessorChecksumScan() {
79
  $oProc = $this->getSubProcessor( 'checksum' );
80
  if ( is_null( $oProc ) ) {
81
  require_once( dirname( __FILE__ ).DIRECTORY_SEPARATOR.'hackprotect_corechecksumscan.php' );
@@ -88,7 +88,7 @@ class ICWP_WPSF_Processor_HackProtect extends ICWP_WPSF_Processor_BaseWpsf {
88
  /**
89
  * @return ICWP_WPSF_Processor_HackProtect_FileCleanerScan
90
  */
91
- protected function getSubProcessorFileCleanerScan() {
92
  $oProc = $this->getSubProcessor( 'cleaner' );
93
  if ( is_null( $oProc ) ) {
94
  require_once( dirname( __FILE__ ).DIRECTORY_SEPARATOR.'hackprotect_filecleanerscan.php' );
23
  // not probably necessary any longer since it's patched in the Core
24
  add_filter( 'pre_comment_content', array( $this, 'secXss64kb' ), 0, 1 );
25
 
26
+ if ( $oFO->isWcfScanEnabled() ) {
27
  $this->runChecksumScan();
28
  }
29
  if ( $oFO->isUfsEnabled() ) {
75
  /**
76
  * @return ICWP_WPSF_Processor_HackProtect_CoreChecksumScan
77
  */
78
+ public function getSubProcessorChecksumScan() {
79
  $oProc = $this->getSubProcessor( 'checksum' );
80
  if ( is_null( $oProc ) ) {
81
  require_once( dirname( __FILE__ ).DIRECTORY_SEPARATOR.'hackprotect_corechecksumscan.php' );
88
  /**
89
  * @return ICWP_WPSF_Processor_HackProtect_FileCleanerScan
90
  */
91
+ public function getSubProcessorFileCleanerScan() {
92
  $oProc = $this->getSubProcessor( 'cleaner' );
93
  if ( is_null( $oProc ) ) {
94
  require_once( dirname( __FILE__ ).DIRECTORY_SEPARATOR.'hackprotect_filecleanerscan.php' );
src/processors/hackprotect_corechecksumscan.php CHANGED
@@ -274,6 +274,19 @@ class ICWP_WPSF_Processor_HackProtect_CoreChecksumScan extends ICWP_WPSF_Process
274
  . ' [<a href="http://icwp.io/moreinfochecksum">' . _wpsf__( 'More Info' ) . ']</a>';
275
  }
276
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
  $sRecipient = $this->getPluginDefaultRecipientAddress();
278
  $sEmailSubject = sprintf( _wpsf__( 'Warning - %s' ), _wpsf__( 'Core WordPress Files(s) Discovered That May Have Been Modified.' ) );
279
  $bSendSuccess = $this->getEmailProcessor()->sendEmailTo( $sRecipient, $sEmailSubject, $aContent );
274
  . ' [<a href="http://icwp.io/moreinfochecksum">' . _wpsf__( 'More Info' ) . ']</a>';
275
  }
276
 
277
+ $aContent[] = '';
278
+
279
+ /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
280
+ $oFO = $this->getFeature();
281
+ if ( $oFO->getCanRunWizards() ) {
282
+ $aContent[] = sprintf( '<a href="%s" target="_blank" style="%s">%s →</a>',
283
+ $oFO->getUrl_Wizard( 'wcf' ),
284
+ 'border:1px solid;padding:20px;line-height:19px;margin:10px 20px;display:inline-block;text-align:center;width:290px;font-size:18px;',
285
+ _wpsf__( 'Run the scanner manually' )
286
+ );
287
+ $aContent[] = '';
288
+ }
289
+
290
  $sRecipient = $this->getPluginDefaultRecipientAddress();
291
  $sEmailSubject = sprintf( _wpsf__( 'Warning - %s' ), _wpsf__( 'Core WordPress Files(s) Discovered That May Have Been Modified.' ) );
292
  $bSendSuccess = $this->getEmailProcessor()->sendEmailTo( $sRecipient, $sEmailSubject, $aContent );
src/processors/hackprotect_filecleanerscan.php CHANGED
@@ -4,7 +4,7 @@ if ( class_exists( 'ICWP_WPSF_Processor_HackProtect_FileCleanerScan', false ) )
4
  return;
5
  }
6
 
7
- require_once( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'base_wpsf.php' );
8
 
9
  class ICWP_WPSF_Processor_HackProtect_FileCleanerScan extends ICWP_WPSF_Processor_BaseWpsf {
10
 
@@ -19,17 +19,16 @@ class ICWP_WPSF_Processor_HackProtect_FileCleanerScan extends ICWP_WPSF_Processo
19
  $this->setupChecksumCron();
20
 
21
  if ( $this->loadWpUsers()->isUserAdmin() ) {
22
- $oDp = $this->loadDataProcessor();
23
 
24
- if ( $oDp->FetchGet( 'force_filecleanscan' ) == 1 ) {
25
  $this->runScan();
26
  }
27
  else {
28
- $sAction = $oDp->FetchGet( 'shield_action' );
29
  switch ( $sAction ) {
30
-
31
  case 'delete_unrecognised_file':
32
- $sPath = '/' . trim( $oDp->FetchGet( 'repair_file_path' ) ); // "/" prevents esc_url() from prepending http.
33
  }
34
  }
35
  }
@@ -76,7 +75,7 @@ class ICWP_WPSF_Processor_HackProtect_FileCleanerScan extends ICWP_WPSF_Processo
76
  $oFilter = new CleanerRecursiveFilterIterator( new RecursiveDirectoryIterator( $sUploadsDir ) );
77
  $oRecursiveIterator = new RecursiveIteratorIterator( $oFilter );
78
 
79
- $sBadExtensionsReg = '#^' . implode( '|', array( 'js', 'php', 'php5' ) ) . '$#i';
80
  foreach ( $oRecursiveIterator as $oFsItem ) {
81
  /** @var SplFileInfo $oFsItem */
82
 
@@ -147,7 +146,11 @@ class ICWP_WPSF_Processor_HackProtect_FileCleanerScan extends ICWP_WPSF_Processo
147
 
148
  foreach ( $oFO->getUfcFileExclusions() as $sExclusion ) {
149
  $sExclusion = $oFS->normalizeFilePathDS( $sExclusion );
150
- if ( strpos( $sExclusion, '/' ) === false ) { // filename only
 
 
 
 
151
  $bExcluded = ( $sFileName == $sExclusion );
152
  }
153
  else {
@@ -178,17 +181,11 @@ class ICWP_WPSF_Processor_HackProtect_FileCleanerScan extends ICWP_WPSF_Processo
178
  }
179
 
180
  /**
181
- * @throws Exception
182
  */
183
  public function runScan() {
184
  /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
185
  $oFO = $this->getFeature();
186
-
187
- $aDiscoveredFiles = $this->scanCore();
188
- if ( $oFO->isUfsScanUploads() ) {
189
- $aDiscoveredFiles = array_merge( $aDiscoveredFiles, $this->scanUploads() );
190
- }
191
-
192
  if ( !empty( $aDiscoveredFiles ) ) {
193
  if ( $oFO->isUfsDeleteFiles() ) {
194
  $this->deleteFiles( $aDiscoveredFiles );
@@ -199,6 +196,20 @@ class ICWP_WPSF_Processor_HackProtect_FileCleanerScan extends ICWP_WPSF_Processo
199
  }
200
  }
201
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
202
  /**
203
  * @param array $aFiles
204
  * @return bool
@@ -209,14 +220,12 @@ class ICWP_WPSF_Processor_HackProtect_FileCleanerScan extends ICWP_WPSF_Processo
209
  }
210
  /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
211
  $oFO = $this->getFeature();
212
-
213
- $oWp = $this->loadWp();
214
- $sHomeUrl = $oWp->getHomeUrl();
215
  $aContent = array(
216
  sprintf( _wpsf__( '%s detected files on your site which are not recognised.' ), $this->getController()
217
  ->getHumanName() ),
218
  _wpsf__( 'This is part of the Hack Protection module for the WordPress Unrecognised File Scanner.' )
219
- . ' [<a href="http://icwp.io/shieldmoreinfounrecognised">' . _wpsf__( 'More Info' ) . ']</a>',
220
  '',
221
  sprintf( _wpsf__( 'Site Home URL - %s' ), sprintf( '<a href="%s" target="_blank">%s</a>', $sHomeUrl, $sHomeUrl ) ),
222
  _wpsf__( 'The following files are considered "unrecognised" and should be examined:' ),
@@ -224,19 +233,28 @@ class ICWP_WPSF_Processor_HackProtect_FileCleanerScan extends ICWP_WPSF_Processo
224
  );
225
 
226
  foreach ( $aFiles as $sFile ) {
227
- $aContent[] = ' - ' . $sFile;
228
  }
229
 
230
  $aContent[] = '';
 
 
 
 
 
 
 
 
 
231
  if ( $oFO->isUfsDeleteFiles() ) {
232
  $aContent[] = _wpsf__( 'We have already attempted to delete these files based on your current settings.' )
233
- . ' ' . _wpsf__( 'But, you should always check these files to ensure everything is as you expect.' );
234
  }
235
  else {
236
  $aContent[] = _wpsf__( 'You should review these files and remove them if required.' );
237
  $aContent[] = _wpsf__( 'You can now add these file names to your exclusion list to no longer be warned about them.' );
238
  $aContent[] = _wpsf__( 'Alternatively you can have the plugin attempt to delete these files automatically.' )
239
- . ' [<a href="http://icwp.io/shieldmoreinfounrecognised">' . _wpsf__( 'More Info' ) . ']</a>';
240
  }
241
 
242
  $sRecipient = $this->getPluginDefaultRecipientAddress();
@@ -249,7 +267,6 @@ class ICWP_WPSF_Processor_HackProtect_FileCleanerScan extends ICWP_WPSF_Processo
249
  else {
250
  $this->addToAuditEntry( sprintf( _wpsf__( 'Failed to send Unrecognised File Scan notification email alert to: %s' ), $sRecipient ) );
251
  }
252
-
253
  return $bSendSuccess;
254
  }
255
 
4
  return;
5
  }
6
 
7
+ require_once( dirname( __FILE__ ).DIRECTORY_SEPARATOR.'base_wpsf.php' );
8
 
9
  class ICWP_WPSF_Processor_HackProtect_FileCleanerScan extends ICWP_WPSF_Processor_BaseWpsf {
10
 
19
  $this->setupChecksumCron();
20
 
21
  if ( $this->loadWpUsers()->isUserAdmin() ) {
22
+ $oDp = $this->loadDP();
23
 
24
+ if ( $oDp->query( 'force_filecleanscan' ) == 1 ) {
25
  $this->runScan();
26
  }
27
  else {
28
+ $sAction = $oDp->query( 'shield_action' );
29
  switch ( $sAction ) {
 
30
  case 'delete_unrecognised_file':
31
+ $sPath = '/'.trim( $oDp->FetchGet( 'repair_file_path' ) ); // "/" prevents esc_url() from prepending http.
32
  }
33
  }
34
  }
75
  $oFilter = new CleanerRecursiveFilterIterator( new RecursiveDirectoryIterator( $sUploadsDir ) );
76
  $oRecursiveIterator = new RecursiveIteratorIterator( $oFilter );
77
 
78
+ $sBadExtensionsReg = '#^'.implode( '|', array( 'js', 'php', 'php5' ) ).'$#i';
79
  foreach ( $oRecursiveIterator as $oFsItem ) {
80
  /** @var SplFileInfo $oFsItem */
81
 
146
 
147
  foreach ( $oFO->getUfcFileExclusions() as $sExclusion ) {
148
  $sExclusion = $oFS->normalizeFilePathDS( $sExclusion );
149
+
150
+ if ( preg_match( '/^#(.+)#$/', $sExclusion, $aMatches ) ) { // it's regex
151
+ $bExcluded = @preg_match( stripslashes( $sExclusion ), $sFilePath );
152
+ }
153
+ else if ( strpos( $sExclusion, '/' ) === false ) { // filename only
154
  $bExcluded = ( $sFileName == $sExclusion );
155
  }
156
  else {
181
  }
182
 
183
  /**
 
184
  */
185
  public function runScan() {
186
  /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
187
  $oFO = $this->getFeature();
188
+ $aDiscoveredFiles = $this->discoverFiles();
 
 
 
 
 
189
  if ( !empty( $aDiscoveredFiles ) ) {
190
  if ( $oFO->isUfsDeleteFiles() ) {
191
  $this->deleteFiles( $aDiscoveredFiles );
196
  }
197
  }
198
 
199
+ /**
200
+ * @return array
201
+ */
202
+ public function discoverFiles() {
203
+ /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
204
+ $oFO = $this->getFeature();
205
+
206
+ $aDiscoveredFiles = $this->scanCore();
207
+ if ( $oFO->isUfsScanUploads() ) {
208
+ $aDiscoveredFiles = array_merge( $aDiscoveredFiles, $this->scanUploads() );
209
+ }
210
+ return $aDiscoveredFiles;
211
+ }
212
+
213
  /**
214
  * @param array $aFiles
215
  * @return bool
220
  }
221
  /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
222
  $oFO = $this->getFeature();
223
+ $sHomeUrl = $this->loadWp()->getHomeUrl();
 
 
224
  $aContent = array(
225
  sprintf( _wpsf__( '%s detected files on your site which are not recognised.' ), $this->getController()
226
  ->getHumanName() ),
227
  _wpsf__( 'This is part of the Hack Protection module for the WordPress Unrecognised File Scanner.' )
228
+ .' [<a href="http://icwp.io/shieldmoreinfounrecognised">'._wpsf__( 'More Info' ).']</a>',
229
  '',
230
  sprintf( _wpsf__( 'Site Home URL - %s' ), sprintf( '<a href="%s" target="_blank">%s</a>', $sHomeUrl, $sHomeUrl ) ),
231
  _wpsf__( 'The following files are considered "unrecognised" and should be examined:' ),
233
  );
234
 
235
  foreach ( $aFiles as $sFile ) {
236
+ $aContent[] = ' - '.$sFile;
237
  }
238
 
239
  $aContent[] = '';
240
+ if ( $oFO->getCanRunWizards() ) {
241
+ $aContent[] = sprintf( '<a href="%s" target="_blank" style="%s">%s →</a>',
242
+ $oFO->getUrl_Wizard( 'ufc' ),
243
+ 'border:1px solid;padding:20px;line-height:19px;margin:10px 20px;display:inline-block;text-align:center;width:290px;font-size:18px;',
244
+ _wpsf__( 'Run the scanner manually' )
245
+ );
246
+ $aContent[] = '';
247
+ }
248
+
249
  if ( $oFO->isUfsDeleteFiles() ) {
250
  $aContent[] = _wpsf__( 'We have already attempted to delete these files based on your current settings.' )
251
+ .' '._wpsf__( 'But, you should always check these files to ensure everything is as you expect.' );
252
  }
253
  else {
254
  $aContent[] = _wpsf__( 'You should review these files and remove them if required.' );
255
  $aContent[] = _wpsf__( 'You can now add these file names to your exclusion list to no longer be warned about them.' );
256
  $aContent[] = _wpsf__( 'Alternatively you can have the plugin attempt to delete these files automatically.' )
257
+ .' [<a href="http://icwp.io/shieldmoreinfounrecognised">'._wpsf__( 'More Info' ).']</a>';
258
  }
259
 
260
  $sRecipient = $this->getPluginDefaultRecipientAddress();
267
  else {
268
  $this->addToAuditEntry( sprintf( _wpsf__( 'Failed to send Unrecognised File Scan notification email alert to: %s' ), $sRecipient ) );
269
  }
 
270
  return $bSendSuccess;
271
  }
272
 
src/processors/hackprotect_wpvulnscan.php CHANGED
@@ -4,7 +4,7 @@ if ( class_exists( 'ICWP_WPSF_Processor_HackProtect_WpVulnScan', false ) ) {
4
  return;
5
  }
6
 
7
- require_once( dirname( __FILE__ ).ICWP_DS.'base_wpsf.php' );
8
 
9
  class ICWP_WPSF_Processor_HackProtect_WpVulnScan extends ICWP_WPSF_Processor_BaseWpsf {
10
 
4
  return;
5
  }
6
 
7
+ require_once( dirname( __FILE__ ).'/base_wpsf.php' );
8
 
9
  class ICWP_WPSF_Processor_HackProtect_WpVulnScan extends ICWP_WPSF_Processor_BaseWpsf {
10
 
src/processors/login_protect.php CHANGED
@@ -17,7 +17,7 @@ class ICWP_WPSF_Processor_LoginProtect extends ICWP_WPSF_Processor_BaseWpsf {
17
 
18
  // XML-RPC Compatibility
19
  if ( $oWp->getIsXmlrpc() && $this->getIsOption( 'enable_xmlrpc_compatibility', 'Y' ) ) {
20
- return true;
21
  }
22
 
23
  if ( $oFO->getIsCustomLoginPathEnabled() ) {
@@ -40,7 +40,6 @@ class ICWP_WPSF_Processor_LoginProtect extends ICWP_WPSF_Processor_BaseWpsf {
40
  $this->getProcessorLoginIntent()->run();
41
 
42
  add_filter( 'wp_login_errors', array( $this, 'addLoginMessage' ) );
43
- return true;
44
  }
45
 
46
  /**
@@ -99,7 +98,7 @@ class ICWP_WPSF_Processor_LoginProtect extends ICWP_WPSF_Processor_BaseWpsf {
99
  /**
100
  * @return ICWP_WPSF_Processor_LoginProtect_Intent
101
  */
102
- protected function getProcessorLoginIntent() {
103
  require_once( dirname( __FILE__ ).DIRECTORY_SEPARATOR.'loginprotect_intent.php' );
104
  $oProc = new ICWP_WPSF_Processor_LoginProtect_Intent( $this->getFeature() );
105
  return $oProc;
17
 
18
  // XML-RPC Compatibility
19
  if ( $oWp->getIsXmlrpc() && $this->getIsOption( 'enable_xmlrpc_compatibility', 'Y' ) ) {
20
+ return;
21
  }
22
 
23
  if ( $oFO->getIsCustomLoginPathEnabled() ) {
40
  $this->getProcessorLoginIntent()->run();
41
 
42
  add_filter( 'wp_login_errors', array( $this, 'addLoginMessage' ) );
 
43
  }
44
 
45
  /**
98
  /**
99
  * @return ICWP_WPSF_Processor_LoginProtect_Intent
100
  */
101
+ public function getProcessorLoginIntent() {
102
  require_once( dirname( __FILE__ ).DIRECTORY_SEPARATOR.'loginprotect_intent.php' );
103
  $oProc = new ICWP_WPSF_Processor_LoginProtect_Intent( $this->getFeature() );
104
  return $oProc;
src/processors/loginprotect_googleauthenticator.php CHANGED
@@ -54,17 +54,31 @@ class ICWP_WPSF_Processor_LoginProtect_GoogleAuthenticator extends ICWP_WPSF_Pro
54
  );
55
 
56
  if ( !$bValidatedProfile ) {
57
- $sChartUrl = $this->loadGoogleAuthenticatorProcessor()->getGoogleQrChartUrl(
58
- $aData['user_google_authenticator_secret'],
59
- preg_replace( '#[^0-9a-z]#i', '', $oUser->get('user_login') )
60
- .'@'.preg_replace( '#[^0-9a-z]#i', '', $this->loadWp()->getSiteName() )
61
- );
62
- $aData[ 'chart_url' ] = $sChartUrl;
63
  }
64
 
65
  echo $this->getFeature()->renderTemplate( 'snippets/user_profile_googleauthenticator.php', $aData );
66
  }
67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  /**
69
  * The only thing we can do is REMOVE Google Authenticator from an account that is not our own
70
  * But, only admins can do this. If Security Admin feature is enabled, then only they can do it.
@@ -130,7 +144,6 @@ class ICWP_WPSF_Processor_LoginProtect_GoogleAuthenticator extends ICWP_WPSF_Pro
130
  * @param int $nSavingUserId
131
  */
132
  public function handleUserProfileSubmit( $nSavingUserId ) {
133
- $oDp = $this->loadDataProcessor();
134
  $oWpUsers = $this->loadWpUsers();
135
  $oWpNotices = $this->loadAdminNoticesProcessor();
136
 
@@ -142,7 +155,7 @@ class ICWP_WPSF_Processor_LoginProtect_GoogleAuthenticator extends ICWP_WPSF_Pro
142
 
143
  $sMessageOtpInvalid = _wpsf__( 'One Time Password (OTP) was not valid.' ).' '._wpsf__( 'Please try again.' );
144
 
145
- $sShieldTurnOff = $oDp->FetchPost( 'shield_turn_off_google_authenticator' );
146
  if ( !empty( $sShieldTurnOff ) && $sShieldTurnOff == 'Y' ) {
147
 
148
  if ( $bValidOtp ) {
@@ -312,6 +325,15 @@ class ICWP_WPSF_Processor_LoginProtect_GoogleAuthenticator extends ICWP_WPSF_Pro
312
  * @return bool
313
  */
314
  protected function processOtp( $oUser, $sOtpCode ) {
 
 
 
 
 
 
 
 
 
315
  $bValidOtp = false;
316
  if ( !empty( $sOtpCode ) && preg_match( '#^[0-9]{6}$#', $sOtpCode ) ) {
317
  $bValidOtp = $this->loadGoogleAuthenticatorProcessor()
54
  );
55
 
56
  if ( !$bValidatedProfile ) {
57
+ $aData[ 'chart_url' ] = $this->getGaRegisterChartUrl( $oUser );
 
 
 
 
 
58
  }
59
 
60
  echo $this->getFeature()->renderTemplate( 'snippets/user_profile_googleauthenticator.php', $aData );
61
  }
62
 
63
+ /**
64
+ * @param WP_User $oUser
65
+ * @return string
66
+ */
67
+ public function getGaRegisterChartUrl( $oUser ) {
68
+ if ( empty( $oUser ) ) {
69
+ $sUrl = '';
70
+ }
71
+ else {
72
+ $sUrl = $this->loadGoogleAuthenticatorProcessor()
73
+ ->getGoogleQrChartUrl(
74
+ $this->getSecret( $oUser ),
75
+ preg_replace( '#[^0-9a-z]#i', '', $oUser->get( 'user_login' ) )
76
+ .'@'.preg_replace( '#[^0-9a-z]#i', '', $this->loadWp()->getSiteName() )
77
+ );
78
+ }
79
+ return $sUrl;
80
+ }
81
+
82
  /**
83
  * The only thing we can do is REMOVE Google Authenticator from an account that is not our own
84
  * But, only admins can do this. If Security Admin feature is enabled, then only they can do it.
144
  * @param int $nSavingUserId
145
  */
146
  public function handleUserProfileSubmit( $nSavingUserId ) {
 
147
  $oWpUsers = $this->loadWpUsers();
148
  $oWpNotices = $this->loadAdminNoticesProcessor();
149
 
155
 
156
  $sMessageOtpInvalid = _wpsf__( 'One Time Password (OTP) was not valid.' ).' '._wpsf__( 'Please try again.' );
157
 
158
+ $sShieldTurnOff = $this->loadDP()->post( 'shield_turn_off_google_authenticator' );
159
  if ( !empty( $sShieldTurnOff ) && $sShieldTurnOff == 'Y' ) {
160
 
161
  if ( $bValidOtp ) {
325
  * @return bool
326
  */
327
  protected function processOtp( $oUser, $sOtpCode ) {
328
+ return $this->validateGaCode( $oUser, $sOtpCode );
329
+ }
330
+
331
+ /**
332
+ * @param WP_User $oUser
333
+ * @param string $sOtpCode
334
+ * @return bool
335
+ */
336
+ public function validateGaCode( $oUser, $sOtpCode ) {
337
  $bValidOtp = false;
338
  if ( !empty( $sOtpCode ) && preg_match( '#^[0-9]{6}$#', $sOtpCode ) ) {
339
  $bValidOtp = $this->loadGoogleAuthenticatorProcessor()
src/processors/loginprotect_intent.php CHANGED
@@ -4,7 +4,7 @@ if ( class_exists( 'ICWP_WPSF_Processor_LoginProtect_Intent', false ) ) {
4
  return;
5
  }
6
 
7
- require_once( dirname(__FILE__).DIRECTORY_SEPARATOR.'base_wpsf.php' );
8
 
9
  class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWpsf {
10
 
@@ -21,7 +21,7 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
21
 
22
  $oLoginTracker = $this->getLoginTrack();
23
 
24
- if ( $this->getIsOption( 'enable_google_authenticator', 'Y' ) ) {
25
  $oLoginTracker->addFactorToTrack( ICWP_WPSF_Processor_LoginProtect_Track::Factor_Google_Authenticator );
26
  $this->getProcessorGoogleAuthenticator()->run();
27
  }
@@ -70,12 +70,12 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
70
  $oFO = $this->getFeature();
71
 
72
  if ( $this->userHasPendingLoginIntent() ) {
73
- $oDp = $this->loadDataProcessor();
74
 
75
  $bIsLoginIntentSubmission = $oDp->FetchRequest( $oFO->getLoginIntentRequestFlag() ) == 1;
76
  if ( $bIsLoginIntentSubmission ) {
77
 
78
- if ( $oDp->FetchPost( 'cancel' ) == 1 ) {
79
  $this->loadWpUsers()->logoutUser(); // clears the login and login intent
80
  $this->loadWp()->redirectToLogin();
81
  return;
@@ -92,11 +92,11 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
92
 
93
  if ( $bLoginIntentValidated ) {
94
  $this->removeLoginIntent();
95
- $sRedirect = $oDp->FetchRequest( 'redirect_to' );
96
  $this->loadAdminNoticesProcessor()->addFlashMessage(
97
  _wpsf__( 'Success' ).'! '._wpsf__( 'Thank you for authenticating your login.' ) );
98
  if ( !empty( $sRedirect ) ) {
99
- $this->loadWp()->doRedirect( esc_url( rawurldecode( $sRedirect ) ) );
100
  }
101
  }
102
  else {
@@ -144,7 +144,7 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
144
  }
145
 
146
  /**
147
- * @param int $nExpirationTime
148
  * @param null $oUser
149
  */
150
  protected function setLoginIntentExpiration( $nExpirationTime, $oUser = null ) {
@@ -170,7 +170,7 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
170
  $oF->prefix( 'login_intent_timeout' ),
171
  $oF->getDefinition( 'login_intent_timeout' )
172
  );
173
- $this->setLoginIntentExpiration($this->time() + MINUTE_IN_SECONDS*$nTimeout, $oUser );
174
  }
175
  return $oUser;
176
  }
@@ -226,16 +226,13 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
226
  $sMessageType = 'warning';
227
  }
228
 
229
- $sRedirectTo = $this->loadDataProcessor()->FetchGet( 'redirect_to' );
230
- if ( empty( $sRedirectTo ) ) {
231
- $sRedirectTo = rawurlencode( esc_url( $this->loadDataProcessor()->getRequestUri() ) );
232
- }
233
 
234
  $aDisplayData = array(
235
  'strings' => array(
236
  'cancel' => _wpsf__( 'Cancel Login' ),
237
  'time_remaining' => _wpsf__( 'Time Remaining' ),
238
- 'calculating' => _wpsf__( 'Calculating' ) . ' ...',
239
  'seconds' => strtolower( _wpsf__( 'Seconds' ) ),
240
  'login_expired' => _wpsf__( 'Login Expired' ),
241
  'verify_my_login' => _wpsf__( 'Verify My Login' ),
@@ -273,7 +270,7 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
273
  * @return ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth
274
  */
275
  protected function getProcessorTwoFactor() {
276
- require_once( dirname(__FILE__).DIRECTORY_SEPARATOR.'loginprotect_twofactorauth.php' );
277
  /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
278
  $oFO = $this->getFeature();
279
  $oProc = new ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth( $oFO );
@@ -284,7 +281,7 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
284
  * @return ICWP_WPSF_Processor_LoginProtect_Yubikey
285
  */
286
  protected function getProcessorYubikey() {
287
- require_once( dirname(__FILE__).DIRECTORY_SEPARATOR.'loginprotect_yubikey.php' );
288
  $oProc = new ICWP_WPSF_Processor_LoginProtect_Yubikey( $this->getFeature() );
289
  return $oProc->setLoginTrack( $this->getLoginTrack() );
290
  }
@@ -292,8 +289,8 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
292
  /**
293
  * @return ICWP_WPSF_Processor_LoginProtect_GoogleAuthenticator
294
  */
295
- protected function getProcessorGoogleAuthenticator() {
296
- require_once( dirname(__FILE__).DIRECTORY_SEPARATOR.'loginprotect_googleauthenticator.php' );
297
  $oProc = new ICWP_WPSF_Processor_LoginProtect_GoogleAuthenticator( $this->getFeature() );
298
  return $oProc->setLoginTrack( $this->getLoginTrack() );
299
  }
@@ -303,7 +300,7 @@ class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWp
303
  */
304
  public function getLoginTrack() {
305
  if ( !isset( $this->oLoginTrack ) ) {
306
- require_once( dirname(__FILE__).DIRECTORY_SEPARATOR.'loginprotect_track.php' );
307
  $this->oLoginTrack = new ICWP_WPSF_Processor_LoginProtect_Track();
308
  }
309
  return $this->oLoginTrack;
4
  return;
5
  }
6
 
7
+ require_once( dirname( __FILE__ ).DIRECTORY_SEPARATOR.'base_wpsf.php' );
8
 
9
  class ICWP_WPSF_Processor_LoginProtect_Intent extends ICWP_WPSF_Processor_BaseWpsf {
10
 
21
 
22
  $oLoginTracker = $this->getLoginTrack();
23
 
24
+ if ( $oFO->getIsEnabledGoogleAuthenticator() ) {
25
  $oLoginTracker->addFactorToTrack( ICWP_WPSF_Processor_LoginProtect_Track::Factor_Google_Authenticator );
26
  $this->getProcessorGoogleAuthenticator()->run();
27
  }
70
  $oFO = $this->getFeature();
71
 
72
  if ( $this->userHasPendingLoginIntent() ) {
73
+ $oDp = $this->loadDP();
74
 
75
  $bIsLoginIntentSubmission = $oDp->FetchRequest( $oFO->getLoginIntentRequestFlag() ) == 1;
76
  if ( $bIsLoginIntentSubmission ) {
77
 
78
+ if ( $oDp->post( 'cancel' ) == 1 ) {
79
  $this->loadWpUsers()->logoutUser(); // clears the login and login intent
80
  $this->loadWp()->redirectToLogin();
81
  return;
92
 
93
  if ( $bLoginIntentValidated ) {
94
  $this->removeLoginIntent();
95
+ $sRedirect = $oDp->post( 'redirect_to' );
96
  $this->loadAdminNoticesProcessor()->addFlashMessage(
97
  _wpsf__( 'Success' ).'! '._wpsf__( 'Thank you for authenticating your login.' ) );
98
  if ( !empty( $sRedirect ) ) {
99
+ // $this->loadWp()->doRedirect( site_url( rawurldecode( $sRedirect ) ) );
100
  }
101
  }
102
  else {
144
  }
145
 
146
  /**
147
+ * @param int $nExpirationTime
148
  * @param null $oUser
149
  */
150
  protected function setLoginIntentExpiration( $nExpirationTime, $oUser = null ) {
170
  $oF->prefix( 'login_intent_timeout' ),
171
  $oF->getDefinition( 'login_intent_timeout' )
172
  );
173
+ $this->setLoginIntentExpiration( $this->time() + MINUTE_IN_SECONDS*$nTimeout, $oUser );
174
  }
175
  return $oUser;
176
  }
226
  $sMessageType = 'warning';
227
  }
228
 
229
+ $sRedirectTo = rawurlencode( $this->loadDP()->getRequestUri() ); // not actually used
 
 
 
230
 
231
  $aDisplayData = array(
232
  'strings' => array(
233
  'cancel' => _wpsf__( 'Cancel Login' ),
234
  'time_remaining' => _wpsf__( 'Time Remaining' ),
235
+ 'calculating' => _wpsf__( 'Calculating' ).' ...',
236
  'seconds' => strtolower( _wpsf__( 'Seconds' ) ),
237
  'login_expired' => _wpsf__( 'Login Expired' ),
238
  'verify_my_login' => _wpsf__( 'Verify My Login' ),
270
  * @return ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth
271
  */
272
  protected function getProcessorTwoFactor() {
273
+ require_once( dirname( __FILE__ ).DIRECTORY_SEPARATOR.'loginprotect_twofactorauth.php' );
274
  /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
275
  $oFO = $this->getFeature();
276
  $oProc = new ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth( $oFO );
281
  * @return ICWP_WPSF_Processor_LoginProtect_Yubikey
282
  */
283
  protected function getProcessorYubikey() {
284
+ require_once( dirname( __FILE__ ).DIRECTORY_SEPARATOR.'loginprotect_yubikey.php' );
285
  $oProc = new ICWP_WPSF_Processor_LoginProtect_Yubikey( $this->getFeature() );
286
  return $oProc->setLoginTrack( $this->getLoginTrack() );
287
  }
289
  /**
290
  * @return ICWP_WPSF_Processor_LoginProtect_GoogleAuthenticator
291
  */
292
+ public function getProcessorGoogleAuthenticator() {
293
+ require_once( dirname( __FILE__ ).DIRECTORY_SEPARATOR.'loginprotect_googleauthenticator.php' );
294
  $oProc = new ICWP_WPSF_Processor_LoginProtect_GoogleAuthenticator( $this->getFeature() );
295
  return $oProc->setLoginTrack( $this->getLoginTrack() );
296
  }
300
  */
301
  public function getLoginTrack() {
302
  if ( !isset( $this->oLoginTrack ) ) {
303
+ require_once( dirname( __FILE__ ).DIRECTORY_SEPARATOR.'loginprotect_track.php' );
304
  $this->oLoginTrack = new ICWP_WPSF_Processor_LoginProtect_Track();
305
  }
306
  return $this->oLoginTrack;
src/processors/loginprotect_intent_base.php CHANGED
@@ -4,7 +4,7 @@ if ( class_exists( 'ICWP_WPSF_Processor_LoginProtect_IntentBase', false ) ) {
4
  return;
5
  }
6
 
7
- require_once( dirname(__FILE__).DIRECTORY_SEPARATOR.'base_wpsf.php' );
8
 
9
  abstract class ICWP_WPSF_Processor_LoginProtect_IntentBase extends ICWP_WPSF_Processor_BaseWpsf {
10
 
@@ -83,7 +83,10 @@ abstract class ICWP_WPSF_Processor_LoginProtect_IntentBase extends ICWP_WPSF_Pro
83
  */
84
  protected function getSecret( WP_User $oUser ) {
85
  $oWpUser = $this->loadWpUsers();
86
- $sSecret = $oWpUser->getUserMeta( $this->getFeature()->prefixOptionKey( $this->getStub().'_secret' ), $oUser->ID );
 
 
 
87
  if ( empty( $sSecret ) ) {
88
  $this->resetSecret( $oUser );
89
  }
@@ -102,10 +105,10 @@ abstract class ICWP_WPSF_Processor_LoginProtect_IntentBase extends ICWP_WPSF_Pro
102
 
103
  /**
104
  * @param WP_User $oUser
105
- * @param bool $bValidated set true for validated, false for invalidated
106
  * @return $this
107
  */
108
- protected function setProfileValidated( $oUser, $bValidated = true ) {
109
  $this->loadWpUsers()
110
  ->updateUserMeta(
111
  $this->getFeature()->prefixOptionKey( $this->getStub().'_validated' ),
@@ -117,7 +120,7 @@ abstract class ICWP_WPSF_Processor_LoginProtect_IntentBase extends ICWP_WPSF_Pro
117
 
118
  /**
119
  * @param WP_User $oUser
120
- * @param $sNewSecret
121
  * @return $this
122
  */
123
  protected function setSecret( $oUser, $sNewSecret ) {
@@ -208,7 +211,7 @@ abstract class ICWP_WPSF_Processor_LoginProtect_IntentBase extends ICWP_WPSF_Pro
208
  * @return string
209
  */
210
  protected function fetchCodeFromRequest() {
211
- return esc_attr( trim( $this->loadDataProcessor()->FetchRequest( $this->getLoginFormParameter(), false, '' ) ) );
212
  }
213
 
214
  /**
4
  return;
5
  }
6
 
7
+ require_once( dirname( __FILE__ ).DIRECTORY_SEPARATOR.'base_wpsf.php' );
8
 
9
  abstract class ICWP_WPSF_Processor_LoginProtect_IntentBase extends ICWP_WPSF_Processor_BaseWpsf {
10
 
83
  */
84
  protected function getSecret( WP_User $oUser ) {
85
  $oWpUser = $this->loadWpUsers();
86
+ $sSecret = $oWpUser->getUserMeta(
87
+ $this->getFeature()->prefixOptionKey( $this->getStub().'_secret' ),
88
+ $oUser->ID
89
+ );
90
  if ( empty( $sSecret ) ) {
91
  $this->resetSecret( $oUser );
92
  }
105
 
106
  /**
107
  * @param WP_User $oUser
108
+ * @param bool $bValidated set true for validated, false for invalidated
109
  * @return $this
110
  */
111
+ public function setProfileValidated( $oUser, $bValidated = true ) {
112
  $this->loadWpUsers()
113
  ->updateUserMeta(
114
  $this->getFeature()->prefixOptionKey( $this->getStub().'_validated' ),
120
 
121
  /**
122
  * @param WP_User $oUser
123
+ * @param $sNewSecret
124
  * @return $this
125
  */
126
  protected function setSecret( $oUser, $sNewSecret ) {
211
  * @return string
212
  */
213
  protected function fetchCodeFromRequest() {
214
+ return esc_attr( trim( $this->loadDP()->FetchRequest( $this->getLoginFormParameter(), false, '' ) ) );
215
  }
216
 
217
  /**
src/processors/loginprotect_twofactorauth.php CHANGED
@@ -160,38 +160,6 @@ class ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth extends ICWP_WPSF_Processor
160
  return $this->loadWpUsers()->getUserMeta( $this->get2FaCodeUserMetaKey() );
161
  }
162
 
163
- /**
164
- * Given the necessary components, creates the 2-factor verification link for giving to the user.
165
- * @param string $sUser
166
- * @param string $sSessionId
167
- * @return string
168
- */
169
- protected function generateTwoFactorVerifyLink( $sUser, $sSessionId ) {
170
- $sUrl = $this->buildTwoFactorVerifyUrl( $sUser, $sSessionId );
171
- return sprintf( '<a href="%s" target="_blank">%s</a>', $sUrl, $sUrl );
172
- }
173
-
174
- /**
175
- * @param string $sUser
176
- * @param string $sSessionId
177
- * @return string
178
- */
179
- protected function buildTwoFactorVerifyUrl( $sUser, $sSessionId ) {
180
- /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
181
- $oFO = $this->getFeature();
182
- $aQueryArgs = array(
183
- $this->getLoginFormParameter() => $this->getSessionHashCode(),
184
- $oFO->getLoginIntentRequestFlag() => 1,
185
- 'username' => rawurlencode( $sUser ),
186
- 'sessionid' => $sSessionId
187
- );
188
- $sRedirectTo = esc_url( $this->loadDataProcessor()->FetchPost( 'redirect_to' ) );
189
- if ( !empty( $sRedirectTo ) ) {
190
- $aQueryArgs[ 'redirect_to' ] = urlencode( $sRedirectTo );
191
- }
192
- return add_query_arg( $aQueryArgs, $this->loadWp()->getHomeUrl() );
193
- }
194
-
195
  /**
196
  * @param WP_User $oUser
197
  * @return boolean
@@ -201,21 +169,23 @@ class ICWP_WPSF_Processor_LoginProtect_TwoFactorAuth extends ICWP_WPSF_Processor
201
  $sEmail = $oUser->get( 'user_email' );
202
 
203
  $aMessage = array(
204
- _wpsf__( 'You, or someone pretending to be you, just attempted to login into your WordPress site.' ),
205
- _wpsf__( 'The IP Address / Cookie from which they tried to login is not currently verified.' ),
 
 
206
  sprintf( _wpsf__( 'Username: %s' ), $oUser->get( 'user_login' ) ),
207
  sprintf( _wpsf__( 'IP Address: %s' ), $sIpAddress ),
208
- _wpsf__( 'Use the following code in the Login Verification page.' ),
209
  '',
210
- sprintf( _wpsf__( 'Authentication Code: %s' ), $this->getSessionHashCode() ),
 
211
  '',
212
- sprintf( '<a href="%s" target="_blank">%s</a>', 'http://icwp.io/96', _wpsf__( 'Why no login link?' ) ),
213
  ''
214
  );
215
- $sEmailSubject = sprintf( _wpsf__( 'Two-Factor Login Verification for %s' ), $this->loadWp()
216
- ->getHomeUrl() );
217
 
218
- $bResult = $this->getEmailProcessor()->sendEmailTo( $sEmail, $sEmailSubject, $aMessage );
 
219
  if ( $bResult ) {
220
  $sAuditMessage = sprintf( _wpsf__( 'User "%s" was sent an email to verify their Identity using Two-Factor Login Auth for IP address "%s".' ), $oUser->get( 'user_login' ), $sIpAddress );
221
  $this->addToAuditEntry( $sAuditMessage, 2, 'login_protect_two_factor_email_send' );
160
  return $this->loadWpUsers()->getUserMeta( $this->get2FaCodeUserMetaKey() );
161
  }
162
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
  /**
164
  * @param WP_User $oUser
165
  * @return boolean
169
  $sEmail = $oUser->get( 'user_email' );
170
 
171
  $aMessage = array(
172
+ _wpsf__( 'Someone just attempted to login into your WordPress site.' ),
173
+ _wpsf__( 'Login for this user account requires verification.' ),
174
+ '',
175
+ sprintf( '<strong>%s</strong>', _wpsf__( 'Login Details' ) ),
176
  sprintf( _wpsf__( 'Username: %s' ), $oUser->get( 'user_login' ) ),
177
  sprintf( _wpsf__( 'IP Address: %s' ), $sIpAddress ),
 
178
  '',
179
+ _wpsf__( 'Use the following code on the Login Verification page.' ),
180
+ sprintf( _wpsf__( 'Verification Code: %s' ), sprintf( '<strong>%s</strong>', $this->getSessionHashCode() ) ),
181
  '',
182
+ sprintf( '(<a href="%s" target="_blank">%s</a>)', 'http://icwp.io/96', _wpsf__( 'Why no login link?' ) ),
183
  ''
184
  );
185
+ $sEmailSubject = sprintf( _wpsf__( '[%s] Two-Factor Login Verification' ), $this->loadWp()->getSiteName() );
 
186
 
187
+ $bResult = $this->getEmailProcessor()
188
+ ->sendEmailTo( $sEmail, $sEmailSubject, $aMessage );
189
  if ( $bResult ) {
190
  $sAuditMessage = sprintf( _wpsf__( 'User "%s" was sent an email to verify their Identity using Two-Factor Login Auth for IP address "%s".' ), $oUser->get( 'user_login' ), $sIpAddress );
191
  $this->addToAuditEntry( $sAuditMessage, 2, 'login_protect_two_factor_email_send' );
src/processors/plugin.php CHANGED
@@ -8,11 +8,6 @@ require_once( dirname( __FILE__ ).DIRECTORY_SEPARATOR.'base_plugin.php' );
8
 
9
  class ICWP_WPSF_Processor_Plugin extends ICWP_WPSF_Processor_BasePlugin {
10
 
11
- /**
12
- * @var ICWP_WPSF_Processor_Plugin_SetupWizard
13
- */
14
- protected $oSetupWizardProcessor;
15
-
16
  /**
17
  * @var ICWP_WPSF_Processor_Plugin_Badge
18
  */
@@ -54,13 +49,6 @@ class ICWP_WPSF_Processor_Plugin extends ICWP_WPSF_Processor_BasePlugin {
54
  $this->getSubProcessorImportExport()->runAction();
55
  }
56
  break;
57
-
58
- case 'wizard':
59
- if ( $oDP->getPhpVersionIsAtLeast( 5.4 ) ) {
60
- $this->getWizardProcessor()->run();
61
- }
62
- break;
63
-
64
  default:
65
  break;
66
  }
@@ -83,17 +71,6 @@ class ICWP_WPSF_Processor_Plugin extends ICWP_WPSF_Processor_BasePlugin {
83
  return $this->oBadgeProcessor;
84
  }
85
 
86
- /**
87
- * @return ICWP_WPSF_Processor_Plugin_SetupWizard
88
- */
89
- public function getWizardProcessor() {
90
- if ( !isset( $this->oSetupWizardProcessor ) ) {
91
- require_once( dirname( __FILE__ ).DIRECTORY_SEPARATOR.'plugin_setupwizard.php' );
92
- $this->oSetupWizardProcessor = new ICWP_WPSF_Processor_Plugin_SetupWizard( $this->getFeature() );
93
- }
94
- return $this->oSetupWizardProcessor;
95
- }
96
-
97
  /**
98
  * @return ICWP_WPSF_Processor_Plugin_Tracking
99
  */
8
 
9
  class ICWP_WPSF_Processor_Plugin extends ICWP_WPSF_Processor_BasePlugin {
10
 
 
 
 
 
 
11
  /**
12
  * @var ICWP_WPSF_Processor_Plugin_Badge
13
  */
49
  $this->getSubProcessorImportExport()->runAction();
50
  }
51
  break;
 
 
 
 
 
 
 
52
  default:
53
  break;
54
  }
71
  return $this->oBadgeProcessor;
72
  }
73
 
 
 
 
 
 
 
 
 
 
 
 
74
  /**
75
  * @return ICWP_WPSF_Processor_Plugin_Tracking
76
  */
src/processors/plugin_setupwizard.php DELETED
@@ -1,830 +0,0 @@
1
- <?php
2
-
3
- if ( class_exists( 'ICWP_WPSF_Processor_Plugin_SetupWizard', false ) ) {
4
- return;
5
- }
6
-
7
- require_once( dirname( __FILE__ ).DIRECTORY_SEPARATOR.'base_wpsf.php' );
8
-
9
- /**
10
- * @uses php 5.4+
11
- * Class ICWP_WPSF_Processor_Plugin_SetupWizard
12
- */
13
- class ICWP_WPSF_Processor_Plugin_SetupWizard extends ICWP_WPSF_Processor_BaseWpsf {
14
-
15
- /**
16
- * @var string
17
- */
18
- private $sCurrentWizard;
19
-
20
- /**
21
- */
22
- public function run() {
23
- add_action( 'init', array( $this, 'onWpInit' ), 0 );
24
- }
25
-
26
- public function onWpInit() {
27
- if ( $this->loadWpUsers()->isUserAdmin() ) {
28
- $this->loadWizard( (string)$this->loadDP()->query( 'wizard', '' ) );
29
- }
30
- }
31
-
32
- /**
33
- * @param string $sWizard
34
- * @throws Exception
35
- */
36
- protected function loadWizard( $sWizard ) {
37
-
38
- $sContent = '';
39
- $this->setCurrentWizard( $sWizard );
40
- switch ( $sWizard ) {
41
- case 'welcome':
42
- $sContent = $this->renderWizardWelcome();
43
- break;
44
- case 'import':
45
- $sContent = $this->renderWizardImport();
46
- break;
47
- default:
48
- $this->loadWp()->redirectToAdmin();
49
- break;
50
- }
51
- echo $sContent;
52
- die();
53
- }
54
-
55
- /**
56
- */
57
- public function ajaxSetupWizardSteps() {
58
- $oDP = $this->loadDP();
59
-
60
- $this->setCurrentWizard( $oDP->post( 'wizard_slug' ) );
61
- $aNextStep = $this->getWizardNextStep( $oDP->post( 'wizard_steps' ), $oDP->post( 'current_index' ) );
62
-
63
- return $this->getFeature()
64
- ->sendAjaxResponse(
65
- true,
66
- array( 'next_step' => $aNextStep )
67
- );
68
- }
69
-
70
- public function ajaxSetupWizardContent() {
71
- $oDP = $this->loadDP();
72
-
73
- $this->loadAutoload(); // for Response
74
- switch ( $oDP->post( 'wizard-step' ) ) {
75
-
76
- case 'admin_access_restriction_verify':
77
- $oResponse = $this->wizardSecurityAdminVerify();
78
- break;
79
-
80
- case 'license':
81
- $oResponse = $this->wizardLicense();
82
- break;
83
-
84
- case 'import_options':
85
- $oResponse = $this->wizardImportOptions();
86
- break;
87
-
88
- case 'admin_access_restriction':
89
- $oResponse = $this->wizardSecurityAdmin();
90
- break;
91
-
92
- case 'audit_trail':
93
- $oResponse = $this->wizardAuditTrail();
94
- break;
95
-
96
- case 'ips':
97
- $oResponse = $this->wizardIps();
98
- break;
99
-
100
- case 'comments_filter':
101
- $oResponse = $this->wizardCommentsFilter();
102
- break;
103
-
104
- case 'login_protect':
105
- $oResponse = $this->wizardLoginProtect();
106
- break;
107
-
108
- case 'optin':
109
- $oResponse = $this->wizardOptin();
110
- break;
111
-
112
- default:
113
- $oResponse = new \FernleafSystems\Utilities\Response();
114
- $oResponse->setSuccessful( false )
115
- ->setMessageText( _wpsf__( 'Unknown request' ) );
116
- break;
117
- }
118
-
119
- $sMessage = $oResponse->getMessageText();
120
- if ( $oResponse->successful() ) {
121
- $sMessage .= '<br />'.sprintf( _wpsf__( 'Please click %s to continue.' ), _wpsf__( 'Next' ) );
122
- }
123
- else {
124
- $sMessage = sprintf( '%s: %s', _wpsf__( 'Error' ), $sMessage );
125
- }
126
-
127
- $aData = $oResponse->getData();
128
- $aData[ 'message' ] = $sMessage;
129
-
130
- $this->getFeature()
131
- ->sendAjaxResponse( $oResponse->successful(), $aData );
132
- }
133
-
134
- /**
135
- * @return string
136
- * @throws Exception
137
- */
138
- protected function renderWizardImport() {
139
- return $this->renderWizard();
140
- }
141
-
142
- /**
143
- * @return string
144
- * @throws Exception
145
- */
146
- protected function renderWizardWelcome() {
147
- return $this->renderWizard();
148
- }
149
-
150
- /**
151
- * @return string
152
- * @throws Exception
153
- */
154
- protected function renderWizard() {
155
- /** @var ICWP_WPSF_FeatureHandler_Plugin $oFO */
156
- $oFO = $this->getFeature();
157
- $oCon = $this->getController();
158
-
159
- $sMessage = $this->loadAdminNoticesProcessor()
160
- ->flushFlashMessage()
161
- ->getRawFlashMessageText();
162
-
163
- $aDisplayData = array(
164
- 'strings' => array(
165
- 'welcome' => _wpsf__( 'Welcome' ),
166
- 'time_remaining' => _wpsf__( 'Time Remaining' ),
167
- 'calculating' => _wpsf__( 'Calculating' ).' ...',
168
- 'seconds' => strtolower( _wpsf__( 'Seconds' ) ),
169
- 'login_expired' => _wpsf__( 'Login Expired' ),
170
- 'verify_my_login' => _wpsf__( 'Verify My Login' ),
171
- 'more_info' => _wpsf__( 'More Info' ),
172
- 'what_is_this' => _wpsf__( 'What is this?' ),
173
- 'message' => $sMessage,
174
- 'page_title' => sprintf( _wpsf__( '%s Setup Wizard' ), $oCon->getHumanName() )
175
- ),
176
- 'data' => array(
177
- 'wizard_slug' => $this->getCurrentWizard(),
178
- 'wizard_steps' => json_encode( $this->determineWizardSteps() ),
179
- 'wizard_first_step' => json_encode( $this->getWizardFirstStep() ),
180
- ),
181
- 'hrefs' => array(
182
- 'form_action' => $this->loadDataProcessor()->getRequestUri(),
183
- 'css_bootstrap' => $oCon->getPluginUrl_Css( 'bootstrap3.min.css' ),
184
- 'css_pages' => $oCon->getPluginUrl_Css( 'pages.css' ),
185
- 'css_steps' => $oCon->getPluginUrl_Css( 'jquery.steps.css' ),
186
- 'css_fancybox' => $oCon->getPluginUrl_Css( 'jquery.fancybox.min.css' ),
187
- 'css_globalplugin' => $oCon->getPluginUrl_Css( 'global-plugin.css' ),
188
- 'css_wizard' => $oCon->getPluginUrl_Css( 'wizard.css' ),
189
- 'js_jquery' => $this->loadWpIncludes()->getUrl_Jquery(),
190
- 'js_bootstrap' => $oCon->getPluginUrl_Js( 'bootstrap3.min.js' ),
191
- 'js_fancybox' => $oCon->getPluginUrl_Js( 'jquery.fancybox.min.js' ),
192
- 'js_globalplugin' => $oCon->getPluginUrl_Js( 'global-plugin.js' ),
193
- 'js_steps' => $oCon->getPluginUrl_Js( 'jquery.steps.min.js' ),
194
- 'js_wizard' => $oCon->getPluginUrl_Js( 'wizard.js' ),
195
- 'shield_logo' => 'https://plugins.svn.wordpress.org/wp-simple-firewall/assets/banner-1544x500-transparent.png',
196
- 'what_is_this' => 'https://icontrolwp.freshdesk.com/support/solutions/articles/3000064840',
197
- 'favicon' => $oCon->getPluginUrl_Image( 'pluginlogo_24x24.png' ),
198
- ),
199
- 'ajax' => array(
200
- 'content' => $oFO->getBaseAjaxActionRenderData( 'SetupWizardContent' ),
201
- 'steps' => $oFO->getBaseAjaxActionRenderData( 'SetupWizardSteps' ),
202
- 'steps_as_json' => $oFO->getBaseAjaxActionRenderData( 'SetupWizardSteps', true ),
203
- )
204
- );
205
-
206
- return $this->loadRenderer( $this->getController()->getPath_Templates() )
207
- ->setTemplate( 'pages/wizard.twig' )
208
- ->setRenderVars( $aDisplayData )
209
- ->setTemplateEngineTwig()
210
- ->render();
211
- }
212
-
213
- /**
214
- * @return string[]
215
- */
216
- protected function determineWizardSteps() {
217
-
218
- switch ( $this->getCurrentWizard() ) {
219
- case 'welcome':
220
- $aSteps = $this->determineWizardSteps_Welcome();
221
- break;
222
- case 'import':
223
- $aSteps = $this->determineWizardSteps_Import();
224
- break;
225
- default:
226
- $aSteps = array();
227
- break;
228
- }
229
-
230
- return $aSteps;
231
- }
232
-
233
- /**
234
- * @return string[]
235
- */
236
- private function determineWizardSteps_Import() {
237
- /** @var ICWP_WPSF_FeatureHandler_Plugin $oFO */
238
- $oFO = $this->getFeature();
239
-
240
- // Special case: user doesn't meet even the basic plugin admin permissions
241
- if ( !$oFO->getController()->getUserCanBasePerms() ) {
242
- return array( 'no_access' );
243
- }
244
-
245
- $aStepsSlugs = array(
246
- 'import_start',
247
- 'import_options',
248
- 'import_finished',
249
- );
250
-
251
- return $aStepsSlugs;
252
- }
253
-
254
- /**
255
- * @return string[]
256
- */
257
- private function determineWizardSteps_Welcome() {
258
- /** @var ICWP_WPSF_FeatureHandler_Plugin $oFO */
259
- $oFO = $this->getFeature();
260
-
261
- // Special case: user doesn't meet even the basic plugin admin permissions
262
- if ( !$oFO->getController()->getUserCanBasePerms() ) {
263
- return array( 'no_access' );
264
- }
265
-
266
- $aStepsSlugs = array( 'welcome' );
267
- if ( !$oFO->isPremium() ) {
268
- // $aStepsSlugs[] = 'license'; not showing it for now
269
- }
270
-
271
- if ( $oFO->isPremium() ) {
272
- $aStepsSlugs[] = 'import_options';
273
- }
274
-
275
- if ( !$this->getController()->getModule( 'admin_access_restriction' )->getIsMainFeatureEnabled() ) {
276
- $aStepsSlugs[] = 'admin_access_restriction';
277
- }
278
-
279
- /** @var ICWP_WPSF_FeatureHandler_AuditTrail $oModule */
280
- $oModule = $this->getController()->getModule( 'audit_trail' );
281
- if ( !$oModule->getIsMainFeatureEnabled() ) {
282
- $aStepsSlugs[] = 'audit_trail';
283
- }
284
-
285
- if ( !$this->getController()->getModule( 'ips' )->getIsMainFeatureEnabled() ) {
286
- $aStepsSlugs[] = 'ips';
287
- }
288
-
289
- /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oModule */
290
- $oModule = $this->getController()->getModule( 'login_protect' );
291
- if ( !( $oModule->getIsMainFeatureEnabled() && $oModule->isEnabledGaspCheck() ) ) {
292
- $aStepsSlugs[] = 'login_protect';
293
- }
294
-
295
- /** @var ICWP_WPSF_FeatureHandler_CommentsFilter $oModule */
296
- $oModule = $this->getController()->getModule( 'comments_filter' );
297
- if ( !( $oModule->getIsMainFeatureEnabled() && $oModule->isEnabledGaspCheck() ) ) {
298
- $aStepsSlugs[] = 'comments_filter';
299
- }
300
-
301
- $aStepsSlugs[] = 'how_shield_works';
302
- $aStepsSlugs[] = 'optin';
303
-
304
- if ( !$oFO->isPremium() ) {
305
- $aStepsSlugs[] = 'import_options';
306
- }
307
-
308
- $aStepsSlugs[] = 'thankyou';
309
- return $aStepsSlugs;
310
- }
311
-
312
- /**
313
- * @return array
314
- */
315
- protected function getWizardFirstStep() {
316
- return $this->getWizardNextStep( $this->determineWizardSteps(), -1 );
317
- }
318
-
319
- /**
320
- * @param array $aAllSteps
321
- * @param int $nCurrentStep
322
- * @return array
323
- */
324
- protected function getWizardNextStep( $aAllSteps, $nCurrentStep ) {
325
-
326
- // The assumption here is that the step data exists!
327
- $aStepData = $this->getWizardSteps()[ $aAllSteps[ $nCurrentStep + 1 ] ];
328
-
329
- $bRestrictedAccess = !isset( $aStepData[ 'restricted_access' ] ) || $aStepData[ 'restricted_access' ];
330
- try {
331
- if ( !$bRestrictedAccess || $this->getController()->getHasPermissionToManage() ) {
332
- $aData = $this->getRenderDataForStep( $aStepData[ 'slug' ] );
333
- $aStepData[ 'content' ] = $this->renderWizardStep( $aStepData[ 'slug' ], $aData );
334
- }
335
- else {
336
- $aStepData[ 'content' ] = $this->renderSecurityAdminVerifyWizardStep( $nCurrentStep );
337
- }
338
- }
339
- catch ( Exception $oE ) {
340
- $aStepData[ 'content' ] = 'Content could not be displayed due to error: '.$oE->getMessage();
341
- }
342
-
343
- return $aStepData;
344
- }
345
-
346
- /**
347
- * @param int $nIndex
348
- * @return string
349
- * @throws Exception
350
- */
351
- protected function renderSecurityAdminVerifyWizardStep( $nIndex ) {
352
- return $this->renderWizardStep( 'admin_access_restriction_verify', array( 'current_index' => $nIndex ) );
353
- }
354
-
355
- /**
356
- * @param string $sSlug
357
- * @return array
358
- */
359
- protected function getRenderDataForStep( $sSlug ) {
360
- /** @var ICWP_WPSF_FeatureHandler_Plugin $oFO */
361
- $oFO = $this->getFeature();
362
- $oConn = $this->getController();
363
-
364
- $aData = array(
365
- 'flags' => array(
366
- 'is_premium' => $oFO->isPremium()
367
- ),
368
- 'hrefs' => array(
369
- 'dashboard' => $oFO->getFeatureAdminPageUrl(),
370
- 'gopro' => 'http://icwp.io/ap',
371
- ),
372
- 'imgs' => array(),
373
- );
374
-
375
- $aAdd = array();
376
-
377
- switch ( $sSlug ) {
378
- case 'license':
379
- break;
380
- case 'import_options':
381
- $aAdd = array(
382
- 'hrefs' => array(
383
- 'blog_importexport' => 'http://icwp.io/av'
384
- ),
385
- 'imgs' => array(
386
- 'shieldnetworkmini' => $oConn->getPluginUrl_Image( 'shield/shieldnetworkmini.png' ),
387
- )
388
- );
389
- break;
390
-
391
- case 'optin':
392
- $oUser = $this->loadWpUsers()->getCurrentWpUser();
393
- $aAdd = array(
394
- 'data' => array(
395
- 'name' => $oUser->first_name,
396
- 'user_email' => $oUser->user_email
397
- )
398
- );
399
- break;
400
-
401
- case 'no_access':
402
- case 'thankyou':
403
- break;
404
-
405
- case 'how_shield_works':
406
- $aAdd = array(
407
- 'imgs' => array(
408
- 'how_shield_works' => $oConn->getPluginUrl_Image( 'wizard/general-shield_where.png' ),
409
- 'modules' => $oConn->getPluginUrl_Image( 'wizard/general-shield_modules.png' ),
410
- 'options' => $oConn->getPluginUrl_Image( 'wizard/general-shield_options.png' ),
411
- 'help' => $oConn->getPluginUrl_Image( 'wizard/general-shield_help.png' ),
412
- 'actions' => $oConn->getPluginUrl_Image( 'wizard/general-shield_actions.png' ),
413
- 'module_onoff' => $oConn->getPluginUrl_Image( 'wizard/general-module_onoff.png' ),
414
- 'option_help' => $oConn->getPluginUrl_Image( 'wizard/general-option_help.png' ),
415
- ),
416
- 'headings' => array(
417
- 'how_shield_works' => _wpsf__( 'Where to find Shield' ),
418
- 'modules' => _wpsf__( 'Accessing Each Module' ),
419
- 'options' => _wpsf__( 'Accessing Options' ),
420
- 'help' => _wpsf__( 'Finding Help' ),
421
- 'actions' => _wpsf__( 'Actions (not Options)' ),
422
- 'module_onoff' => _wpsf__( 'Module On/Off Switch' ),
423
- 'option_help' => _wpsf__( 'Help For Each Option' ),
424
- ),
425
- 'captions' => array(
426
- 'how_shield_works' => _wpsf__( "You'll find the main Shield Security setting in the left-hand WordPress menu." ),
427
- 'modules' => _wpsf__( 'Shield is split up into independent modules for accessing the options of each feature.' ),
428
- 'options' => _wpsf__( 'When you load a module, you can access the options by clicking on the Options Panel link.' ),
429
- 'help' => _wpsf__( 'Each module also has a brief overview help section - there is more in-depth help available.' ),
430
- 'actions' => _wpsf__( 'Certain modules have extra actions and features, e.g. Audit Trail Viewer.' )
431
- .' '._wpsf__( 'Note: Not all modules have the actions section' ),
432
- 'module_onoff' => _wpsf__( 'Each module has an Enable/Disable checkbox to turn on/off all processing for that module' ),
433
- 'option_help' => _wpsf__( 'To help you understand each option, most of them have a more info link, and/or a blog link, to read more' ),
434
- ),
435
- );
436
- break;
437
- default:
438
- break;
439
- }
440
-
441
- return $this->loadDP()->mergeArraysRecursive( $aData, $aAdd );
442
- }
443
-
444
- /**
445
- * @param string $sSlug
446
- * @param array $aRenderData
447
- * @return string
448
- * @throws Exception
449
- */
450
- protected function renderWizardStep( $sSlug, $aRenderData = array() ) {
451
- return $this->loadRenderer( $this->getController()->getPath_Templates() )
452
- ->setTemplate( sprintf( 'wizard/slide-%s.twig', $sSlug ) )
453
- ->setRenderVars( $aRenderData )
454
- ->setTemplateEngineTwig()
455
- ->render();
456
- }
457
-
458
- /**
459
- * @return array[]
460
- */
461
- private function getWizardSteps() {
462
- $aStandard = array(
463
- 'import_start' => array(
464
- 'title' => _wpsf__( 'Start Import' ),
465
- 'slug' => 'import_start',
466
- 'content' => '',
467
- 'restricted_access' => false
468
- ),
469
- 'import_finished' => array(
470
- 'title' => _wpsf__( 'Import Finished' ),
471
- 'slug' => 'import_finished',
472
- 'content' => '',
473
- 'restricted_access' => false
474
- ),
475
- 'no_access' => array(
476
- 'title' => _wpsf__( 'No Access' ),
477
- 'slug' => 'no_access',
478
- 'content' => '',
479
- 'restricted_access' => false
480
- ),
481
- 'welcome' => array(
482
- 'title' => _wpsf__( 'Welcome' ),
483
- 'slug' => 'welcome',
484
- 'content' => '',
485
- 'restricted_access' => false,
486
- ),
487
- 'license' => array(
488
- 'title' => _wpsf__( 'Go Pro' ),
489
- 'slug' => 'license',
490
- 'content' => '',
491
- ),
492
- 'import_options' => array(
493
- 'title' => _wpsf__( 'Import' ),
494
- 'slug' => 'import_options',
495
- 'content' => '',
496
- ),
497
- 'admin_access_restriction' => array(
498
- 'title' => _wpsf__( 'Security Admin' ),
499
- 'slug' => 'admin_access_restriction',
500
- 'content' => '',
501
- ),
502
- 'audit_trail' => array(
503
- 'title' => _wpsf__( 'Audit Trail' ),
504
- 'slug' => 'audit_trail',
505
- 'content' => '',
506
- ),
507
- 'ips' => array(
508
- 'title' => _wpsf__( 'IP Blacklist' ),
509
- 'slug' => 'ips',
510
- 'content' => '',
511
- ),
512
- 'login_protect' => array(
513
- 'title' => _wpsf__( 'Login Protection' ),
514
- 'slug' => 'login_protect',
515
- 'content' => '',
516
- ),
517
- 'comments_filter' => array(
518
- 'title' => _wpsf__( 'Comment SPAM' ),
519
- 'slug' => 'comments_filter',
520
- 'content' => '',
521
- ),
522
- 'how_shield_works' => array(
523
- 'title' => _wpsf__( 'How Shield Works' ),
524
- 'slug' => 'how_shield_works',
525
- 'content' => '',
526
- 'restricted_access' => false,
527
- ),
528
- 'optin' => array(
529
- 'title' => _wpsf__( 'Join Us!' ),
530
- 'slug' => 'optin',
531
- 'content' => '',
532
- ),
533
- 'thankyou' => array(
534
- 'title' => _wpsf__( 'Thank You' ),
535
- 'slug' => 'thankyou',
536
- 'content' => '',
537
- 'restricted_access' => false,
538
- )
539
- );
540
-
541
- return $aStandard;
542
- }
543
-
544
- /**
545
- * @return \FernleafSystems\Utilities\Response
546
- */
547
- private function wizardLicense() {
548
- $sKey = $this->loadDP()->post( 'LicenseKey' );
549
-
550
- $bSuccess = false;
551
- if ( empty( $sKey ) ) {
552
- $sMessage = 'License key was empty.';
553
- }
554
- else {
555
- /** @var ICWP_WPSF_FeatureHandler_License $oModule */
556
- $oModule = $this->getController()->getModule( 'license' );
557
- try {
558
- $oModule->activateOfficialLicense( $sKey, true );
559
- if ( $oModule->hasValidWorkingLicense() ) {
560
- $bSuccess = true;
561
- $sMessage = _wpsf__( 'License key was accepted and installed successfully.' );
562
- }
563
- else {
564
- $sMessage = _wpsf__( 'License key was not accepted.' );
565
- }
566
- }
567
- catch ( Exception $oE ) {
568
- $sMessage = _wpsf__( $oE->getMessage() );
569
- }
570
- }
571
-
572
- $oResponse = new \FernleafSystems\Utilities\Response();
573
- return $oResponse->setSuccessful( $bSuccess )
574
- ->setMessageText( $sMessage );
575
- }
576
-
577
- /**
578
- * @return \FernleafSystems\Utilities\Response
579
- */
580
- private function wizardImportOptions() {
581
- /** @var ICWP_WPSF_FeatureHandler_Plugin $oFO */
582
- $oFO = $this->getFeature();
583
- $oDP = $this->loadDP();
584
-
585
- $sMasterSiteUrl = $oDP->post( 'MasterSiteUrl' );
586
- $sSecretKey = $oDP->post( 'MasterSiteSecretKey' );
587
- $bEnabledNetwork = $oDP->post( 'ShieldNetworkCheck' ) === 'Y';
588
-
589
- /** @var ICWP_WPSF_Processor_Plugin $oProc */
590
- $oProc = $oFO->getProcessor();
591
- $nCode = $oProc->getSubProcessorImportExport()
592
- ->runImport( $sMasterSiteUrl, $sSecretKey, $bEnabledNetwork, $sSiteResponse );
593
-
594
- $aErrors = array(
595
- _wpsf__( 'Options imported successfully to your site.' ), // success
596
- _wpsf__( 'Secret key was empty.' ),
597
- _wpsf__( 'Secret key was not 40 characters long.' ),
598
- _wpsf__( 'Secret key contains invalid characters - it should be letters and numbers only.' ),
599
- _wpsf__( 'Source site URL could not be parsed correctly.' ),
600
- _wpsf__( 'Could not parse the response from the site.' )
601
- .' '._wpsf__( 'Check the secret key is correct for the remote site.' ),
602
- _wpsf__( 'Failure response returned from the site.' ),
603
- sprintf( _wpsf__( 'Remote site responded with - %s' ), $sSiteResponse ),
604
- _wpsf__( 'Data returned from the site was empty.' )
605
- );
606
-
607
- $sMessage = isset( $aErrors[ $nCode ] ) ? $aErrors[ $nCode ] : 'Unknown Error';
608
-
609
- $oResponse = new \FernleafSystems\Utilities\Response();
610
- return $oResponse->setSuccessful( $nCode === 0 )
611
- ->setMessageText( $sMessage );
612
- }
613
-
614
- /**
615
- * @return \FernleafSystems\Utilities\Response
616
- */
617
- private function wizardSecurityAdminVerify() {
618
- $sKey = $this->loadDP()->post( 'AccessKey' );
619
-
620
- $oResponse = new \FernleafSystems\Utilities\Response();
621
-
622
- $bSuccess = false;
623
- /** @var ICWP_WPSF_FeatureHandler_AdminAccessRestriction $oModule */
624
- $oModule = $this->getController()->getModule( 'admin_access_restriction' );
625
-
626
- $sMessage = '';
627
- if ( empty( $sKey ) ) {
628
- $sMessage = 'Security access key was empty.';
629
- }
630
- else if ( !$oModule->verifyAccessKey( $sKey ) ) {
631
- $sMessage = _wpsf__( 'Security Admin Key was not correct.' );
632
- }
633
- else {
634
- $bSuccess = true;
635
- $oModule->setPermissionToSubmit( true );
636
- $aData = array(
637
- 'rerender' => true
638
- );
639
- $oResponse->setData( $aData );
640
- }
641
-
642
- return $oResponse->setSuccessful( $bSuccess )
643
- ->setMessageText( $sMessage );
644
- }
645
-
646
- /**
647
- * @return \FernleafSystems\Utilities\Response
648
- */
649
- private function wizardSecurityAdmin() {
650
- $oDP = $this->loadDP();
651
- $sKey = $oDP->post( 'AccessKey' );
652
- $sConfirm = $oDP->post( 'AccessKeyConfirm' );
653
-
654
- $oResponse = new \FernleafSystems\Utilities\Response();
655
-
656
- $bSuccess = false;
657
- if ( empty( $sKey ) ) {
658
- $sMessage = 'Security access key was empty.';
659
- }
660
- else if ( $sKey != $sConfirm ) {
661
- $sMessage = 'Keys do not match.';
662
- }
663
- else {
664
- /** @var ICWP_WPSF_FeatureHandler_AdminAccessRestriction $oModule */
665
- $oModule = $this->getController()->getModule( 'admin_access_restriction' );
666
- try {
667
- $oModule->setNewAccessKeyManually( $sKey )
668
- ->setPermissionToSubmit( true );
669
- $bSuccess = true;
670
- $sMessage = _wpsf__( 'Security Admin setup was successful.' );
671
- }
672
- catch ( Exception $oE ) {
673
- $sMessage = _wpsf__( $oE->getMessage() );
674
- }
675
- }
676
-
677
- return $oResponse->setSuccessful( $bSuccess )
678
- ->setMessageText( $sMessage );
679
- }
680
-
681
- /**
682
- * @return \FernleafSystems\Utilities\Response
683
- */
684
- private function wizardAuditTrail() {
685
- $bEnabled = $this->loadDP()->post( 'AuditTrailOption' ) === 'Y';
686
-
687
- /** @var ICWP_WPSF_FeatureHandler_AdminAccessRestriction $oModule */
688
- $oModule = $this->getController()->getModule( 'audit_trail' );
689
- $oModule->setIsMainFeatureEnabled( $bEnabled )
690
- ->savePluginOptions();
691
-
692
- $bSuccess = $oModule->getIsMainFeatureEnabled() === $bEnabled;
693
- if ( $bSuccess ) {
694
- $sMessage = sprintf( '%s has been %s.', _wpsf__( 'Audit Trail' ),
695
- $oModule->getIsMainFeatureEnabled() ? _wpsf__( 'Enabled' ) : _wpsf__( 'Disabled' )
696
- );
697
- }
698
- else {
699
- $sMessage = sprintf( _wpsf__( '%s setting could not be changed at this time.' ), _wpsf__( 'Audit Trail' ) );
700
- }
701
-
702
- $oResponse = new \FernleafSystems\Utilities\Response();
703
- return $oResponse->setSuccessful( $bSuccess )
704
- ->setMessageText( $sMessage );
705
- }
706
-
707
- /**
708
- * @return \FernleafSystems\Utilities\Response
709
- */
710
- private function wizardIps() {
711
-
712
- $bEnabled = $this->loadDP()->post( 'IpManagerOption' ) === 'Y';
713
-
714
- /** @var ICWP_WPSF_FeatureHandler_Ips $oModule */
715
- $oModule = $this->getController()->getModule( 'ips' );
716
- $oModule->setIsMainFeatureEnabled( $bEnabled )
717
- ->savePluginOptions();
718
-
719
- $bSuccess = $oModule->getIsMainFeatureEnabled() === $bEnabled;
720
- if ( $bSuccess ) {
721
- $sMessage = sprintf( '%s has been %s.', _wpsf__( 'IP Manager' ),
722
- $oModule->getIsMainFeatureEnabled() ? _wpsf__( 'Enabled' ) : _wpsf__( 'Disabled' )
723
- );
724
- }
725
- else {
726
- $sMessage = sprintf( _wpsf__( '%s setting could not be changed at this time.' ), _wpsf__( 'IP Manager' ) );
727
- }
728
-
729
- $oResponse = new \FernleafSystems\Utilities\Response();
730
- return $oResponse->setSuccessful( $bSuccess )
731
- ->setMessageText( $sMessage );
732
- }
733
-
734
- /**
735
- * @return \FernleafSystems\Utilities\Response
736
- */
737
- private function wizardLoginProtect() {
738
-
739
- $bEnabled = $this->loadDP()->post( 'LoginProtectOption' ) === 'Y';
740
-
741
- /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oModule */
742
- $oModule = $this->getController()->getModule( 'login_protect' );
743
- if ( $bEnabled ) { // we don't disable the whole module
744
- $oModule->setIsMainFeatureEnabled( true );
745
- }
746
- $oModule->setEnabledGaspCheck( $bEnabled )
747
- ->savePluginOptions();
748
-
749
- $bSuccess = $oModule->getIsMainFeatureEnabled() === $bEnabled;
750
- if ( $bSuccess ) {
751
- $sMessage = sprintf( '%s has been %s.', _wpsf__( 'Login Protection' ),
752
- $oModule->getIsMainFeatureEnabled() ? _wpsf__( 'Enabled' ) : _wpsf__( 'Disabled' )
753
- );
754
- }
755
- else {
756
- $sMessage = sprintf( _wpsf__( '%s setting could not be changed at this time.' ), _wpsf__( 'Login Protection' ) );
757
- }
758
-
759
- $oResponse = new \FernleafSystems\Utilities\Response();
760
- return $oResponse->setSuccessful( $bSuccess )
761
- ->setMessageText( $sMessage );
762
- }
763
-
764
- /**
765
- * @return \FernleafSystems\Utilities\Response
766
- */
767
- private function wizardOptin() {
768
- $oDP = $this->loadDP();
769
-
770
- $bEnabledTracking = $oDP->post( 'AnonymousOption', 'N', true ) === 'Y';
771
- $bEnabledBadge = $oDP->post( 'BadgeOption', 'N', true ) === 'Y';
772
-
773
- /** @var ICWP_WPSF_FeatureHandler_Plugin $oModule */
774
- $oModule = $this->getController()->getModule( 'plugin' );
775
- $oModule->setIsDisplayPluginBadge( $bEnabledBadge )
776
- ->setPluginTrackingPermission( $bEnabledTracking );
777
-
778
- $sMessage = _wpsf__( 'Preferences have been saved.' );
779
-
780
- $oResponse = new \FernleafSystems\Utilities\Response();
781
- return $oResponse->setSuccessful( true )
782
- ->setMessageText( $sMessage );
783
- }
784
-
785
- /**
786
- * @return \FernleafSystems\Utilities\Response
787
- */
788
- private function wizardCommentsFilter() {
789
-
790
- $bEnabled = $this->loadDP()->post( 'CommentsFilterOption' ) === 'Y';
791
-
792
- /** @var ICWP_WPSF_FeatureHandler_CommentsFilter $oModule */
793
- $oModule = $this->getController()->getModule( 'comments_filter' );
794
- if ( $bEnabled ) { // we don't disable the whole module
795
- $oModule->setIsMainFeatureEnabled( true );
796
- }
797
- $oModule->setEnabledGasp( $bEnabled )
798
- ->savePluginOptions();
799
-
800
- $bSuccess = $oModule->getIsMainFeatureEnabled() === $bEnabled;
801
- if ( $bSuccess ) {
802
- $sMessage = sprintf( '%s has been %s.', _wpsf__( 'Comment SPAM Protection' ),
803
- $oModule->getIsMainFeatureEnabled() ? _wpsf__( 'Enabled' ) : _wpsf__( 'Disabled' )
804
- );
805
- }
806
- else {
807
- $sMessage = sprintf( _wpsf__( '%s setting could not be changed at this time.' ), _wpsf__( 'Comment SPAM Protection' ) );
808
- }
809
-
810
- $oResponse = new \FernleafSystems\Utilities\Response();
811
- return $oResponse->setSuccessful( $bSuccess )
812
- ->setMessageText( $sMessage );
813
- }
814
-
815
- /**
816
- * @return string
817
- */
818
- public function getCurrentWizard() {
819
- return $this->sCurrentWizard;
820
- }
821
-
822
- /**
823
- * @param string $sCurrentWizard
824
- * @return $this
825
- */
826
- public function setCurrentWizard( $sCurrentWizard ) {
827
- $this->sCurrentWizard = $sCurrentWizard;
828
- return $this;
829
- }
830
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/wizards/base.php ADDED
@@ -0,0 +1,537 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( class_exists( 'ICWP_WPSF_Wizard_Base', false ) ) {
4
+ return;
5
+ }
6
+
7
+ /**
8
+ * @uses php 5.4+
9
+ * Class ICWP_WPSF_Wizard_Base
10
+ */
11
+ abstract class ICWP_WPSF_Wizard_Base extends ICWP_WPSF_Foundation {
12
+
13
+ /**
14
+ * @var string
15
+ */
16
+ private $sCurrentWizard;
17
+
18
+ /**
19
+ * @var ICWP_WPSF_FeatureHandler_Base
20
+ */
21
+ protected $oModule;
22
+
23
+ /**
24
+ * @param ICWP_WPSF_FeatureHandler_Base $oFeatureOptions
25
+ */
26
+ public function __construct( ICWP_WPSF_FeatureHandler_Base $oFeatureOptions ) {
27
+ $this->oModule = $oFeatureOptions;
28
+ }
29
+
30
+ /**
31
+ */
32
+ public function init() {
33
+ add_action( 'wp_loaded', array( $this, 'onWpLoaded' ), 0 );
34
+ }
35
+
36
+ /**
37
+ * Ensure to only ever process supported wizards
38
+ */
39
+ public function ajaxWizardRenderStep() {
40
+ $oDP = $this->loadDP();
41
+
42
+ try {
43
+ $this->setCurrentWizard( $oDP->post( 'wizard_slug' ) );
44
+ if ( $this->getUserCan() ) {
45
+ $aNextStep = $this->buildNextStep(
46
+ $oDP->post( 'wizard_steps' ),
47
+ (int)$oDP->post( 'current_index' )
48
+ );
49
+ $this->getModCon()
50
+ ->sendAjaxResponse(
51
+ true,
52
+ array( 'next_step' => $aNextStep )
53
+ );
54
+ }
55
+ else {
56
+ $this->loadWp()
57
+ ->wpDie( 'Please login to run this wizard.' );
58
+ }
59
+ }
60
+ catch ( Exception $oE ) {
61
+ }
62
+ }
63
+
64
+ public function onWpLoaded() {
65
+ $sWizard = $this->loadDP()->query( 'wizard' );
66
+ try {
67
+ $this->setCurrentWizard( $sWizard );
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
+ }
89
+ }
90
+
91
+ /**
92
+ * @uses echo()
93
+ */
94
+ protected function loadWizard() {
95
+ try {
96
+ $sContent = $this->renderWizard();
97
+ }
98
+ catch ( Exception $oE ) {
99
+ $sContent = $oE->getMessage();
100
+ }
101
+ echo $sContent;
102
+ die();
103
+ }
104
+
105
+ /**
106
+ * @uses echo()
107
+ */
108
+ protected function loadWizardLanding() {
109
+ try {
110
+ $sContent = $this->loadRenderer( $this->getModCon()->getController()->getPath_Templates() )
111
+ ->setTemplate( 'wizard/pages/landing.twig' )
112
+ ->setRenderVars( $this->getRenderData_PageWizardLanding() )
113
+ ->setTemplateEngineTwig()
114
+ ->render();
115
+ }
116
+ catch ( Exception $oE ) {
117
+ $sContent = $oE->getMessage();
118
+ }
119
+ echo $sContent;
120
+ die();
121
+ }
122
+
123
+ /**
124
+ * @param string $sSlug
125
+ * @return bool
126
+ */
127
+ protected function isSupportedWizard( $sSlug ) {
128
+ return in_array( $sSlug, $this->getSupportedWizards() );
129
+ }
130
+
131
+ /**
132
+ * @param string $sPerm
133
+ * @return bool
134
+ */
135
+ protected function getUserCan( $sPerm = null ) {
136
+ if ( empty( $sPerm ) ) {
137
+ $sPerm = 'manage_options';
138
+ }
139
+ return $sPerm == 'none' || current_user_can( $sPerm );
140
+ }
141
+
142
+ /**
143
+ * @param string $sSlide
144
+ * @return bool
145
+ */
146
+ protected function getUserCanSlide( $sSlide ) {
147
+ return $this->getUserCan();
148
+ }
149
+
150
+ /**
151
+ * @return string[] the array of wizard slugs supported
152
+ */
153
+ protected function getSupportedWizards() {
154
+ return array_keys( $this->getModCon()->getWizardDefinitions() );
155
+ }
156
+
157
+ public function ajaxWizardProcessStepSubmit() {
158
+ $this->loadAutoload(); // for Response
159
+ $oResponse = $this->processWizardStep( $this->loadDP()->post( 'wizard-step' ) );
160
+ if ( !empty( $oResponse ) ) {
161
+ $this->sendWizardResponse( $oResponse );
162
+ }
163
+ }
164
+
165
+ /**
166
+ * @param string $sStep
167
+ * @return \FernleafSystems\Utilities\Response|null
168
+ */
169
+ protected function processWizardStep( $sStep ) {
170
+ switch ( $sStep ) {
171
+ default:
172
+ $oResponse = null; // we don't process any steps we don't recognise.
173
+ break;
174
+ }
175
+ return $oResponse;
176
+ }
177
+
178
+ /**
179
+ * @param \FernleafSystems\Utilities\Response $oResponse
180
+ */
181
+ protected function sendWizardResponse( $oResponse ) {
182
+
183
+ $sMessage = $oResponse->getMessageText();
184
+ if ( $oResponse->successful() ) {
185
+ $sMessage .= '<br />'.sprintf( 'Please click %s to continue.', __( 'Next Step' ) );
186
+ }
187
+ else {
188
+ $sMessage = sprintf( '%s: %s', __( 'Error' ), $sMessage );
189
+ }
190
+
191
+ $aData = $oResponse->getData();
192
+ $aData[ 'message' ] = $sMessage;
193
+ $oResponse->setData( $aData );
194
+
195
+ $this->getModCon()
196
+ ->sendAjaxResponse( $oResponse->successful(), $aData );
197
+ }
198
+
199
+ /**
200
+ * @return string
201
+ * @throws Exception
202
+ */
203
+ protected function renderWizard() {
204
+ return $this->loadRenderer( $this->getModCon()->getController()->getPath_Templates() )
205
+ ->setTemplate( 'wizard/pages/wizard.twig' )
206
+ ->setRenderVars( $this->getRenderData_PageWizard() )
207
+ ->setTemplateEngineTwig()
208
+ ->render();
209
+ }
210
+
211
+ /**
212
+ * @return array[]
213
+ */
214
+ protected function getModuleWizardsForRender() {
215
+ /** @var ICWP_WPSF_FeatureHandler_Base $oFO */
216
+ $oFO = $this->getModCon();
217
+ $aWizards = $oFO->getWizardDefinitions();
218
+ foreach ( $aWizards as $sKey => &$aWizard ) {
219
+ $aWizard[ 'has_perm' ] = $this->getUserCan( $aWizard[ 'min_user_permissions' ] );
220
+ $aWizard[ 'url' ] = $oFO->getUrl_Wizard( $sKey );
221
+ $aWizard[ 'has_premium' ] = isset( $aWizard[ 'has_premium' ] ) && $aWizard[ 'has_premium' ];
222
+ }
223
+ return $aWizards;
224
+ }
225
+
226
+ /**
227
+ * @return array[]
228
+ */
229
+ protected function getRenderData_PageWizardLanding() {
230
+ /** @var ICWP_WPSF_FeatureHandler_Base $oFO */
231
+ $oFO = $this->getModCon();
232
+
233
+ $aWizards = $this->getModuleWizardsForRender();
234
+
235
+ return $this->loadDP()->mergeArraysRecursive(
236
+ $this->getRenderData_TwigPageBase(),
237
+ array(
238
+ 'strings' => array(
239
+ 'page_title' => 'Select Your Wizard',
240
+ 'premium_note' => 'Note: This uses features only available to Pro-licensed installations.'
241
+ ),
242
+ 'data' => array(
243
+ 'mod_wizards_count' => count( $aWizards ),
244
+ 'mod_wizards' => $aWizards
245
+ ),
246
+ 'hrefs' => array(
247
+ 'dashboard' => $oFO->getUrl_AdminPage(),
248
+ 'goprofooter' => 'http://icwp.io/goprofooter',
249
+ ),
250
+ 'ajax' => array(
251
+ 'content' => $oFO->getBaseAjaxActionRenderData( 'WizardProcessStepSubmit' ),
252
+ 'steps' => $oFO->getBaseAjaxActionRenderData( 'WizardRenderStep' ),
253
+ 'steps_as_json' => $oFO->getBaseAjaxActionRenderData( 'WizardRenderStep', true ),
254
+ )
255
+ )
256
+ );
257
+ }
258
+
259
+ /**
260
+ * TODO: Abstract and move elsewhere - it's here because Wizards on the only consumer of twig templates
261
+ * @return array
262
+ */
263
+ protected function getRenderData_TwigPageBase() {
264
+ $oCon = $this->getModCon()->getController();
265
+ return array(
266
+ 'strings' => array(
267
+ 'page_title' => 'Twig Page'
268
+ ),
269
+ 'data' => array(),
270
+ 'hrefs' => array(
271
+ 'form_action' => $this->loadDP()->getRequestUri(),
272
+ 'css_bootstrap' => $oCon->getPluginUrl_Css( 'bootstrap3.min.css' ),
273
+ 'css_pages' => $oCon->getPluginUrl_Css( 'pages.css' ),
274
+ 'css_steps' => $oCon->getPluginUrl_Css( 'jquery.steps.css' ),
275
+ 'css_fancybox' => $oCon->getPluginUrl_Css( 'jquery.fancybox.min.css' ),
276
+ 'css_globalplugin' => $oCon->getPluginUrl_Css( 'global-plugin.css' ),
277
+ 'css_wizard' => $oCon->getPluginUrl_Css( 'wizard.css' ),
278
+ 'js_jquery' => $this->loadWpIncludes()->getUrl_Jquery(),
279
+ 'js_bootstrap' => $oCon->getPluginUrl_Js( 'bootstrap3.min.js' ),
280
+ 'js_fancybox' => $oCon->getPluginUrl_Js( 'jquery.fancybox.min.js' ),
281
+ 'js_globalplugin' => $oCon->getPluginUrl_Js( 'global-plugin.js' ),
282
+ 'js_steps' => $oCon->getPluginUrl_Js( 'jquery.steps.min.js' ),
283
+ 'js_wizard' => $oCon->getPluginUrl_Js( 'wizard.js' ),
284
+ 'plugin_banner' => $oCon->getPluginUrl_Image( 'banner-1500x500-transparent.png' ),
285
+ 'favicon' => $oCon->getPluginUrl_Image( 'pluginlogo_24x24.png' ),
286
+ ),
287
+ 'ajax' => array(),
288
+ 'flags' => array(
289
+ 'is_premium' => $this->getModCon()->isPremium(),
290
+ )
291
+ );
292
+ }
293
+
294
+ /**
295
+ * @return array
296
+ */
297
+ protected function getRenderData_PageWizard() {
298
+ /** @var ICWP_WPSF_FeatureHandler_Plugin $oFO */
299
+ $oFO = $this->getModCon();
300
+ return $this->loadDP()->mergeArraysRecursive(
301
+ $this->getRenderData_TwigPageBase(),
302
+ array(
303
+ 'strings' => array(
304
+ 'page_title' => $this->getPageTitle()
305
+ ),
306
+ 'data' => array(
307
+ 'wizard_slug' => $this->getWizardSlug(),
308
+ 'wizard_steps' => json_encode( $this->buildSteps() ),
309
+ 'wizard_first_step' => json_encode( $this->getWizardFirstStep() ),
310
+ ),
311
+ 'hrefs' => array(
312
+ 'dashboard' => $oFO->getUrl_AdminPage(),
313
+ 'goprofooter' => 'http://icwp.io/goprofooter',
314
+ ),
315
+ 'ajax' => array(
316
+ 'content' => $oFO->getBaseAjaxActionRenderData( 'WizardProcessStepSubmit' ),
317
+ 'steps' => $oFO->getBaseAjaxActionRenderData( 'WizardRenderStep' ),
318
+ 'steps_as_json' => $oFO->getBaseAjaxActionRenderData( 'WizardRenderStep', true ),
319
+ )
320
+ )
321
+ );
322
+ }
323
+
324
+ /**
325
+ * @return string
326
+ */
327
+ protected function getPageTitle() {
328
+ return sprintf( _wpsf__( '%s Wizard' ), $this->getModCon()->getController()->getHumanName() );
329
+ }
330
+
331
+ /**
332
+ * @return string[]
333
+ */
334
+ protected function buildSteps() {
335
+ return $this->getUserCan() ? $this->determineWizardSteps() : array( 'no_access' );
336
+ }
337
+
338
+ /**
339
+ * @throws Exception
340
+ */
341
+ protected function determineWizardSteps() {
342
+ throw new Exception( sprintf( 'Could not determine wizard steps for current wizard: %s', $this->getWizardSlug() ) );
343
+ }
344
+
345
+ /**
346
+ * @return array
347
+ */
348
+ protected function getWizardFirstStep() {
349
+ return $this->buildNextStep( $this->buildSteps(), -1 );
350
+ }
351
+
352
+ protected function getNextStepDefinition( $aStepsInThisInstance, $nCurrentStep ) {
353
+ }
354
+
355
+ /**
356
+ * @param array $aStepsInThisInstance
357
+ * @param int $nCurrentPos
358
+ * @return array
359
+ */
360
+ protected function buildNextStep( $aStepsInThisInstance, $nCurrentPos ) {
361
+ $aNextStepDef = $this->getNextStep( $aStepsInThisInstance, $nCurrentPos );
362
+
363
+ try {
364
+ $aNextStepDef[ 'content' ] = $this->renderWizardStep( $aNextStepDef[ 'slug' ] );
365
+ }
366
+ catch ( Exception $oE ) {
367
+ $aNextStepDef[ 'content' ] = 'Content could not be displayed due to error: '.$oE->getMessage();
368
+ }
369
+
370
+ return $aNextStepDef;
371
+ }
372
+
373
+ /**
374
+ * @param array $aStepsInThisInstance
375
+ * @param int $nCurrentPos
376
+ * @return array
377
+ */
378
+ protected function getNextStep( $aStepsInThisInstance, $nCurrentPos ) {
379
+ // The assumption here is that the step data exists!
380
+ $sNextStepKey = $aStepsInThisInstance[ $nCurrentPos + 1 ];
381
+ return $this->getStepsDefinition()[ $sNextStepKey ];
382
+ }
383
+
384
+ /**
385
+ * @param string $sStep
386
+ * @return array
387
+ */
388
+ protected function getRenderData_Slide( $sStep ) {
389
+ return $this->loadDP()->mergeArraysRecursive(
390
+ $this->getRenderData_SlideBase(),
391
+ $this->getRenderData_SlideExtra( $sStep )
392
+ );
393
+ }
394
+
395
+ /**
396
+ * @return array
397
+ */
398
+ protected function getRenderData_SlideBase() {
399
+ $oFO = $this->getModCon();
400
+ $aWizards = $this->getModuleWizardsForRender();
401
+ return array(
402
+ 'flags' => array(
403
+ 'is_premium' => $oFO->isPremium(),
404
+ 'has_other_wizards' => false
405
+ ),
406
+ 'hrefs' => array(
407
+ 'dashboard' => $oFO->getUrl_AdminPage(),
408
+ 'gopro' => 'http://icwp.io/ap',
409
+ ),
410
+ 'imgs' => array(),
411
+ 'data' => array(
412
+ 'mod_wizards_count' => count( $aWizards ),
413
+ 'mod_wizards' => $aWizards
414
+ ),
415
+ );
416
+ }
417
+
418
+ /**
419
+ * @param string $sStep
420
+ * @return array
421
+ */
422
+ protected function getRenderData_SlideExtra( $sStep ) {
423
+ return array();
424
+ }
425
+
426
+ /**
427
+ * @param string $sSlug
428
+ * @return string
429
+ * @throws Exception
430
+ */
431
+ protected function renderWizardStep( $sSlug ) {
432
+
433
+ $sTemplateSlug = $sSlug;
434
+ if ( strpos( $sSlug, '/' ) === false ) {
435
+ $sBase = $this->isSlideCommon( $sSlug ) ? 'common' : $this->getWizardSlug();
436
+ $sTemplateSlug = sprintf( '%s/%s', $sBase, $sSlug );
437
+ }
438
+
439
+ return $this->loadRenderer( $this->getModCon()->getController()->getPath_Templates() )
440
+ ->setTemplate( sprintf( 'wizard/slides/%s.twig', $sTemplateSlug ) )
441
+ ->setRenderVars( $this->getRenderData_Slide( $sSlug ) )
442
+ ->setTemplateEngineTwig()
443
+ ->render();
444
+ }
445
+
446
+ /**
447
+ * @param string $sSlideSlug
448
+ * @return bool
449
+ */
450
+ protected function isSlideCommon( $sSlideSlug ) {
451
+ return in_array( $sSlideSlug, [ 'no_access' ] );
452
+ }
453
+
454
+ /**
455
+ * @return array[]
456
+ */
457
+ protected function getAllDefinedSteps() {
458
+ return $this->getWizard()[ 'steps' ];
459
+ }
460
+
461
+ /**
462
+ * @return array[]
463
+ */
464
+ protected function getStepsDefinition() {
465
+ $aNoAccess = array(
466
+ 'no_access' => array(
467
+ 'title' => _wpsf__( 'No Access' ),
468
+ )
469
+ );
470
+ $aSteps = array_merge( $this->getAllDefinedSteps(), $aNoAccess );
471
+ foreach ( $aSteps as $sSlug => $aStep ) {
472
+ $aSteps[ $sSlug ][ 'slug' ] = $sSlug;
473
+ $aSteps[ $sSlug ][ 'content' ] = '';
474
+ }
475
+ return $aSteps;
476
+ }
477
+
478
+ /**
479
+ * @return string
480
+ */
481
+ public function getWizardSlug() {
482
+ return $this->sCurrentWizard;
483
+ }
484
+
485
+ /**
486
+ * @return array
487
+ */
488
+ public function getWizard() {
489
+ return $this->getModCon()->getWizardDefinitions()[ $this->getWizardSlug() ];
490
+ }
491
+
492
+ /**
493
+ * @param string $sKey
494
+ * @return array
495
+ */
496
+ public function getWizardProperty( $sKey ) {
497
+ $aW = $this->getWizard();
498
+ return isset( $aW[ $sKey ] ) ? $aW[ $sKey ] : null;
499
+ }
500
+
501
+ /**
502
+ * @param string $sCurrentWizard
503
+ * @return $this
504
+ * @throws Exception
505
+ */
506
+ public function setCurrentWizard( $sCurrentWizard ) {
507
+ if ( empty( $sCurrentWizard ) || !$this->isSupportedWizard( $sCurrentWizard ) ) {
508
+ throw new Exception( 'Not a supported wizard.' );
509
+ }
510
+ $this->sCurrentWizard = $sCurrentWizard;
511
+ return $this;
512
+ }
513
+
514
+ /**
515
+ * @return ICWP_WPSF_FeatureHandler_Base
516
+ */
517
+ protected function getModCon() {
518
+ return $this->oModule;
519
+ }
520
+
521
+ /**
522
+ * @return ICWP_WPSF_Plugin_Controller
523
+ */
524
+ protected function getPluginCon() {
525
+ return $this->getModCon()->getConn();
526
+ }
527
+
528
+ /**
529
+ * @return false|int
530
+ */
531
+ protected function verifyNonce( $sWizard = null ) {
532
+ if ( is_null( $sWizard ) ) {
533
+ $sWizard = $this->getWizardSlug();
534
+ }
535
+ return wp_verify_nonce( $this->loadDP()->query( 'nonwizard' ), 'wizard'.$sWizard );
536
+ }
537
+ }
src/wizards/base_wpsf.php ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( class_exists( 'ICWP_WPSF_Wizard_Base', false ) ) {
4
+ return;
5
+ }
6
+
7
+ require_once( dirname( __FILE__ ).'/base.php' );
8
+
9
+ /**
10
+ * Class ICWP_WPSF_Wizard_BaseWpsf
11
+ */
12
+ abstract class ICWP_WPSF_Wizard_BaseWpsf extends ICWP_WPSF_Wizard_Base {
13
+
14
+ /**
15
+ * @param string $sSlide
16
+ * @return bool
17
+ */
18
+ protected function getUserCanSlide( $sSlide ) {
19
+ $aSlide = $this->getStepsDefinition()[ $sSlide ];
20
+ $bRestricted = !isset( $aSlide[ 'security_admin' ] ) || $aSlide[ 'security_admin' ];
21
+ return !$bRestricted || $this->getPluginCon()->getHasPermissionToManage();
22
+ }
23
+
24
+ /**
25
+ * @param array $aStepsInThisInstance
26
+ * @param int $nCurrentPos
27
+ * @return array
28
+ */
29
+ protected function getNextStep( $aStepsInThisInstance, $nCurrentPos ) {
30
+ $aNext = parent::getNextStep( $aStepsInThisInstance, $nCurrentPos );
31
+ if ( !$this->getUserCanSlide( $aNext[ 'slug' ] ) ) {
32
+ $aNext = $this->getStepsDefinition()[ 'security_admin_verify' ];
33
+ }
34
+ return $aNext;
35
+ }
36
+
37
+ /**
38
+ * @param string $sStep
39
+ * @return array
40
+ */
41
+ protected function getRenderData_SlideExtra( $sStep ) {
42
+
43
+ switch ( $sStep ) {
44
+ case 'security_admin_verify':
45
+ $aAdditional = array( 'current_index' => $this->loadDP()->post( 'current_index' ) );
46
+ break;
47
+ default:
48
+ $aAdditional = parent::getRenderData_SlideExtra( $sStep );
49
+ break;
50
+ }
51
+
52
+ return $aAdditional;
53
+ }
54
+
55
+ /**
56
+ * @return array[]
57
+ */
58
+ protected function getStepsDefinition() {
59
+ return array_merge(
60
+ parent::getStepsDefinition(),
61
+ array(
62
+ 'security_admin_verify' => array(
63
+ 'content' => '',
64
+ 'slug' => 'security_admin_verify',
65
+ 'title' => _wpsf__( 'Security Admin' ),
66
+ 'security_admin' => false
67
+ )
68
+ )
69
+ );
70
+ }
71
+
72
+ /**
73
+ * @param string $sSlideSlug
74
+ * @return bool
75
+ */
76
+ protected function isSlideCommon( $sSlideSlug ) {
77
+ return parent::isSlideCommon( $sSlideSlug ) || in_array( $sSlideSlug, [ 'security_admin_verify' ] );
78
+ }
79
+
80
+ /**
81
+ * @param string $sStep
82
+ * @return \FernleafSystems\Utilities\Response|null
83
+ */
84
+ protected function processWizardStep( $sStep ) {
85
+ switch ( $sStep ) {
86
+ case 'security_admin_verify':
87
+ $oResponse = $this->wizardSecurityAdminVerify();
88
+ break;
89
+ default:
90
+ $oResponse = parent::processWizardStep( $sStep );
91
+ break;
92
+ }
93
+ return $oResponse;
94
+ }
95
+
96
+ /**
97
+ * @return \FernleafSystems\Utilities\Response
98
+ */
99
+ private function wizardSecurityAdminVerify() {
100
+ $sKey = $this->loadDP()->post( 'AccessKey' );
101
+
102
+ $oResponse = new \FernleafSystems\Utilities\Response();
103
+
104
+ $bSuccess = false;
105
+ /** @var ICWP_WPSF_FeatureHandler_AdminAccessRestriction $oModule */
106
+ $oModule = $this->getPluginCon()->getModule( 'admin_access_restriction' );
107
+
108
+ $sMessage = '';
109
+ if ( empty( $sKey ) ) {
110
+ $sMessage = 'Security access key was empty.';
111
+ }
112
+ else if ( !$oModule->verifyAccessKey( $sKey ) ) {
113
+ $sMessage = _wpsf__( 'Security Admin Key was not correct.' );
114
+ }
115
+ else {
116
+ $bSuccess = true;
117
+ $oModule->setPermissionToSubmit( true );
118
+ $aData = array(
119
+ 'rerender' => true
120
+ );
121
+ $oResponse->setData( $aData );
122
+ }
123
+
124
+ return $oResponse->setSuccessful( $bSuccess )
125
+ ->setMessageText( $sMessage );
126
+ }
127
+ }
src/wizards/hack_protect.php ADDED
@@ -0,0 +1,346 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( class_exists( 'ICWP_WPSF_Wizard_HackProtect', false ) ) {
4
+ return;
5
+ }
6
+
7
+ require_once( dirname( __FILE__ ).'/base_wpsf.php' );
8
+
9
+ /**
10
+ * Class ICWP_WPSF_Wizard_HackProtect
11
+ */
12
+ class ICWP_WPSF_Wizard_HackProtect extends ICWP_WPSF_Wizard_BaseWpsf {
13
+
14
+ /**
15
+ * @return string
16
+ */
17
+ protected function getPageTitle() {
18
+ return sprintf( _wpsf__( '%s Hack Protect Wizard' ), $this->getPluginCon()->getHumanName() );
19
+ }
20
+
21
+ /**
22
+ * @param string $sStep
23
+ * @return \FernleafSystems\Utilities\Response|null
24
+ */
25
+ protected function processWizardStep( $sStep ) {
26
+ switch ( $sStep ) {
27
+ case 'exclusions':
28
+ $oResponse = $this->process_Exclusions();
29
+ break;
30
+ case 'deletefiles':
31
+ $oResponse = $this->process_DeleteFiles();
32
+ break;
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;
45
+ }
46
+ return $oResponse;
47
+ }
48
+
49
+ /**
50
+ * @return \FernleafSystems\Utilities\Response
51
+ */
52
+ private function process_Exclusions() {
53
+ /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
54
+ $oFO = $this->getModCon();
55
+ $oFO->setUfcFileExclusions( explode( "\n", $this->loadDP()->post( 'exclusions' ) ) );
56
+
57
+ $oResponse = new \FernleafSystems\Utilities\Response();
58
+ return $oResponse->setSuccessful( true )
59
+ ->setMessageText( 'File exclusions list has been updated.' );
60
+ }
61
+
62
+ /**
63
+ * @return \FernleafSystems\Utilities\Response
64
+ */
65
+ private function process_DeleteFiles() {
66
+ /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
67
+ $oFO = $this->getModCon();
68
+
69
+ $oResponse = new \FernleafSystems\Utilities\Response();
70
+ if ( $this->loadDP()->post( 'DeleteFiles' ) === 'Y' ) {
71
+ // First get the current setting and if necessary, modify it and then reset it.
72
+ $sDesiredOption = 'enabled_delete_only';
73
+ $sCurrentOption = $oFO->getUnrecognisedFileScannerOption();
74
+ if ( $sCurrentOption != $sDesiredOption ) {
75
+ $oFO->setUfcOption( $sDesiredOption );
76
+ }
77
+
78
+ /** @var ICWP_WPSF_Processor_HackProtect $oProc */
79
+ $oProc = $oFO->getProcessor();
80
+ $oProc->getSubProcessorFileCleanerScan()
81
+ ->runScan();
82
+ $oFO->setUfcOption( $sCurrentOption )
83
+ ->savePluginOptions();
84
+
85
+ $oResponse->setSuccessful( true );
86
+ $sMessage = 'If your filesystem permissions allowed it, the scanner will have deleted these files.';
87
+ }
88
+ else {
89
+ $oResponse->setSuccessful( false );
90
+ $sMessage = 'No attempt was made to delete any files since the checkbox was not checked.';
91
+ }
92
+
93
+ return $oResponse->setMessageText( $sMessage );
94
+ }
95
+
96
+ /**
97
+ * @return \FernleafSystems\Utilities\Response
98
+ */
99
+ private function process_RestoreFiles() {
100
+ /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
101
+ $oFO = $this->getModCon();
102
+
103
+ if ( $this->loadDP()->post( 'RestoreFiles' ) === 'Y' ) {
104
+ /** @var ICWP_WPSF_Processor_HackProtect $oProc */
105
+ $oProc = $oFO->getProcessor();
106
+ $oProc->getSubProcessorChecksumScan()->doChecksumScan( true );
107
+
108
+ $sMessage = 'The scanner will have restore these files if your filesystem permissions allowed it.';
109
+ }
110
+ else {
111
+ $sMessage = 'No attempt was made to restore the files since the checkbox was not checked.';
112
+ }
113
+
114
+ $oResponse = new \FernleafSystems\Utilities\Response();
115
+ return $oResponse->setSuccessful( true )
116
+ ->setMessageText( $sMessage );
117
+ }
118
+
119
+ /**
120
+ * @return \FernleafSystems\Utilities\Response
121
+ */
122
+ private function process_UfcConfig() {
123
+ /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
124
+ $oFO = $this->getModCon();
125
+
126
+ $sSetting = $this->loadDP()->post( 'enable_scan' );
127
+ $oFO->setUfcOption( $sSetting )
128
+ ->savePluginOptions();
129
+
130
+ $bSuccess = ( $sSetting == $oFO->getUnrecognisedFileScannerOption() );
131
+
132
+ if ( $bSuccess ) {
133
+ if ( $oFO->isUfsEnabled() ) {
134
+ $sMessage = 'Scanner automation has been enabled.';
135
+ }
136
+ else {
137
+ $sMessage = 'Scanner automation has been disabled.';
138
+ }
139
+ }
140
+ else {
141
+ $sMessage = 'There was a problem with saving this option. You may need to reload.';
142
+ }
143
+
144
+ $oResponse = new \FernleafSystems\Utilities\Response();
145
+ return $oResponse->setSuccessful( $bSuccess )
146
+ ->setMessageText( $sMessage );
147
+ }
148
+
149
+ /**
150
+ * @return \FernleafSystems\Utilities\Response
151
+ */
152
+ private function process_WcfConfig() {
153
+ /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
154
+ $oFO = $this->getModCon();
155
+
156
+ $sSetting = $this->loadDP()->post( 'enable_scan' );
157
+
158
+ $bEnabled = true;
159
+ $bRestore = false;
160
+ $bProcess = true;
161
+ switch ( $sSetting ) {
162
+ case 'enabled_report_only':
163
+ break;
164
+ case 'enabled_restore_report':
165
+ $bRestore = true;
166
+ break;
167
+ default:
168
+ $bProcess = false;
169
+ break;
170
+ }
171
+
172
+ $bSuccess = false;
173
+ if ( $bProcess ) {
174
+
175
+ $oFO->setWcfScanEnabled( $bEnabled )
176
+ ->setWcfScanAutoRepair( $bRestore )
177
+ ->savePluginOptions();
178
+
179
+ $bSuccess = ( $bEnabled == $oFO->isWcfScanEnabled() ) && ( $bRestore === $oFO->isWcfScanAutoRepair() );
180
+
181
+ if ( $bSuccess ) {
182
+ if ( $bEnabled ) {
183
+ $sMessage = 'Scanner automation has been enabled.';
184
+ }
185
+ else {
186
+ $sMessage = 'Scanner automation has been disabled.';
187
+ }
188
+ }
189
+ else {
190
+ $sMessage = 'There was a problem with saving this option. You may need to reload.';
191
+ }
192
+ }
193
+ else {
194
+ $sMessage = 'Scanner automation is unchanged because of failed request.';
195
+ }
196
+
197
+ $oResponse = new \FernleafSystems\Utilities\Response();
198
+ return $oResponse->setSuccessful( $bSuccess )
199
+ ->setMessageText( $sMessage );
200
+ }
201
+
202
+ /**
203
+ * @return string[]
204
+ * @throws Exception
205
+ */
206
+ protected function determineWizardSteps() {
207
+
208
+ switch ( $this->getWizardSlug() ) {
209
+ case 'wcf':
210
+ $aSteps = $this->determineWizardSteps_Wcf();
211
+ break;
212
+ case 'ufc':
213
+ $aSteps = $this->determineWizardSteps_Ufc();
214
+ break;
215
+ default:
216
+ parent::determineWizardSteps();
217
+ break;
218
+ }
219
+ return array_values( array_intersect( array_keys( $this->getAllDefinedSteps() ), $aSteps ) );
220
+ }
221
+
222
+ /**
223
+ * @return string[]
224
+ */
225
+ private function determineWizardSteps_Wcf() {
226
+ /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
227
+ $oFO = $this->getModCon();
228
+
229
+ $aStepsSlugs = array(
230
+ 'start',
231
+ 'scanresult',
232
+ );
233
+ if ( !$oFO->isWcfScanEnabled() ) {
234
+ $aStepsSlugs[] = 'config';
235
+ }
236
+ $aStepsSlugs[] = 'finished';
237
+ return $aStepsSlugs;
238
+ }
239
+
240
+ /**
241
+ * @return string[]
242
+ */
243
+ private function determineWizardSteps_Ufc() {
244
+ /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
245
+ $oFO = $this->getModCon();
246
+
247
+ $aStepsSlugs = array(
248
+ 'start',
249
+ 'exclusions',
250
+ 'scanresult'
251
+ );
252
+ if ( !$oFO->isUfsEnabled() ) {
253
+ $aStepsSlugs[] = 'config';
254
+ }
255
+ $aStepsSlugs[] = 'finished';
256
+ return $aStepsSlugs;
257
+ }
258
+
259
+ /**
260
+ * @param string $sStep
261
+ * @return array
262
+ */
263
+ protected function getRenderData_SlideExtra( $sStep ) {
264
+ /** @var ICWP_WPSF_FeatureHandler_HackProtect $oFO */
265
+ $oFO = $this->getModCon();
266
+ /** @var ICWP_WPSF_Processor_HackProtect $oProc */
267
+ $oProc = $oFO->getProcessor();
268
+
269
+ $aAdditional = array();
270
+
271
+ $sCurrentWiz = $this->getWizardSlug();
272
+
273
+ if ( $sCurrentWiz == 'ufc' ) {
274
+ switch ( $sStep ) {
275
+
276
+ case 'exclusions':
277
+ $aFiles = $oFO->getUfcFileExclusions();
278
+ $aAdditional[ 'data' ] = array(
279
+ 'files' => array(
280
+ 'count' => count( $aFiles ),
281
+ 'has' => !empty( $aFiles ),
282
+ 'list' => implode( "\n", array_map( 'stripslashes', $aFiles ) ),
283
+ )
284
+ );
285
+ break;
286
+
287
+ case 'scanresult':
288
+ $aFiles = $this->cleanAbsPath( $oProc->getSubProcessorFileCleanerScan()->discoverFiles() );
289
+
290
+ $aAdditional[ 'data' ] = array(
291
+ 'files' => array(
292
+ 'count' => count( $aFiles ),
293
+ 'has' => !empty( $aFiles ),
294
+ 'list' => $aFiles,
295
+ )
296
+ );
297
+ break;
298
+ }
299
+ }
300
+ else if ( $sCurrentWiz == 'wcf' ) {
301
+
302
+ switch ( $sStep ) {
303
+ case 'scanresult':
304
+ $aFiles = $oProc->getSubProcessorChecksumScan()->doChecksumScan( false );
305
+ $aChecksum = $this->cleanAbsPath( $aFiles[ 'checksum_mismatch' ] );
306
+ $aMissing = $this->cleanAbsPath( $aFiles[ 'missing' ] );
307
+
308
+ $aAdditional[ 'data' ] = array(
309
+ 'files' => array(
310
+ 'count' => count( $aChecksum ) + count( $aMissing ),
311
+ 'has' => !empty( $aChecksum ) || !empty( $aMissing ),
312
+ 'checksum' => array(
313
+ 'count' => count( $aChecksum ),
314
+ 'has' => !empty( $aChecksum ),
315
+ 'list' => $aChecksum,
316
+ ),
317
+ 'missing' => array(
318
+ 'count' => count( $aMissing ),
319
+ 'has' => !empty( $aMissing ),
320
+ 'list' => $aMissing,
321
+ )
322
+ )
323
+ );
324
+ break;
325
+ }
326
+ }
327
+
328
+ if ( empty( $aAdditional ) ) {
329
+ $aAdditional = parent::getRenderData_SlideExtra( $sStep );
330
+ }
331
+ return $aAdditional;
332
+ }
333
+
334
+ /**
335
+ * @param string[] $aFilePaths
336
+ * @return string[]
337
+ */
338
+ private function cleanAbsPath( $aFilePaths ) {
339
+ return array_map(
340
+ function ( $sFile ) {
341
+ return str_replace( ABSPATH, '', $sFile );
342
+ },
343
+ $aFilePaths
344
+ );
345
+ }
346
+ }
src/wizards/login_protect.php ADDED
@@ -0,0 +1,267 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( class_exists( 'ICWP_WPSF_Wizard_LoginProtect', false ) ) {
4
+ return;
5
+ }
6
+
7
+ require_once( dirname( __FILE__ ).'/base_wpsf.php' );
8
+
9
+ /**
10
+ * Class ICWP_WPSF_Processor_LoginProtect_Wizard
11
+ */
12
+ class ICWP_WPSF_Wizard_LoginProtect extends ICWP_WPSF_Wizard_BaseWpsf {
13
+
14
+ /**
15
+ * @return string
16
+ */
17
+ protected function getPageTitle() {
18
+ return sprintf( _wpsf__( '%s Multi-Factor Authentication Wizard' ), $this->getPluginCon()->getHumanName() );
19
+ }
20
+
21
+ /**
22
+ * @param string $sStep
23
+ * @return \FernleafSystems\Utilities\Response|null
24
+ */
25
+ protected function processWizardStep( $sStep ) {
26
+ switch ( $sStep ) {
27
+ case 'authemail':
28
+ $oResponse = $this->processAuthEmail();
29
+ break;
30
+
31
+ case 'authga':
32
+ $oResponse = $this->processAuthGa();
33
+ break;
34
+
35
+ case 'multiselect':
36
+ $oResponse = $this->processMultiSelect();
37
+ break;
38
+
39
+ default:
40
+ $oResponse = parent::processWizardStep( $sStep );
41
+ break;
42
+ }
43
+ return $oResponse;
44
+ }
45
+
46
+ /**
47
+ * @return \FernleafSystems\Utilities\Response
48
+ */
49
+ private function processAuthEmail() {
50
+ /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
51
+ $oFO = $this->getModCon();
52
+ $oDP = $this->loadDP();
53
+
54
+ $oResponse = new \FernleafSystems\Utilities\Response();
55
+ $oResponse->setSuccessful( false );
56
+
57
+ $sEmail = $oDP->post( 'email' );
58
+ $sCode = $oDP->post( 'code' );
59
+ $bFa = $oDP->post( 'Email2FAOption' ) === 'Y';
60
+
61
+ if ( !$oDP->validEmail( $sEmail ) ) {
62
+ $sMessage = _wpsf__( 'Invalid email address' );
63
+ }
64
+ else {
65
+ if ( empty( $sCode ) ) {
66
+ if ( $oFO->sendEmailVerifyCanSend( $sEmail, false ) ) {
67
+ $oResponse->setSuccessful( true );
68
+ $sMessage = 'Verification email sent - please check your email (including your SPAM)';
69
+ }
70
+ else {
71
+ $sMessage = 'Failed to send verification email';
72
+ }
73
+ }
74
+ else {
75
+ if ( $sCode == $oFO->getCanEmailVerifyCode() ) {
76
+ $oResponse->setSuccessful( true );
77
+ $sMessage = 'Email sending has been verified successfully.';
78
+
79
+ $oFO->setIfCanSendEmail( true );
80
+
81
+ if ( $bFa ) {
82
+ $oFO->setEnabled2FaEmail( true );
83
+ $sMessage .= ' '.'Email-based two factor authentication is now enabled.';
84
+ }
85
+ else {
86
+ $sMessage .= ' '.'Email-based two factor authentication is NOT enabled.';
87
+ }
88
+ }
89
+ else {
90
+ $sMessage = 'This does not appear to be the correct 6-digit code that was sent to you.'
91
+ .'Email-based two factor authentication option has not been updated.';
92
+ }
93
+ }
94
+ }
95
+
96
+ return $oResponse->setMessageText( $sMessage );
97
+ }
98
+
99
+ /**
100
+ * @return \FernleafSystems\Utilities\Response
101
+ */
102
+ private function processAuthGa() {
103
+ /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
104
+ $oFO = $this->getModCon();
105
+ $oDP = $this->loadDP();
106
+
107
+ $oResponse = new \FernleafSystems\Utilities\Response();
108
+ $oResponse->setSuccessful( false );
109
+
110
+ $sCode = $oDP->post( 'code' );
111
+ $bEnableGa = $oDP->post( 'enablega' ) === 'Y';
112
+
113
+ $sMessage = '';
114
+ if ( $sCode != 'ignore' ) {
115
+
116
+ if ( empty( $sCode ) ) {
117
+ $sMessage = _wpsf__( 'Code was empty.' );
118
+ }
119
+ else {
120
+ $oUser = $this->loadWpUsers()->getCurrentWpUser();
121
+ /** @var ICWP_WPSF_Processor_LoginProtect $oProc */
122
+ $oProc = $oFO->getProcessor();
123
+ $oProcGa = $oProc->getProcessorLoginIntent()
124
+ ->getProcessorGoogleAuthenticator();
125
+ $bValidated = $oProcGa->validateGaCode( $oUser, $sCode );
126
+
127
+ if ( $bValidated ) {
128
+ $oProcGa->setProfileValidated( $oUser, true );
129
+ $sMessage = 'Google Authenticator was validated.';
130
+ $oResponse->setSuccessful( true );
131
+ }
132
+ else {
133
+ $sMessage = 'Could not validate - this does not appear to be the correct 6-digit code.';
134
+ $bEnableGa = false; // we don't enable GA on the site if the code was bad.
135
+ }
136
+ }
137
+ }
138
+ else {
139
+ $oResponse->setSuccessful( true );
140
+ }
141
+
142
+ if ( $bEnableGa ) {
143
+ $oFO->setEnabled2FaGoogleAuthenticator( true );
144
+ $sMessage .= ' '._wpsf__( 'Google Authenticator was enabled for the site.' );
145
+ }
146
+
147
+ return $oResponse->setMessageText( $sMessage );
148
+ }
149
+
150
+ /**
151
+ * @return \FernleafSystems\Utilities\Response
152
+ */
153
+ private function processMultiSelect() {
154
+ /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
155
+ $oFO = $this->getModCon();
156
+
157
+ $bEnabledMulti = $this->loadDP()->post( 'multiselect' ) === 'Y';
158
+ $oFO->setIsChainedAuth( $bEnabledMulti );
159
+ $sMessage = sprintf( _wpsf__( 'Multi-Factor Authentication was %s for the site.' ),
160
+ $bEnabledMulti ? _wpsf__( 'enabled' ) : _wpsf__( 'disabled' )
161
+ );
162
+
163
+ $oResponse = new \FernleafSystems\Utilities\Response();
164
+ return $oResponse->setSuccessful( true )
165
+ ->setMessageText( $sMessage );
166
+ }
167
+
168
+ /**
169
+ * @return string[]
170
+ * @throws Exception
171
+ */
172
+ protected function determineWizardSteps() {
173
+
174
+ switch ( $this->getWizardSlug() ) {
175
+ case 'mfa':
176
+ $aSteps = $this->determineWizardSteps_Mfa();
177
+ break;
178
+ default:
179
+ parent::determineWizardSteps();
180
+ break;
181
+ }
182
+ return array_values( array_intersect( array_keys( $this->getAllDefinedSteps() ), $aSteps ) );
183
+ }
184
+
185
+ /**
186
+ * @return string[]
187
+ */
188
+ private function determineWizardSteps_Mfa() {
189
+ /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
190
+ $oFO = $this->getModCon();
191
+
192
+ $aStepsSlugs = array( 'start' );
193
+
194
+ if ( !$oFO->getIfCanSendEmailVerified() || !$oFO->getIsEmailAuthenticationEnabled() ) {
195
+ $aStepsSlugs[] = 'authemail';
196
+ }
197
+
198
+ if ( !$oFO->getIsEnabledGoogleAuthenticator() ) {
199
+ $aStepsSlugs[] = 'authga';
200
+ }
201
+
202
+ $aStepsSlugs[] = 'multiselect';
203
+ $aStepsSlugs[] = 'finished';
204
+ return $aStepsSlugs;
205
+ }
206
+
207
+ /**
208
+ * @param string $sStep
209
+ * @return array
210
+ */
211
+ protected function getRenderData_SlideExtra( $sStep ) {
212
+ /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oFO */
213
+ $oFO = $this->getModCon();
214
+
215
+ $aAdditional = array();
216
+
217
+ switch ( $sStep ) {
218
+
219
+ case 'authemail':
220
+ $oUser = $this->loadWpUsers()->getCurrentWpUser();
221
+ $aAdditional = array(
222
+ 'data' => array(
223
+ 'name' => $oUser->first_name,
224
+ 'user_email' => $oUser->user_email
225
+ )
226
+ );
227
+ break;
228
+
229
+ case 'authga':
230
+ $oUser = $this->loadWpUsers()->getCurrentWpUser();
231
+ /** @var ICWP_WPSF_Processor_LoginProtect $oProc */
232
+ $oProc = $oFO->getProcessor();
233
+ $oProcGa = $oProc->getProcessorLoginIntent()
234
+ ->getProcessorGoogleAuthenticator();
235
+ $sGaUrl = $oProcGa->getGaRegisterChartUrl( $oUser );
236
+ $aAdditional = array(
237
+ 'data' => array(
238
+ 'name' => $oUser->first_name,
239
+ 'user_email' => $oUser->user_email
240
+ ),
241
+ 'hrefs' => array(
242
+ 'ga_chart' => $sGaUrl,
243
+ ),
244
+ 'flags' => array(
245
+ 'has_ga' => $oProcGa->getCurrentUserHasValidatedProfile(),
246
+ )
247
+ );
248
+ break;
249
+
250
+ case 'multiselect':
251
+ $aAdditional = array(
252
+ 'flags' => array(
253
+ 'has_multiselect' => $oFO->isChainedAuth(),
254
+ )
255
+ );
256
+ break;
257
+
258
+ default:
259
+ break;
260
+ }
261
+
262
+ if ( empty( $aAdditional ) ) {
263
+ $aAdditional = parent::getRenderData_SlideExtra( $sStep );
264
+ }
265
+ return $aAdditional;
266
+ }
267
+ }
src/wizards/plugin.php ADDED
@@ -0,0 +1,548 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( class_exists( 'ICWP_WPSF_Wizard_Plugin', false ) ) {
4
+ return;
5
+ }
6
+
7
+ require_once( dirname( __FILE__ ).'/base_wpsf.php' );
8
+
9
+ /**
10
+ * Class ICWP_WPSF_Processor_LoginProtect_Wizard
11
+ */
12
+ class ICWP_WPSF_Wizard_Plugin extends ICWP_WPSF_Wizard_BaseWpsf {
13
+
14
+ /**
15
+ * @return string[]
16
+ */
17
+ protected function getSupportedWizards() {
18
+ return array( 'welcome', 'importexport' );
19
+ }
20
+
21
+ /**
22
+ * @return string
23
+ */
24
+ protected function getPageTitle() {
25
+ return sprintf( _wpsf__( '%s Welcome Wizard' ), $this->getPluginCon()->getHumanName() );
26
+ }
27
+
28
+ /**
29
+ * @param string $sStep
30
+ * @return \FernleafSystems\Utilities\Response|null
31
+ */
32
+ protected function processWizardStep( $sStep ) {
33
+ switch ( $sStep ) {
34
+
35
+ case 'ip_detect':
36
+ $oResponse = $this->wizardIpDetect();
37
+ break;
38
+
39
+ case 'license':
40
+ $oResponse = $this->wizardLicense();
41
+ break;
42
+
43
+ case 'import':
44
+ $oResponse = $this->wizardImportOptions();
45
+ break;
46
+
47
+ case 'admin_access_restriction':
48
+ $oResponse = $this->wizardSecurityAdmin();
49
+ break;
50
+
51
+ case 'audit_trail':
52
+ $oResponse = $this->wizardAuditTrail();
53
+ break;
54
+
55
+ case 'ips':
56
+ $oResponse = $this->wizardIps();
57
+ break;
58
+
59
+ case 'comments_filter':
60
+ $oResponse = $this->wizardCommentsFilter();
61
+ break;
62
+
63
+ case 'login_protect':
64
+ $oResponse = $this->wizardLoginProtect();
65
+ break;
66
+
67
+ case 'optin':
68
+ $oResponse = $this->wizardOptin();
69
+ break;
70
+
71
+ default:
72
+ $oResponse = parent::processWizardStep( $sStep );
73
+ break;
74
+ }
75
+ return $oResponse;
76
+ }
77
+
78
+ /**
79
+ * @return string[]
80
+ * @throws Exception
81
+ */
82
+ protected function determineWizardSteps() {
83
+
84
+ switch ( $this->getWizardSlug() ) {
85
+ case 'welcome':
86
+ $aSteps = $this->determineWizardSteps_Welcome();
87
+ break;
88
+ case 'importexport':
89
+ $aSteps = $this->determineWizardSteps_Import();
90
+ break;
91
+ default:
92
+ parent::determineWizardSteps();
93
+ break;
94
+ }
95
+ return array_values( array_intersect( array_keys( $this->getAllDefinedSteps() ), $aSteps ) );
96
+ }
97
+
98
+ /**
99
+ * @return string[]
100
+ */
101
+ private function determineWizardSteps_Import() {
102
+ return array(
103
+ 'start',
104
+ 'import',
105
+ 'finished',
106
+ );
107
+ }
108
+
109
+ /**
110
+ * @return string[]
111
+ */
112
+ private function determineWizardSteps_Welcome() {
113
+ /** @var ICWP_WPSF_FeatureHandler_Plugin $oFO */
114
+ $oFO = $this->getModCon();
115
+ $oConn = $this->getPluginCon();
116
+
117
+ $aStepsSlugs = array(
118
+ 'welcome',
119
+ 'ip_detect'
120
+ );
121
+ // if ( !$oFO->isPremium() ) {
122
+ // $aStepsSlugs[] = 'license'; not showing it for now
123
+ // }
124
+
125
+ if ( $oFO->isPremium() ) {
126
+ $aStepsSlugs[] = 'import';
127
+ }
128
+
129
+ if ( !$oConn->getModule( 'admin_access_restriction' )->getIsMainFeatureEnabled() ) {
130
+ $aStepsSlugs[] = 'admin_access_restriction';
131
+ }
132
+
133
+ /** @var ICWP_WPSF_FeatureHandler_AuditTrail $oModule */
134
+ $oModule = $oConn->getModule( 'audit_trail' );
135
+ if ( !$oModule->getIsMainFeatureEnabled() ) {
136
+ $aStepsSlugs[] = 'audit_trail';
137
+ }
138
+
139
+ if ( !$oConn->getModule( 'ips' )->getIsMainFeatureEnabled() ) {
140
+ $aStepsSlugs[] = 'ips';
141
+ }
142
+
143
+ /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oModule */
144
+ $oModule = $oConn->getModule( 'login_protect' );
145
+ if ( !( $oModule->getIsMainFeatureEnabled() && $oModule->isEnabledGaspCheck() ) ) {
146
+ $aStepsSlugs[] = 'login_protect';
147
+ }
148
+
149
+ /** @var ICWP_WPSF_FeatureHandler_CommentsFilter $oModule */
150
+ $oModule = $oConn->getModule( 'comments_filter' );
151
+ if ( !( $oModule->getIsMainFeatureEnabled() && $oModule->isEnabledGaspCheck() ) ) {
152
+ $aStepsSlugs[] = 'comments_filter';
153
+ }
154
+
155
+ $aStepsSlugs[] = 'how_shield_works';
156
+ $aStepsSlugs[] = 'optin';
157
+
158
+ if ( !$oFO->isPremium() ) {
159
+ $aStepsSlugs[] = 'import';
160
+ }
161
+
162
+ $aStepsSlugs[] = 'thankyou';
163
+ return $aStepsSlugs;
164
+ }
165
+
166
+ /**
167
+ * @param string $sStep
168
+ * @return array
169
+ */
170
+ protected function getRenderData_SlideExtra( $sStep ) {
171
+ $oConn = $this->getPluginCon();
172
+
173
+ $aAdditional = array();
174
+
175
+ $sCurrentWiz = $this->getWizardSlug();
176
+
177
+ if ( $sCurrentWiz == 'welcome' ) {
178
+
179
+ switch ( $sStep ) {
180
+ case 'ip_detect':
181
+ $aAdditional = array(
182
+ 'hrefs' => array(
183
+ 'visitor_ip' => 'http://icwp.io/visitorip',
184
+ )
185
+ );
186
+ break;
187
+ case 'license':
188
+ break;
189
+ case 'import':
190
+ $aAdditional = array(
191
+ 'hrefs' => array(
192
+ 'blog_importexport' => 'http://icwp.io/av'
193
+ ),
194
+ 'imgs' => array(
195
+ 'shieldnetworkmini' => $oConn->getPluginUrl_Image( 'shield/shieldnetworkmini.png' ),
196
+ )
197
+ );
198
+ break;
199
+
200
+ case 'optin':
201
+ $oUser = $this->loadWpUsers()->getCurrentWpUser();
202
+ $aAdditional = array(
203
+ 'data' => array(
204
+ 'name' => $oUser->first_name,
205
+ 'user_email' => $oUser->user_email
206
+ )
207
+ );
208
+ break;
209
+
210
+ case 'thankyou':
211
+ break;
212
+
213
+ case 'how_shield_works':
214
+ $aAdditional = array(
215
+ 'imgs' => array(
216
+ 'how_shield_works' => $oConn->getPluginUrl_Image( 'wizard/general-shield_where.png' ),
217
+ 'modules' => $oConn->getPluginUrl_Image( 'wizard/general-shield_modules.png' ),
218
+ 'options' => $oConn->getPluginUrl_Image( 'wizard/general-shield_options.png' ),
219
+ 'help' => $oConn->getPluginUrl_Image( 'wizard/general-shield_help.png' ),
220
+ 'actions' => $oConn->getPluginUrl_Image( 'wizard/general-shield_actions.png' ),
221
+ 'module_onoff' => $oConn->getPluginUrl_Image( 'wizard/general-module_onoff.png' ),
222
+ 'option_help' => $oConn->getPluginUrl_Image( 'wizard/general-option_help.png' ),
223
+ ),
224
+ 'headings' => array(
225
+ 'how_shield_works' => _wpsf__( 'Where to find Shield' ),
226
+ 'modules' => _wpsf__( 'Accessing Each Module' ),
227
+ 'options' => _wpsf__( 'Accessing Options' ),
228
+ 'help' => _wpsf__( 'Finding Help' ),
229
+ 'actions' => _wpsf__( 'Actions (not Options)' ),
230
+ 'module_onoff' => _wpsf__( 'Module On/Off Switch' ),
231
+ 'option_help' => _wpsf__( 'Help For Each Option' ),
232
+ ),
233
+ 'captions' => array(
234
+ 'how_shield_works' => _wpsf__( "You'll find the main Shield Security setting in the left-hand WordPress menu." ),
235
+ 'modules' => _wpsf__( 'Shield is split up into independent modules for accessing the options of each feature.' ),
236
+ 'options' => _wpsf__( 'When you load a module, you can access the options by clicking on the Options Panel link.' ),
237
+ 'help' => _wpsf__( 'Each module also has a brief overview help section - there is more in-depth help available.' ),
238
+ 'actions' => _wpsf__( 'Certain modules have extra actions and features, e.g. Audit Trail Viewer.' )
239
+ .' '._wpsf__( 'Note: Not all modules have the actions section' ),
240
+ 'module_onoff' => _wpsf__( 'Each module has an Enable/Disable checkbox to turn on/off all processing for that module' ),
241
+ 'option_help' => _wpsf__( 'To help you understand each option, most of them have a more info link, and/or a blog link, to read more' ),
242
+ ),
243
+ );
244
+ break;
245
+ default:
246
+ break;
247
+ }
248
+ }
249
+ else if ( $sCurrentWiz == 'importexport' ) {
250
+ switch ( $sStep ) {
251
+ case 'import':
252
+ $aAdditional = array(
253
+ 'hrefs' => array(
254
+ 'blog_importexport' => 'http://icwp.io/av'
255
+ ),
256
+ 'imgs' => array(
257
+ 'shieldnetworkmini' => $oConn->getPluginUrl_Image( 'shield/shieldnetworkmini.png' ),
258
+ )
259
+ );
260
+ break;
261
+
262
+ default:
263
+ break;
264
+ }
265
+ }
266
+
267
+ if ( empty( $aAdditional ) ) {
268
+ $aAdditional = parent::getRenderData_SlideExtra( $sStep );
269
+ }
270
+ return $aAdditional;
271
+ }
272
+
273
+ /**
274
+ * @return \FernleafSystems\Utilities\Response
275
+ */
276
+ private function wizardIpDetect() {
277
+ $oIps = $this->loadIpService();
278
+ $sIp = $this->loadDP()->post( 'ip' );
279
+
280
+ $oResponse = new \FernleafSystems\Utilities\Response();
281
+ $oResponse->setSuccessful( false );
282
+ if ( empty( $sIp ) ) {
283
+ $sMessage = 'IP address was empty.';
284
+ }
285
+ else if ( !$oIps->isValidIp_PublicRemote( $sIp ) ) {
286
+ $sMessage = 'The IP address supplied was not a valid public IP address.';
287
+ }
288
+ // else if ( $oIps->getIpVersion( $sIp ) != 4 ) {
289
+ // $sMessage = 'The IP address supplied was not a valid IP address.';
290
+ // }
291
+ else {
292
+ $sSource = $oIps->determineSourceFromIp( $sIp );
293
+ if ( empty( $sSource ) ) {
294
+ $sMessage = 'Strange, the address source could not be found from this IP.';
295
+ }
296
+ else {
297
+ /** @var ICWP_WPSF_FeatureHandler_Plugin $oModule */
298
+ $oModule = $this->getPluginCon()->getModule( 'plugin' );
299
+ $oModule->setVisitorAddressSource( $sSource )
300
+ ->savePluginOptions();
301
+ $oResponse->setSuccessful( true );
302
+ $sMessage = _wpsf__( 'Success!' ).' '
303
+ .sprintf( '"%s" was found to be the best source of visitor IP addresses for your site.', $sSource );
304
+ }
305
+ }
306
+
307
+ return $oResponse->setMessageText( $sMessage );
308
+ }
309
+
310
+ /**
311
+ * @return \FernleafSystems\Utilities\Response
312
+ */
313
+ private function wizardLicense() {
314
+ $sKey = $this->loadDP()->post( 'LicenseKey' );
315
+
316
+ $bSuccess = false;
317
+ if ( empty( $sKey ) ) {
318
+ $sMessage = 'License key was empty.';
319
+ }
320
+ else {
321
+ /** @var ICWP_WPSF_FeatureHandler_License $oModule */
322
+ $oModule = $this->getPluginCon()->getModule( 'license' );
323
+ try {
324
+ $oModule->activateOfficialLicense( $sKey, true );
325
+ if ( $oModule->hasValidWorkingLicense() ) {
326
+ $bSuccess = true;
327
+ $sMessage = _wpsf__( 'License key was accepted and installed successfully.' );
328
+ }
329
+ else {
330
+ $sMessage = _wpsf__( 'License key was not accepted.' );
331
+ }
332
+ }
333
+ catch ( Exception $oE ) {
334
+ $sMessage = _wpsf__( $oE->getMessage() );
335
+ }
336
+ }
337
+
338
+ $oResponse = new \FernleafSystems\Utilities\Response();
339
+ return $oResponse->setSuccessful( $bSuccess )
340
+ ->setMessageText( $sMessage );
341
+ }
342
+
343
+ /**
344
+ * @return \FernleafSystems\Utilities\Response
345
+ */
346
+ private function wizardImportOptions() {
347
+ /** @var ICWP_WPSF_FeatureHandler_Plugin $oFO */
348
+ $oFO = $this->getModCon();
349
+ $oDP = $this->loadDP();
350
+
351
+ $sMasterSiteUrl = $oDP->post( 'MasterSiteUrl' );
352
+ $sSecretKey = $oDP->post( 'MasterSiteSecretKey' );
353
+ $bEnabledNetwork = $oDP->post( 'ShieldNetworkCheck' ) === 'Y';
354
+
355
+ /** @var ICWP_WPSF_Processor_Plugin $oProc */
356
+ $oProc = $oFO->getProcessor();
357
+ $nCode = $oProc->getSubProcessorImportExport()
358
+ ->runImport( $sMasterSiteUrl, $sSecretKey, $bEnabledNetwork, $sSiteResponse );
359
+
360
+ $aErrors = array(
361
+ _wpsf__( 'Options imported successfully to your site.' ), // success
362
+ _wpsf__( 'Secret key was empty.' ),
363
+ _wpsf__( 'Secret key was not 40 characters long.' ),
364
+ _wpsf__( 'Secret key contains invalid characters - it should be letters and numbers only.' ),
365
+ _wpsf__( 'Source site URL could not be parsed correctly.' ),
366
+ _wpsf__( 'Could not parse the response from the site.' )
367
+ .' '._wpsf__( 'Check the secret key is correct for the remote site.' ),
368
+ _wpsf__( 'Failure response returned from the site.' ),
369
+ sprintf( _wpsf__( 'Remote site responded with - %s' ), $sSiteResponse ),
370
+ _wpsf__( 'Data returned from the site was empty.' )
371
+ );
372
+
373
+ $sMessage = isset( $aErrors[ $nCode ] ) ? $aErrors[ $nCode ] : 'Unknown Error';
374
+
375
+ $oResponse = new \FernleafSystems\Utilities\Response();
376
+ return $oResponse->setSuccessful( $nCode === 0 )
377
+ ->setMessageText( $sMessage );
378
+ }
379
+
380
+ /**
381
+ * @return \FernleafSystems\Utilities\Response
382
+ */
383
+ private function wizardSecurityAdmin() {
384
+ $oDP = $this->loadDP();
385
+ $sKey = $oDP->post( 'AccessKey' );
386
+ $sConfirm = $oDP->post( 'AccessKeyConfirm' );
387
+
388
+ $oResponse = new \FernleafSystems\Utilities\Response();
389
+
390
+ $bSuccess = false;
391
+ if ( empty( $sKey ) ) {
392
+ $sMessage = 'Security access key was empty.';
393
+ }
394
+ else if ( $sKey != $sConfirm ) {
395
+ $sMessage = 'Keys do not match.';
396
+ }
397
+ else {
398
+ /** @var ICWP_WPSF_FeatureHandler_AdminAccessRestriction $oModule */
399
+ $oModule = $this->getPluginCon()->getModule( 'admin_access_restriction' );
400
+ try {
401
+ $oModule->setNewAccessKeyManually( $sKey )
402
+ ->setPermissionToSubmit( true );
403
+ $bSuccess = true;
404
+ $sMessage = _wpsf__( 'Security Admin setup was successful.' );
405
+ }
406
+ catch ( Exception $oE ) {
407
+ $sMessage = _wpsf__( $oE->getMessage() );
408
+ }
409
+ }
410
+
411
+ return $oResponse->setSuccessful( $bSuccess )
412
+ ->setMessageText( $sMessage );
413
+ }
414
+
415
+ /**
416
+ * @return \FernleafSystems\Utilities\Response
417
+ */
418
+ private function wizardAuditTrail() {
419
+ $bEnabled = $this->loadDP()->post( 'AuditTrailOption' ) === 'Y';
420
+
421
+ /** @var ICWP_WPSF_FeatureHandler_AdminAccessRestriction $oModule */
422
+ $oModule = $this->getPluginCon()->getModule( 'audit_trail' );
423
+ $oModule->setIsMainFeatureEnabled( $bEnabled )
424
+ ->savePluginOptions();
425
+
426
+ $bSuccess = $oModule->getIsMainFeatureEnabled() === $bEnabled;
427
+ if ( $bSuccess ) {
428
+ $sMessage = sprintf( '%s has been %s.', _wpsf__( 'Audit Trail' ),
429
+ $oModule->getIsMainFeatureEnabled() ? _wpsf__( 'Enabled' ) : _wpsf__( 'Disabled' )
430
+ );
431
+ }
432
+ else {
433
+ $sMessage = sprintf( _wpsf__( '%s setting could not be changed at this time.' ), _wpsf__( 'Audit Trail' ) );
434
+ }
435
+
436
+ $oResponse = new \FernleafSystems\Utilities\Response();
437
+ return $oResponse->setSuccessful( $bSuccess )
438
+ ->setMessageText( $sMessage );
439
+ }
440
+
441
+ /**
442
+ * @return \FernleafSystems\Utilities\Response
443
+ */
444
+ private function wizardIps() {
445
+
446
+ $bEnabled = $this->loadDP()->post( 'IpManagerOption' ) === 'Y';
447
+
448
+ /** @var ICWP_WPSF_FeatureHandler_Ips $oModule */
449
+ $oModule = $this->getPluginCon()->getModule( 'ips' );
450
+ $oModule->setIsMainFeatureEnabled( $bEnabled )
451
+ ->savePluginOptions();
452
+
453
+ $bSuccess = $oModule->getIsMainFeatureEnabled() === $bEnabled;
454
+ if ( $bSuccess ) {
455
+ $sMessage = sprintf( '%s has been %s.', _wpsf__( 'IP Manager' ),
456
+ $oModule->getIsMainFeatureEnabled() ? _wpsf__( 'Enabled' ) : _wpsf__( 'Disabled' )
457
+ );
458
+ }
459
+ else {
460
+ $sMessage = sprintf( _wpsf__( '%s setting could not be changed at this time.' ), _wpsf__( 'IP Manager' ) );
461
+ }
462
+
463
+ $oResponse = new \FernleafSystems\Utilities\Response();
464
+ return $oResponse->setSuccessful( $bSuccess )
465
+ ->setMessageText( $sMessage );
466
+ }
467
+
468
+ /**
469
+ * @return \FernleafSystems\Utilities\Response
470
+ */
471
+ private function wizardLoginProtect() {
472
+
473
+ $bEnabled = $this->loadDP()->post( 'LoginProtectOption' ) === 'Y';
474
+
475
+ /** @var ICWP_WPSF_FeatureHandler_LoginProtect $oModule */
476
+ $oModule = $this->getPluginCon()->getModule( 'login_protect' );
477
+ if ( $bEnabled ) { // we don't disable the whole module
478
+ $oModule->setIsMainFeatureEnabled( true );
479
+ }
480
+ $oModule->setEnabledGaspCheck( $bEnabled )
481
+ ->savePluginOptions();
482
+
483
+ $bSuccess = $oModule->getIsMainFeatureEnabled() === $bEnabled;
484
+ if ( $bSuccess ) {
485
+ $sMessage = sprintf( '%s has been %s.', _wpsf__( 'Login Protection' ),
486
+ $oModule->getIsMainFeatureEnabled() ? _wpsf__( 'Enabled' ) : _wpsf__( 'Disabled' )
487
+ );
488
+ }
489
+ else {
490
+ $sMessage = sprintf( _wpsf__( '%s setting could not be changed at this time.' ), _wpsf__( 'Login Protection' ) );
491
+ }
492
+
493
+ $oResponse = new \FernleafSystems\Utilities\Response();
494
+ return $oResponse->setSuccessful( $bSuccess )
495
+ ->setMessageText( $sMessage );
496
+ }
497
+
498
+ /**
499
+ * @return \FernleafSystems\Utilities\Response
500
+ */
501
+ private function wizardOptin() {
502
+ $oDP = $this->loadDP();
503
+
504
+ $bEnabledTracking = $oDP->post( 'AnonymousOption', 'N', true ) === 'Y';
505
+ $bEnabledBadge = $oDP->post( 'BadgeOption', 'N', true ) === 'Y';
506
+
507
+ /** @var ICWP_WPSF_FeatureHandler_Plugin $oModule */
508
+ $oModule = $this->getPluginCon()->getModule( 'plugin' );
509
+ $oModule->setIsDisplayPluginBadge( $bEnabledBadge )
510
+ ->setPluginTrackingPermission( $bEnabledTracking );
511
+
512
+ $sMessage = _wpsf__( 'Preferences have been saved.' );
513
+
514
+ $oResponse = new \FernleafSystems\Utilities\Response();
515
+ return $oResponse->setSuccessful( true )
516
+ ->setMessageText( $sMessage );
517
+ }
518
+
519
+ /**
520
+ * @return \FernleafSystems\Utilities\Response
521
+ */
522
+ private function wizardCommentsFilter() {
523
+
524
+ $bEnabled = $this->loadDP()->post( 'CommentsFilterOption' ) === 'Y';
525
+
526
+ /** @var ICWP_WPSF_FeatureHandler_CommentsFilter $oModule */
527
+ $oModule = $this->getPluginCon()->getModule( 'comments_filter' );
528
+ if ( $bEnabled ) { // we don't disable the whole module
529
+ $oModule->setIsMainFeatureEnabled( true );
530
+ }
531
+ $oModule->setEnabledGasp( $bEnabled )
532
+ ->savePluginOptions();
533
+
534
+ $bSuccess = $oModule->getIsMainFeatureEnabled() === $bEnabled;
535
+ if ( $bSuccess ) {
536
+ $sMessage = sprintf( '%s has been %s.', _wpsf__( 'Comment SPAM Protection' ),
537
+ $oModule->getIsMainFeatureEnabled() ? _wpsf__( 'Enabled' ) : _wpsf__( 'Disabled' )
538
+ );
539
+ }
540
+ else {
541
+ $sMessage = sprintf( _wpsf__( '%s setting could not be changed at this time.' ), _wpsf__( 'Comment SPAM Protection' ) );
542
+ }
543
+
544
+ $oResponse = new \FernleafSystems\Utilities\Response();
545
+ return $oResponse->setSuccessful( $bSuccess )
546
+ ->setMessageText( $sMessage );
547
+ }
548
+ }
templates/html/plugin_badge.html CHANGED
@@ -37,7 +37,7 @@
37
  font-size: 12px;
38
  line-height: 17px;
39
  padding-left: 43px;
40
-
41
  -webkit-transition: opacity 1s; /* Safari */
42
  transition: opacity 1s;
43
  }
37
  font-size: 12px;
38
  line-height: 17px;
39
  padding-left: 43px;
40
+ letter-spacing: 0;
41
  -webkit-transition: opacity 1s; /* Safari */
42
  transition: opacity 1s;
43
  }
templates/php/feature-default.php CHANGED
@@ -1,8 +1,13 @@
 
 
 
 
 
1
  <div class="row icwpTopLevelRow">
2
  <div class="icwpTopLevelSpan <?php echo $flags[ 'show_ads' ] ? 'span11' : 'span11'; ?>" id="icwpOptionsTopPill">
3
 
4
  <ul class="nav nav-pills">
5
- <li>
6
  <a href="#icwpPillOptions" data-toggle="pill">
7
  <span class="dashicons dashicons-admin-settings">&nbsp;</span>
8
  <div class="title"><?php echo $strings[ 'options_title' ]; ?></div>
@@ -27,10 +32,21 @@
27
  </a>
28
  </li>
29
  <?php endif; ?>
 
 
 
 
 
 
 
 
 
 
 
 
30
  </ul>
31
  <div class="tab-content">
32
- <div class="tab-pane"
33
- id="icwpPillOptions">
34
  <?php echo $flags[ 'show_standard_options' ] ? $options_form : ''; ?>
35
  <?php echo $flags[ 'show_alt_content' ] ? $content[ 'alt' ] : ''; ?>
36
  </div>
@@ -44,7 +60,7 @@
44
  <div class="content-help"><?php echo $content[ 'help' ]; ?></div>
45
  </div>
46
  <?php endif; ?>
47
- <div class="tab-pane active" id="icwpPillSelect">
48
  <h3 style="text-align: center">&uarr; <?php echo 'Select Desired Section Above'; ?> &uarr;</h3>
49
  </div>
50
  </div>
1
+ <style>
2
+ #icwpOptionsTopPill > .nav-pills li#icwpWizardPill a {
3
+ background-image: url("<?php echo $hrefs['img_wizard_wand'];?>");
4
+ }
5
+ </style>
6
  <div class="row icwpTopLevelRow">
7
  <div class="icwpTopLevelSpan <?php echo $flags[ 'show_ads' ] ? 'span11' : 'span11'; ?>" id="icwpOptionsTopPill">
8
 
9
  <ul class="nav nav-pills">
10
+ <li class="active">
11
  <a href="#icwpPillOptions" data-toggle="pill">
12
  <span class="dashicons dashicons-admin-settings">&nbsp;</span>
13
  <div class="title"><?php echo $strings[ 'options_title' ]; ?></div>
32
  </a>
33
  </li>
34
  <?php endif; ?>
35
+ <?php if ( $flags[ 'has_wizard' ] ) : ?>
36
+ <?php if ( $flags[ 'can_wizard' ] ) : ?>
37
+ <li id="icwpWizardPill">
38
+ <a href="<?php echo $hrefs[ 'wizard_link' ]; ?>"
39
+ title="Launch Guided Walk-Through Wizards" target="_blank">&nbsp;</a>
40
+ </li>
41
+ <?php else: ?>
42
+ <li id="icwpWizardPill">
43
+ <a href="#" title="Wizards are not available as your PHP version is too old.">&nbsp;</a>
44
+ </li>
45
+ <?php endif; ?>
46
+ <?php endif; ?>
47
  </ul>
48
  <div class="tab-content">
49
+ <div class="tab-pane active" id="icwpPillOptions">
 
50
  <?php echo $flags[ 'show_standard_options' ] ? $options_form : ''; ?>
51
  <?php echo $flags[ 'show_alt_content' ] ? $content[ 'alt' ] : ''; ?>
52
  </div>
60
  <div class="content-help"><?php echo $content[ 'help' ]; ?></div>
61
  </div>
62
  <?php endif; ?>
63
+ <div class="tab-pane" id="icwpPillSelect">
64
  <h3 style="text-align: center">&uarr; <?php echo 'Select Desired Section Above'; ?> &uarr;</h3>
65
  </div>
66
  </div>
templates/php/index_footer.php CHANGED
@@ -1,2 +1,14 @@
1
  </div><!-- / bootstrap-wpadmin -->
2
- </div><!-- / wrap -->
 
 
 
 
 
 
 
 
 
 
 
 
1
  </div><!-- / bootstrap-wpadmin -->
2
+ </div><!-- / wrap -->
3
+
4
+ <script type="text/javascript">
5
+ jQuery( 'a.feature-icon' ).popover( {
6
+ placement: 'left',
7
+ trigger: 'hover',
8
+ html: true
9
+ } );
10
+ jQuery( 'li#icwpWizardPill a' ).tooltip( {
11
+ placement: 'top',
12
+ trigger: 'hover focus'
13
+ } );
14
+ </script>
templates/php/index_header.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  $sBaseDirName = dirname( __FILE__ ).DIRECTORY_SEPARATOR;
3
- include_once( $sBaseDirName.'widgets'.DIRECTORY_SEPARATOR.'icwp_widgets.php' ); ?>
4
  <div class="wrap">
5
  <div class="bootstrap-wpadmin <?php echo isset( $sFeatureSlug ) ? $sFeatureSlug : ''; ?> icwp-options-page">
6
 
@@ -8,17 +8,15 @@ include_once( $sBaseDirName.'widgets'.DIRECTORY_SEPARATOR.'icwp_widgets.php' );
8
  <div class="span11">
9
  <div class="page-header">
10
  <h2>
11
- <span class="feature-headline">
12
- <a id="pluginlogo_32" class="header-icon32" href="http://icwp.io/2k" target="_blank"></a>
13
- <?php echo $sPageTitle; ?>
14
- <?php if ( !empty( $sTagline ) ) : ?>
15
- <small class="feature-tagline">- <?php echo $sTagline; ?></small>
16
- <?php endif; ?>
17
- <?php if ( $help_video[ 'show' ] ) : ?>
18
- <a href="#"
19
- class="btn btn-success"
20
- data-featherlight="#<?php echo $help_video[ 'display_id' ]; ?>">Help Video</a>
21
- <?php endif; ?>
22
  </h2>
23
  </div>
24
  <?php
@@ -29,7 +27,7 @@ include_once( $sBaseDirName.'widgets'.DIRECTORY_SEPARATOR.'icwp_widgets.php' );
29
  </div>
30
  <div class="span1">
31
  <?php if ( isset( $flags[ 'show_summary' ] ) && $flags[ 'show_summary' ] ) : ?>
32
- <?php include_once( $sBaseDirName.'snippets'.DIRECTORY_SEPARATOR.'state_summary.php' ); ?>
33
  <?php endif; ?>
34
  </div>
35
  </div>
1
  <?php
2
  $sBaseDirName = dirname( __FILE__ ).DIRECTORY_SEPARATOR;
3
+ include_once( $sBaseDirName.'widgets/icwp_widgets.php' ); ?>
4
  <div class="wrap">
5
  <div class="bootstrap-wpadmin <?php echo isset( $sFeatureSlug ) ? $sFeatureSlug : ''; ?> icwp-options-page">
6
 
8
  <div class="span11">
9
  <div class="page-header">
10
  <h2>
11
+ <a id="pluginlogo_32" class="header-icon32" href="http://icwp.io/2k" target="_blank"></a>
12
+ <span class="feature-headline"><?php echo $sPageTitle; ?></span>
13
+ <?php if ( $help_video[ 'show' ] ) : ?>
14
+ <a href="#" class="btn btn-success"
15
+ data-featherlight="#<?php echo $help_video[ 'display_id' ]; ?>">Help Video</a>
16
+ <?php endif; ?>
17
+ <?php if ( !empty( $sTagline ) ) : ?>
18
+ <small class="feature-tagline">- <?php echo $sTagline; ?></small>
19
+ <?php endif; ?>
 
 
20
  </h2>
21
  </div>
22
  <?php
27
  </div>
28
  <div class="span1">
29
  <?php if ( isset( $flags[ 'show_summary' ] ) && $flags[ 'show_summary' ] ) : ?>
30
+ <?php include_once( $sBaseDirName.'snippets/state_summary.php' ); ?>
31
  <?php endif; ?>
32
  </div>
33
  </div>
templates/php/snippets/module-help-plugin.php CHANGED
@@ -15,7 +15,7 @@
15
  <p>Basically you select the IP address from the list that represents your own, personal
16
  public IP address.
17
  </p>
18
- <p>Don't know your IP address? Go to Google and search: "What is my IP address"
19
  (<a href="http://icwp.io/an" target="_blank">We've done it for you</a> ;)
20
  </p>
21
  <p>With this result, you should be able to select the correct item from the list. The higher up the
15
  <p>Basically you select the IP address from the list that represents your own, personal
16
  public IP address.
17
  </p>
18
+ <p>Don't know your IP address? Go here:
19
  (<a href="http://icwp.io/an" target="_blank">We've done it for you</a> ;)
20
  </p>
21
  <p>With this result, you should be able to select the correct item from the list. The higher up the
templates/php/snippets/module-help-template.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ if ( isset( $slug ) ) {
3
+ include_once( dirname( __FILE__ ).sprintf( '/module-help-%s.php', $slug ) );
4
+ }
templates/php/snippets/module-plugin-actions.php CHANGED
@@ -12,7 +12,8 @@
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 is covered in many areas, and your webhost/server is a critical one of these.</p>
 
16
  <p>Note: As Shield Security is further developed, more and more features will require higher versions of PHP.</p>
17
  </div>
18
  <?php endif; ?>
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 Shield Security is further developed, more and more features will require higher versions of PHP.</p>
18
  </div>
19
  <?php endif; ?>
templates/php/snippets/options_form.php CHANGED
@@ -4,8 +4,10 @@
4
 
5
  <ul class="nav nav-tabs">
6
  <?php foreach ( $aAllOptions as $sOptionSection ) : ?>
7
- <li class="<?php echo $sOptionSection['primary'] ? 'active' : '' ?>">
8
- <a href="#<?php echo $sOptionSection['slug'] ?>" data-toggle="tab" ><?php echo $sOptionSection['title_short']; ?></a>
 
 
9
  </li>
10
  <?php endforeach; ?>
11
  </ul>
@@ -13,174 +15,195 @@
13
  <div class="tab-content">
14
  <?php foreach ( $aAllOptions as $sOptionSection ) : ?>
15
 
16
- <div class="tab-pane fade <?php echo $sOptionSection['primary'] ? 'active in primary_section' : 'non_primary_section'; ?>"
17
- id="<?php echo $sOptionSection['slug'] ?>">
18
- <div class="row option_section_row <?php echo $sOptionSection['primary'] ? 'primary_section' : 'non_primary_section'; ?>"
19
- id="row-<?php echo $sOptionSection['slug']; ?>">
20
- <div class="span9">
21
- <fieldset>
22
  <legend>
23
- <?php echo $sOptionSection['title']; ?>
24
- <?php if ( !empty( $sOptionSection['help_video_url'] ) ) : ?>
25
- <div style="float:right;">
26
-
27
- <a href="<?php echo $sOptionSection['help_video_url']; ?>"
28
- class="btn"
29
- data-featherlight-iframe-height="454"
30
- data-featherlight-iframe-width="772"
31
- data-featherlight="iframe">
32
  <span class="dashicons dashicons-controls-play"></span> Help Video
33
  </a>
34
  </div>
35
- <?php endif; ?>
36
  </legend>
37
 
38
- <?php if ( !empty( $sOptionSection['summary'] ) ) : ?>
39
- <div class="row row_section_summary">
40
- <div class="span9">
41
- <?php foreach( $sOptionSection['summary'] as $sItem ) : ?>
42
  <p class="noselect"><?php echo $sItem; ?></p>
43
  <?php endforeach; ?>
44
  </div>
45
  </div>
46
- <?php endif; ?>
47
-
48
- <?php foreach( $sOptionSection['options'] as $nKeyRow => $aOption ) :
49
- $sOptionKey = $aOption['key'];
50
- $sOptionType = $aOption['type'];
51
- $bEnabled = $aOption[ 'enabled' ];
52
- $sDisabledText = $bEnabled ? '' : 'disabled="Disabled"';
53
- ?>
54
- <div class="row row_number_<?php echo $nKeyRow; ?> option_row">
55
-
56
- <?php if ( $sOptionKey == 'spacer' ) : ?>
57
- <div class="span8"></div>
58
- <?php else: ?>
59
- <div class="item_group span8
60
- <?php echo $bEnabled ? 'enabled' : 'disabled overlay_container' ?>
61
- <?php echo ( $aOption['value'] == 'Y' || $aOption['value'] != $aOption['default'] ) ? 'selected_item_group':''; ?>"
62
- id="span_<?php echo $var_prefix.$sOptionKey; ?>">
63
-
64
- <?php if ( !$bEnabled ) : ?>
65
- <div class="option_overlay">
66
- <div class="overlay_message">
67
- <a href="<?php echo $hrefs['go_pro']; ?>" target="_blank">
68
- A Pro Feature</a>
69
- </div>
70
  </div>
71
- <?php endif; ?>
72
-
73
- <div class="control-group">
74
- <label class="control-label" for="<?php echo $var_prefix.$sOptionKey; ?>">
75
- <?php echo $aOption['name']; ?>
76
- <br />
77
- <?php if ( !empty( $aOption['link_info'] ) ) : ?>
78
- [
79
- <a href="<?php echo $aOption['link_info']; ?>" target="_blank"><?php echo $strings['more_info']; ?></a>
80
- <?php if ( !empty( $aOption['link_blog'] ) ) : ?>
81
- | <a href="<?php echo $aOption['link_blog']; ?>" target="_blank"><?php echo $strings['blog']; ?></a>
 
 
 
82
  <?php endif; ?>
83
- ]
84
- <?php endif; ?>
85
- </label>
86
- <div class="controls">
87
- <div class="option_section <?php echo ( $aOption['value'] == 'Y' ) ? 'selected_item':''; ?>"
88
- id="option_section_<?php echo $var_prefix.$sOptionKey; ?>">
89
- <label>
90
- <?php if ( $sOptionType == 'checkbox' ) : ?>
91
-
92
- <input type="checkbox" name="<?php echo $var_prefix.$sOptionKey; ?>" id="<?php echo $var_prefix.$sOptionKey; ?>"
93
- value="Y" <?php echo ( $aOption['value'] == 'Y' ) ? 'checked="checked"':''; ?>
94
- <?php echo $sDisabledText; ?> />
95
- <?php echo $aOption['summary']; ?>
96
-
97
- <?php elseif ( $sOptionType == 'text' ) : ?>
98
-
99
- <p><?php echo $aOption['summary']; ?></p>
100
- <textarea name="<?php echo $var_prefix.$sOptionKey; ?>" id="<?php echo $var_prefix.$sOptionKey; ?>"
101
- placeholder="<?php echo $aOption['value']; ?>" rows="<?php echo $aOption['rows']; ?>"
102
- class="span5" <?php echo $sDisabledText; ?>><?php echo $aOption['value']; ?></textarea>
103
-
104
- <?php elseif ( $sOptionType == 'noneditable_text' ) : ?>
105
-
106
- <p><?php echo $aOption['summary']; ?></p>
107
- <input type="text" readonly value="<?php echo $aOption['value']; ?>" class="span5" />
108
-
109
- <?php elseif ( $sOptionType == 'password' ) : ?>
110
-
111
- <p><?php echo $aOption['summary']; ?></p>
112
- <input type="password" name="<?php echo $var_prefix.$sOptionKey; ?>" id="<?php echo $var_prefix.$sOptionKey; ?>"
113
- value="<?php echo $aOption['value']; ?>" placeholder="<?php echo $aOption['value']; ?>"
114
- class="span5" <?php echo $sDisabledText; ?> />
115
-
116
- <?php elseif ( $sOptionType == 'email' ) : ?>
117
-
118
- <p><?php echo $aOption['summary']; ?></p>
119
- <input type="email" name="<?php echo $var_prefix.$sOptionKey; ?>" id="<?php echo $var_prefix.$sOptionKey; ?>"
120
- value="<?php echo $aOption['value']; ?>" placeholder="<?php echo $aOption['value']; ?>"
121
- class="span5" <?php echo $sDisabledText; ?> />
122
-
123
- <?php elseif ( $sOptionType == 'select' ) : ?>
124
-
125
- <p><?php echo $aOption['summary']; ?></p>
126
- <select name="<?php echo $var_prefix.$sOptionKey; ?>" id="<?php echo $var_prefix.$sOptionKey; ?>"
127
- <?php echo $sDisabledText; ?> >
128
- <?php foreach( $aOption['value_options'] as $sOptionValue => $sOptionValueName ) : ?>
129
- <option value="<?php echo $sOptionValue; ?>" id="<?php echo $var_prefix.$sOptionKey; ?>_<?php echo $sOptionValue; ?>"
130
- <?php echo ( $sOptionValue == $aOption['value'] ) ? 'selected="selected"' : ''; ?>
131
- ><?php echo $sOptionValueName; ?></option>
132
- <?php endforeach; ?>
133
- </select>
134
-
135
- <?php elseif ( $sOptionType == 'multiple_select' ) : ?>
136
-
137
- <p><?php echo $aOption['summary']; ?></p>
138
- <select name="<?php echo $var_prefix.$sOptionKey; ?>[]" id="<?php echo $var_prefix.$sOptionKey; ?>"
139
- multiple="multiple" multiple size="<?php echo count( $aOption['value_options'] ); ?>"
140
- <?php echo $sDisabledText; ?> >
141
- <?php foreach( $aOption['value_options'] as $sOptionValue => $sOptionValueName ) : ?>
142
- <option value="<?php echo $sOptionValue; ?>" id="<?php echo $var_prefix.$sOptionKey; ?>_<?php echo $sOptionValue; ?>"
143
- <?php echo in_array( $sOptionValue, $aOption['value'] ) ? 'selected="selected"' : ''; ?>
144
- ><?php echo $sOptionValueName; ?></option>
145
- <?php endforeach; ?>
146
- </select>
147
-
148
- <?php elseif ( $sOptionType == 'array' ) : ?>
149
-
150
- <p><?php echo $aOption['summary']; ?></p>
151
- <textarea name="<?php echo $var_prefix.$sOptionKey; ?>" id="<?php echo $var_prefix.$sOptionKey; ?>"
152
- placeholder="<?php echo $aOption['value']; ?>" rows="<?php echo $aOption['rows']; ?>"
153
- class="span5" <?php echo $sDisabledText; ?>><?php echo $aOption['value']; ?></textarea>
154
-
155
- <?php elseif ( $sOptionType == 'comma_separated_lists' ) : ?>
156
-
157
- <p><?php echo $aOption['summary']; ?></p>
158
- <textarea name="<?php echo $var_prefix.$sOptionKey; ?>" id="<?php echo $var_prefix.$sOptionKey; ?>"
159
- placeholder="<?php echo $aOption['value']; ?>" rows="<?php echo $aOption['rows']; ?>"
160
- class="span5" <?php echo $sDisabledText; ?> ><?php echo $aOption['value']; ?></textarea>
161
-
162
- <?php elseif ( $sOptionType == 'integer' ) : ?>
163
-
164
- <p><?php echo $aOption['summary']; ?></p>
165
- <input type="text" name="<?php echo $var_prefix.$sOptionKey; ?>" id="<?php echo $var_prefix.$sOptionKey; ?>"
166
- value="<?php echo $aOption['value']; ?>" placeholder="<?php echo $aOption['value']; ?>"
167
- class="span5" <?php echo $sDisabledText; ?> />
168
-
169
- <?php else : ?>
170
- ERROR: Should never reach this point.
171
- <?php endif; ?>
172
-
173
- </label>
174
- <p class="help-block"><?php echo $aOption['description']; ?></p>
175
- <div style="clear:both"></div>
176
- </div>
177
- </div><!-- controls -->
178
- </div><!-- control-group -->
179
- </div>
180
- <?php endif; ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181
  </div>
182
- <?php endforeach; ?>
183
- </fieldset>
184
  </div>
185
  </div>
186
  </div>
@@ -189,9 +212,28 @@
189
 
190
  <div class="form-actions">
191
  <input type="hidden" name="<?php echo $var_prefix; ?>feature_slug" value="<?php echo $feature_slug; ?>" />
192
- <input type="hidden" name="<?php echo $var_prefix; ?>all_options_input" value="<?php echo $all_options_input; ?>" />
 
193
  <input type="hidden" name="<?php echo $var_prefix; ?>plugin_form_submit" value="Y" />
194
- <button type="submit" class="btn btn-success btn-large icwp-form-button" name="submit"><?php _wpsf_e( 'Save All Settings' ); ?></button>
 
195
  </div>
196
  </form>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
  </div>
4
 
5
  <ul class="nav nav-tabs">
6
  <?php foreach ( $aAllOptions as $sOptionSection ) : ?>
7
+ <li class="<?php echo $sOptionSection[ 'primary' ] ? 'active' : '' ?>">
8
+ <a href="#<?php echo $sOptionSection[ 'slug' ] ?>" data-toggle="tab">
9
+ <?php echo $sOptionSection[ 'title_short' ]; ?>
10
+ </a>
11
  </li>
12
  <?php endforeach; ?>
13
  </ul>
15
  <div class="tab-content">
16
  <?php foreach ( $aAllOptions as $sOptionSection ) : ?>
17
 
18
+ <div class="tab-pane fade <?php echo $sOptionSection[ 'primary' ] ? 'active in primary_section' : 'non_primary_section'; ?>"
19
+ id="<?php echo $sOptionSection[ 'slug' ] ?>">
20
+ <div class="row-fluid option_section_row <?php echo $sOptionSection[ 'primary' ] ? 'primary_section' : 'non_primary_section'; ?>"
21
+ id="row-<?php echo $sOptionSection[ 'slug' ]; ?>">
22
+ <div class="span12 options-body">
 
23
  <legend>
24
+ <?php echo $sOptionSection[ 'title' ]; ?>
25
+ <?php if ( !empty( $sOptionSection[ 'help_video_url' ] ) ) : ?>
26
+ <div style="float:right;">
27
+
28
+ <a href="<?php echo $sOptionSection[ 'help_video_url' ]; ?>"
29
+ class="btn"
30
+ data-featherlight-iframe-height="454"
31
+ data-featherlight-iframe-width="772"
32
+ data-featherlight="iframe">
33
  <span class="dashicons dashicons-controls-play"></span> Help Video
34
  </a>
35
  </div>
36
+ <?php endif; ?>
37
  </legend>
38
 
39
+ <?php if ( !empty( $sOptionSection[ 'summary' ] ) ) : ?>
40
+ <div class="row-fluid row_section_summary">
41
+ <div class="span12">
42
+ <?php foreach ( $sOptionSection[ 'summary' ] as $sItem ) : ?>
43
  <p class="noselect"><?php echo $sItem; ?></p>
44
  <?php endforeach; ?>
45
  </div>
46
  </div>
47
+ <?php endif; ?>
48
+
49
+ <?php foreach ( $sOptionSection[ 'options' ] as $nKeyRow => $aOption ) :
50
+ $sOptionKey = $aOption[ 'key' ];
51
+ $sFullOptionKey = $var_prefix.$sOptionKey;
52
+ $mOptValue = $aOption[ 'value' ];
53
+ $sOptionType = $aOption[ 'type' ];
54
+ $bEnabled = $aOption[ 'enabled' ];
55
+ $sDisabledText = $bEnabled ? '' : 'disabled="Disabled"';
56
+ ?>
57
+ <div class="row-fluid option_row row_number_<?php echo $nKeyRow; ?>">
58
+ <div class="item_group span12
59
+ <?php echo $bEnabled ? 'enabled' : 'disabled overlay_container' ?>
60
+ <?php echo ( $mOptValue == 'Y' || $mOptValue != $aOption[ 'default' ] ) ? 'selected_item_group' : ''; ?>"
61
+ id="span_<?php echo $sFullOptionKey; ?>">
62
+
63
+ <?php if ( !$bEnabled ) : ?>
64
+ <div class="option_overlay">
65
+ <div class="overlay_message">
66
+ <a href="<?php echo $hrefs[ 'go_pro' ]; ?>" target="_blank">
67
+ This is a premium feature</a>
 
 
 
68
  </div>
69
+ </div>
70
+ <?php endif; ?>
71
+
72
+ <div class="control-group">
73
+ <label class="control-label" for="<?php echo $sFullOptionKey; ?>">
74
+ <span class="optname"><?php echo $aOption[ 'name' ]; ?></span>
75
+ <?php if ( !empty( $aOption[ 'link_info' ] ) ) : ?>
76
+ <span class="optlinks">
77
+ [
78
+ <a href="<?php echo $aOption[ 'link_info' ]; ?>"
79
+ target="_blank"><?php echo $strings[ 'more_info' ]; ?></a>
80
+ <?php if ( !empty( $aOption[ 'link_blog' ] ) ) : ?>
81
+ | <a href="<?php echo $aOption[ 'link_blog' ]; ?>"
82
+ target="_blank"><?php echo $strings[ 'blog' ]; ?></a>
83
  <?php endif; ?>
84
+ ]
85
+ </span>
86
+ <?php endif; ?>
87
+ </label>
88
+ <div class="controls">
89
+ <div class="option_section <?php echo ( $mOptValue == 'Y' ) ? 'selected_item' : ''; ?>"
90
+ id="option_section_<?php echo $sFullOptionKey; ?>">
91
+
92
+ <label class="for<?php echo $sOptionType; ?>">
93
+ <?php if ( $sOptionType == 'checkbox' ) : ?>
94
+ <span class="switch">
95
+ <input type="checkbox"
96
+ name="<?php echo $sFullOptionKey; ?>"
97
+ id="<?php echo $sFullOptionKey; ?>"
98
+ value="Y" <?php echo ( $mOptValue == 'Y' ) ? 'checked="checked"' : ''; ?>
99
+ <?php echo $sDisabledText; ?> />
100
+ <span class="slider round"></span>
101
+ </span>
102
+ <span class="summary"><?php echo $aOption[ 'summary' ]; ?></span>
103
+
104
+ <?php elseif ( $sOptionType == 'text' ) : ?>
105
+
106
+ <p><?php echo $aOption[ 'summary' ]; ?></p>
107
+ <textarea name="<?php echo $sFullOptionKey; ?>"
108
+ id="<?php echo $sFullOptionKey; ?>"
109
+ placeholder="<?php echo $mOptValue; ?>"
110
+ rows="<?php echo $aOption[ 'rows' ]; ?>"
111
+ class="span5" <?php echo $sDisabledText; ?>><?php echo $mOptValue; ?></textarea>
112
+
113
+ <?php elseif ( $sOptionType == 'noneditable_text' ) : ?>
114
+
115
+ <p><?php echo $aOption[ 'summary' ]; ?></p>
116
+ <input type="text" readonly
117
+ value="<?php echo $mOptValue; ?>" class="span5" />
118
+
119
+ <?php elseif ( $sOptionType == 'password' ) : ?>
120
+
121
+ <p><?php echo $aOption[ 'summary' ]; ?></p>
122
+ <input type="password" name="<?php echo $sFullOptionKey; ?>"
123
+ id="<?php echo $sFullOptionKey; ?>"
124
+ value="<?php echo $mOptValue; ?>"
125
+ placeholder="<?php echo $mOptValue; ?>"
126
+ class="span5" <?php echo $sDisabledText; ?> />
127
+
128
+ <?php elseif ( $sOptionType == 'email' ) : ?>
129
+
130
+ <p><?php echo $aOption[ 'summary' ]; ?></p>
131
+ <input type="email" name="<?php echo $sFullOptionKey; ?>"
132
+ id="<?php echo $sFullOptionKey; ?>"
133
+ value="<?php echo $mOptValue; ?>"
134
+ placeholder="<?php echo $mOptValue; ?>"
135
+ class="span5" <?php echo $sDisabledText; ?> />
136
+
137
+ <?php elseif ( $sOptionType == 'select' ) : ?>
138
+
139
+ <p><?php echo $aOption[ 'summary' ]; ?></p>
140
+ <select name="<?php echo $sFullOptionKey; ?>"
141
+ id="<?php echo $sFullOptionKey; ?>"
142
+ <?php echo $sDisabledText; ?> >
143
+ <?php foreach ( $aOption[ 'value_options' ] as $sOptionValue => $sOptionValueName ) : ?>
144
+ <option value="<?php echo $sOptionValue; ?>"
145
+ id="<?php echo $sFullOptionKey; ?>_<?php echo $sOptionValue; ?>"
146
+ <?php echo ( $sOptionValue == $mOptValue ) ? 'selected="selected"' : ''; ?>
147
+ ><?php echo $sOptionValueName; ?></option>
148
+ <?php endforeach; ?>
149
+ </select>
150
+
151
+ <?php elseif ( $sOptionType == 'multiple_select' ) : ?>
152
+
153
+ <p><?php echo $aOption[ 'summary' ]; ?></p>
154
+ <select name="<?php echo $sFullOptionKey; ?>[]"
155
+ id="<?php echo $sFullOptionKey; ?>"
156
+ multiple="multiple" multiple
157
+ size="<?php echo count( $aOption[ 'value_options' ] ); ?>"
158
+ <?php echo $sDisabledText; ?> >
159
+ <?php foreach ( $aOption[ 'value_options' ] as $sOptionValue => $sOptionValueName ) : ?>
160
+ <option value="<?php echo $sOptionValue; ?>"
161
+ id="<?php echo $sFullOptionKey; ?>_<?php echo $sOptionValue; ?>"
162
+ <?php echo in_array( $sOptionValue, $mOptValue ) ? 'selected="selected"' : ''; ?>
163
+ ><?php echo $sOptionValueName; ?></option>
164
+ <?php endforeach; ?>
165
+ </select>
166
+
167
+ <?php elseif ( $sOptionType == 'array' ) : ?>
168
+
169
+ <p><?php echo $aOption[ 'summary' ]; ?></p>
170
+ <textarea name="<?php echo $sFullOptionKey; ?>"
171
+ id="<?php echo $sFullOptionKey; ?>"
172
+ placeholder="<?php echo $mOptValue; ?>"
173
+ rows="<?php echo $aOption[ 'rows' ]; ?>"
174
+ class="span5" <?php echo $sDisabledText; ?>><?php echo $mOptValue; ?></textarea>
175
+
176
+ <?php elseif ( $sOptionType == 'comma_separated_lists' ) : ?>
177
+
178
+ <p><?php echo $aOption[ 'summary' ]; ?></p>
179
+ <textarea name="<?php echo $sFullOptionKey; ?>"
180
+ id="<?php echo $sFullOptionKey; ?>"
181
+ placeholder="<?php echo $mOptValue; ?>"
182
+ rows="<?php echo $aOption[ 'rows' ]; ?>"
183
+ class="span5" <?php echo $sDisabledText; ?> ><?php echo $mOptValue; ?></textarea>
184
+
185
+ <?php elseif ( $sOptionType == 'integer' ) : ?>
186
+
187
+ <p><?php echo $aOption[ 'summary' ]; ?></p>
188
+ <input type="text" name="<?php echo $sFullOptionKey; ?>"
189
+ id="<?php echo $sFullOptionKey; ?>"
190
+ value="<?php echo $mOptValue; ?>"
191
+ placeholder="<?php echo $mOptValue; ?>"
192
+ class="span5" <?php echo $sDisabledText; ?> />
193
+
194
+ <?php else : ?>
195
+ ERROR: Should never reach this point.
196
+ <?php endif; ?>
197
+
198
+ </label>
199
+ <p class="help-block"><?php echo $aOption[ 'description' ]; ?></p>
200
+ <div style="clear:both"></div>
201
+ </div>
202
+ </div><!-- controls -->
203
+ </div><!-- control-group -->
204
+ </div>
205
  </div>
206
+ <?php endforeach; ?>
 
207
  </div>
208
  </div>
209
  </div>
212
 
213
  <div class="form-actions">
214
  <input type="hidden" name="<?php echo $var_prefix; ?>feature_slug" value="<?php echo $feature_slug; ?>" />
215
+ <input type="hidden" name="<?php echo $var_prefix; ?>all_options_input"
216
+ value="<?php echo $all_options_input; ?>" />
217
  <input type="hidden" name="<?php echo $var_prefix; ?>plugin_form_submit" value="Y" />
218
+ <button type="submit" class="btn btn-success btn-large icwp-form-button"
219
+ name="submit"><?php _wpsf_e( 'Save All Settings' ); ?></button>
220
  </div>
221
  </form>
222
+ <div class="pull-right well">
223
+ <h5 style="margin-bottom: 10px;">Options Legend</h5>
224
+ <label class="forcheckbox">
225
+ <span class="switch">
226
+ <input type="checkbox" name="legend" id="legend" value="Y" checked="checked" disabled="disabled">
227
+ <span class="slider round"></span>
228
+ </span>
229
+ <span class="summary">Option is turned on / enabled</span>
230
+ </label>
231
+ <label class="forcheckbox">
232
+ <span class="switch">
233
+ <input type="checkbox" name="legend" id="legend" value="Y" disabled="disabled">
234
+ <span class="slider round"></span>
235
+ </span>
236
+ <span class="summary">Option is turned off / disabled</span>
237
+ </label>
238
+ </div>
239
  </div>
templates/php/snippets/plugin_badge.php CHANGED
@@ -37,7 +37,7 @@
37
  font-size: 12px;
38
  line-height: 17px;
39
  padding-left: 43px;
40
-
41
  -webkit-transition: opacity 1s; /* Safari */
42
  transition: opacity 1s;
43
  }
@@ -80,7 +80,9 @@
80
  </style>
81
  <div id="icwpWpsfSiteBadge">
82
  <a id="icwpWpsfCloseButton">x</a>
83
- <a href="http://icwp.io/wpsecurityfirewall" target="_blank" title="This site is protected by the Shield Security plugin.">
 
 
84
  <img src="%s" alt="%s Logo" />
85
  <div class="badge-text">%s</div>
86
  </a>
37
  font-size: 12px;
38
  line-height: 17px;
39
  padding-left: 43px;
40
+ letter-spacing: 0;
41
  -webkit-transition: opacity 1s; /* Safari */
42
  transition: opacity 1s;
43
  }
80
  </style>
81
  <div id="icwpWpsfSiteBadge">
82
  <a id="icwpWpsfCloseButton">x</a>
83
+ <a href="http://icwp.io/wpsecurityfirewall" target="_blank"
84
+ title="This site is protected by the Shield Security plugin."
85
+ %s>
86
  <img src="%s" alt="%s Logo" />
87
  <div class="badge-text">%s</div>
88
  </a>
templates/php/snippets/state_summary.php CHANGED
@@ -3,10 +3,7 @@ if ( empty( $aSummaryData ) ) {
3
  return;
4
  } ?>
5
 
6
- <div class="feature-summary-blocks
7
- <?php echo $aSummary[ 'active' ] ? 'active-feature' : ''; ?>
8
- state-<?php echo $aSummary[ 'enabled' ] ? 'on' : 'off'; ?>"
9
- >
10
  <?php foreach ( $aSummaryData as $nKey => $aSummary ) : ?>
11
  <div class="summary-state state-<?php echo $aSummary[ 'enabled' ] ? 'on' : 'off'; ?> <?php echo $aSummary[ 'active' ] ? 'active-feature' : ''; ?> "
12
  id="feature-<?php echo $aSummary[ 'slug' ]; ?>">
@@ -18,12 +15,4 @@ if ( empty( $aSummaryData ) ) {
18
  </div>
19
  <?php endforeach; ?>
20
  <div style="clear: both"></div>
21
- </div>
22
- <script type="text/javascript">
23
- jQuery( 'a.feature-icon' ).popover( {
24
- placement: 'left',
25
- trigger: 'hover',
26
- html: true
27
- } );
28
- // jQuery( '#feature-plugin a.feature-icon' ).popover( 'show' );
29
- </script>
3
  return;
4
  } ?>
5
 
6
+ <div class="feature-summary-blocks">
 
 
 
7
  <?php foreach ( $aSummaryData as $nKey => $aSummary ) : ?>
8
  <div class="summary-state state-<?php echo $aSummary[ 'enabled' ] ? 'on' : 'off'; ?> <?php echo $aSummary[ 'active' ] ? 'active-feature' : ''; ?> "
9
  id="feature-<?php echo $aSummary[ 'slug' ]; ?>">
15
  </div>
16
  <?php endforeach; ?>
17
  <div style="clear: both"></div>
18
+ </div>
 
 
 
 
 
 
 
 
templates/twig/pages/base.twig CHANGED
@@ -25,27 +25,36 @@
25
  </head>
26
  {% block body %}
27
  <body>
28
- <div class="container-fluid">
29
- {% block body_content_header %}
30
- <div class="row">
31
- <div class="col-md-4 col-md-offset-4">
32
- <img id="ShieldLogo" class="img-responsive" src="{{ hrefs.shield_logo }}" />
33
- </div>
34
- </div>
35
- {% endblock %}
36
- {% block body_content_main %}
37
- <div class="row">
38
- <div class="col-md-4 col-md-offset-4"></div>
39
- </div>
40
  {% endblock %}
41
- {% block body_content_footer %}
42
- <div class="row">
43
- <div class="col-md-4 col-md-offset-4"></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  </div>
45
  {% endblock %}
 
46
  {% block body_footer %}
47
  {% endblock %}
48
- </div>
49
- </body>
 
 
50
  {% endblock %}
51
  </html>
25
  </head>
26
  {% block body %}
27
  <body>
28
+ {% block body_header %}
 
 
 
 
 
 
 
 
 
 
 
29
  {% endblock %}
30
+
31
+ {% block body_content %}
32
+ <div class="container-fluid">
33
+ {% block body_content_header %}
34
+ <div class="row">
35
+ <div class="col-lg-3 col-lg-offset-4 col-md-4 col-md-offset-4 col-sm-4 col-sm-offset-4">
36
+ <img id="ShieldLogo" class="img-responsive" src="{{ hrefs.plugin_banner }}" />
37
+ </div>
38
+ </div>
39
+ {% endblock %}
40
+ {% block body_content_main %}
41
+ <div class="row">
42
+ <div class="col-md-4 col-md-offset-4"></div>
43
+ </div>
44
+ {% endblock %}
45
+ {% block body_content_footer %}
46
+ <div class="row">
47
+ <div class="col-md-4 col-md-offset-4"></div>
48
+ </div>
49
+ {% endblock %}
50
  </div>
51
  {% endblock %}
52
+
53
  {% block body_footer %}
54
  {% endblock %}
55
+
56
+ {% block body_footer_scripts %}
57
+ {% endblock %}
58
+ </body>
59
  {% endblock %}
60
  </html>
templates/twig/wizard/base_finish.twig DELETED
@@ -1,7 +0,0 @@
1
- {% extends 'wizard/base.twig' %}
2
-
3
- {% block slide_header_next %}{% endblock %}
4
- {% block slide_footer %}
5
- <hr />
6
- <a href="{{ hrefs.dashboard }}" class="btn btn-default">&#x21d0; Return To The Shield WordPress Dashboard</a>
7
- {% endblock %}
 
 
 
 
 
 
 
templates/twig/wizard/base_start.twig DELETED
@@ -1,3 +0,0 @@
1
- {% extends 'wizard/base.twig' %}
2
-
3
- {% block slide_header_previous %}{% endblock %}
 
 
 
templates/twig/wizard/pages/base.twig ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'pages/base.twig' %}
2
+
3
+ {% block body_footer %}
4
+ {% if not flags.is_premium %}
5
+ <div id="FooterWizardBanner" class="container-fluid">
6
+ <div class="row"><div id="WizardTop" class="span12"></div></div>
7
+
8
+ <div id="WizardBanner" class="row">
9
+ <div class="col-lg-4 col-lg-offset-4 col-md-5 col-md-offset-3 col-sm-7 col-sm-offset-1 col-xs-9">
10
+ <p>Support future development and get extra Shield features:
11
+ <br />Vulnerability Scanner; Options Import; Email Support+more.</p>
12
+ </div>
13
+ <div class="col-lg-1 col-md-2 col-sm-2 col-xs-1">
14
+ <a href="{{ hrefs.goprofooter }}" target="_blank" class="btn btn-default">Go Pro Today &rarr;</a>
15
+ </div>
16
+ </div>
17
+ </div>
18
+ {% endif %}
19
+ {% endblock %}
templates/twig/wizard/pages/landing.twig ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'wizard/pages/base.twig' %}
2
+
3
+ {% block head_stylesheets %}
4
+ {{ parent() }}
5
+ <link rel="stylesheet" href="{{ hrefs.css_wizard }}" />
6
+ {% endblock %}
7
+
8
+ {% block head_scripts %}
9
+ {{ parent() }}
10
+ {% endblock %}
11
+
12
+ {% block body_content_main %}
13
+ <div class="row">
14
+ <div class="col-md-4 col-md-offset-4">
15
+ <p>This module comes with {{ data.mod_wizards_count }} Wizard(s).</p>
16
+ <p>Please click the link below of the Guided Wizard you'd like to launch.</p>
17
+ </div>
18
+ </div>
19
+ <div class="row">
20
+ <div class="col-md-2"></div>
21
+ {% for wizard in data.mod_wizards %}
22
+ <div class="col-md-4">
23
+ <div class="wizard_slot">
24
+ <div><h3>{{ wizard.title }}</h3></div>
25
+ <div>
26
+ <p>{{ wizard.desc }}</p>
27
+ {% if wizard.has_premium %}
28
+ <p>{{ strings.premium_note }}</p>
29
+ {% endif %}
30
+ </div>
31
+ <div><a class="btn btn-info" href="{{ wizard.url }}">Launch Wizard</a></div>
32
+ </div>
33
+ </div>
34
+ {% endfor %}
35
+ </div>
36
+ {% endblock %}
templates/twig/{pages → wizard/pages}/wizard.twig RENAMED
@@ -1,4 +1,4 @@
1
- {% extends 'pages/base.twig' %}
2
 
3
  {% block head_stylesheets %}
4
  {{ parent() }}
@@ -23,7 +23,7 @@
23
  </div>
24
  {% endblock %}
25
 
26
- {% block body_footer %}
27
  <script type="text/javascript">
28
 
29
  jQuery( document ).ready( function ( $ ) {
@@ -157,10 +157,6 @@ var iCWP_WPSF_Wizard_FormHandler = new function () {
157
 
158
  jQuery.post( '{{ ajax.content.ajaxurl }}', $oForm.serialize(),
159
  function ( oResponse ) {
160
- var sMessage = 'Unknown Error';
161
- if ( undefined !== oResponse.data ) {
162
- sMessage = oResponse.data.message;
163
- }
164
 
165
  if ( oResponse.success ) {
166
  $oResponseField.removeClass( 'bg-danger' )
@@ -171,12 +167,23 @@ var iCWP_WPSF_Wizard_FormHandler = new function () {
171
  .addClass( 'bg-danger' );
172
  $oSubmitButton.prop( 'disabled', false );
173
  }
 
 
 
 
 
 
 
 
 
 
174
  $oResponseField.html( sMessage );
175
 
176
- if ( undefined !== oResponse.data && undefined !== oResponse.data.rerender
177
- && oResponse.data.rerender === true ) {
178
  iCWP_WPSF_Wizard_FormHandler.reRenderCurrent();
179
  }
 
 
180
  }
181
  ).always(
182
  function () {
1
+ {% extends 'wizard/pages/base.twig' %}
2
 
3
  {% block head_stylesheets %}
4
  {{ parent() }}
23
  </div>
24
  {% endblock %}
25
 
26
+ {% block body_footer_scripts %}
27
  <script type="text/javascript">
28
 
29
  jQuery( document ).ready( function ( $ ) {
157
 
158
  jQuery.post( '{{ ajax.content.ajaxurl }}', $oForm.serialize(),
159
  function ( oResponse ) {
 
 
 
 
160
 
161
  if ( oResponse.success ) {
162
  $oResponseField.removeClass( 'bg-danger' )
167
  .addClass( 'bg-danger' );
168
  $oSubmitButton.prop( 'disabled', false );
169
  }
170
+
171
+ var bRerender = false;
172
+ var sMessage = 'Unknown Error';
173
+ if ( undefined !== oResponse.data ) {
174
+
175
+ if ( undefined !== oResponse.data.rerender && oResponse.data.rerender === true ) {
176
+ bRerender = true;
177
+ }
178
+ sMessage = oResponse.data.message;
179
+ }
180
  $oResponseField.html( sMessage );
181
 
182
+ if ( bRerender ) {
 
183
  iCWP_WPSF_Wizard_FormHandler.reRenderCurrent();
184
  }
185
+
186
+ jQuery( $oForm ).trigger( 'icwpWizardFormSubmit', oResponse.success );
187
  }
188
  ).always(
189
  function () {
templates/twig/wizard/slide-import_finished.twig DELETED
@@ -1,7 +0,0 @@
1
- {% extends 'wizard/base_finish.twig' %}
2
-
3
- {% block slide_body %}
4
- <h3>Finished: Shield Options Import Wizard</h3>
5
- <p>This is the end of the Shield Security Network/Import Wizard. Click the link below to return to the main
6
- WordPress dashboard.</p>
7
- {% endblock %}
 
 
 
 
 
 
 
templates/twig/wizard/{base.twig → slides/common/base.twig} RENAMED
@@ -4,12 +4,12 @@
4
  {% block slide_header_nav %}
5
  <div class="container-fluid">
6
  <div class="row">
7
- <div class="col-md-6">
8
  {% block slide_header_previous %}
9
  <button class="btn btn-default btn-block ButtonPreviousSlide">&larr; Previous Step </button>
10
  {% endblock %}
11
  </div>
12
- <div class="col-md-6">
13
  {% block slide_header_next %}
14
  <button class="btn btn-info btn-block ButtonNextSlide">Next Step &rarr;</button>
15
  {% endblock %}
@@ -21,7 +21,11 @@
21
  {% endblock %}
22
  </div>
23
  <div class="slide-body">
24
- {% block slide_body %} {% endblock %}
 
 
 
 
25
  </div>
26
  <div class="slide-footer">
27
  {% block slide_footer %}
4
  {% block slide_header_nav %}
5
  <div class="container-fluid">
6
  <div class="row">
7
+ <div class="col-md-6 col-sm-6 col-xs-6">
8
  {% block slide_header_previous %}
9
  <button class="btn btn-default btn-block ButtonPreviousSlide">&larr; Previous Step </button>
10
  {% endblock %}
11
  </div>
12
+ <div class="col-md-6 col-sm-6 col-xs-6">
13
  {% block slide_header_next %}
14
  <button class="btn btn-info btn-block ButtonNextSlide">Next Step &rarr;</button>
15
  {% endblock %}
21
  {% endblock %}
22
  </div>
23
  <div class="slide-body">
24
+ {% block slide_body %}
25
+ {% block slide_body_top %}{% endblock %}
26
+ {% block slide_body_middle %}{% endblock %}
27
+ {% block slide_body_bottom %}{% endblock %}
28
+ {% endblock %}
29
  </div>
30
  <div class="slide-footer">
31
  {% block slide_footer %}
templates/twig/wizard/slides/common/base_finish.twig ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'wizard/slides/common/base.twig' %}
2
+
3
+ {% block slide_header_next %}{% endblock %}
4
+
5
+ {% block slide_body_middle %}
6
+
7
+ <h3>Next Steps?</h3>
8
+
9
+ {% if data.mod_wizards_count > 1 %}
10
+ <h4>All Wizards In This Module</h4>
11
+ <ul>
12
+ {% for wizard in data.mod_wizards %}
13
+ <li><a href="{{ wizard.url }}">{{ wizard.title }}</a></li>
14
+ {% endfor %}
15
+ </ul>
16
+ {% endif %}
17
+
18
+ {% block slide_body_middle_gopro %}
19
+ {% if not flags.is_premium %}
20
+ <h4>Go Further With Pro :)</h4>
21
+ <p>We've added many advantages to the Pro version, and we've made it available for every budget
22
+ for just $1/month - the most affordable Security plugin available today!</p>
23
+ <p>With your support, we'll continue our work and bring you ever-more powerful security features.</p>
24
+ <p>This is what you get for going Pro:</p>
25
+ <ul>
26
+ <li>Simple (+automatic) options import/export between all your websites</li>
27
+ <li>Vulnerability Scanner - daily scans/alerts for security vulnerabilities</li>
28
+ <li>Exclusive customer support</li>
29
+ <li>3rd-Party Plugin integration including WooCommerce, BuddyPress etc.</li>
30
+ <li>Unlimited audit trail</li>
31
+ <li>Invisible Google reCAPTCHA</li>
32
+ <li>Customize visitor messages</li>
33
+ <li>(coming soon) Mobile Push Notifications</li>
34
+ <li>(coming soon) White Labelling</li>
35
+ <li>(coming soon) Refined options for 2-Factor Authentication</li>
36
+ </ul>
37
+ <a href="{{ hrefs.gopro }}" target="_blank" class="btn btn-success" id="GoProBtn">Go Pro Today!</a>
38
+ {% endif %}
39
+ {% endblock %}
40
+
41
+ {% endblock %}
42
+
43
+ {% block slide_body_bottom %}
44
+ <p>Click the button below to return to the main WordPress dashboard.</p>
45
+ {% endblock %}
46
+
47
+ {% block slide_footer %}
48
+ <hr />
49
+ <a href="{{ hrefs.dashboard }}" class="btn btn-default">&#x21d0; Return To The Shield WordPress Dashboard</a>
50
+ {% endblock %}
templates/twig/wizard/slides/common/base_start.twig ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ {% extends 'wizard/slides/common/base.twig' %}
2
+
3
+ {% block slide_header_previous %}{% endblock %}
templates/twig/wizard/{slide-no_access.twig → slides/common/no_access.twig} RENAMED
@@ -1,4 +1,4 @@
1
- {% extends 'wizard/base.twig' %}
2
 
3
  {% block slide_header_nav %}{% endblock %}
4
 
1
+ {% extends 'wizard/slides/common/base.twig' %}
2
 
3
  {% block slide_header_nav %}{% endblock %}
4
 
templates/twig/wizard/{slide-admin_access_restriction_verify.twig → slides/common/security_admin_verify.twig} RENAMED
@@ -1,4 +1,4 @@
1
- {% extends 'wizard/base.twig' %}
2
 
3
  {% block slide_body %}
4
 
@@ -7,7 +7,7 @@
7
 
8
  <h4>Supply Security Admin Access Key</h4>
9
  <form class="form-horizontal icwp-wizard-form">
10
- <input name="wizard-step" value="admin_access_restriction_verify" type="hidden" />
11
  <input name="current_index" value="{{ current_index }}" type="hidden" />
12
  <div class="form-group">
13
  <label class="col-md-4 control-label" for="AccessKey">Access Key</label>
1
+ {% extends 'wizard/slides/common/base.twig' %}
2
 
3
  {% block slide_body %}
4
 
7
 
8
  <h4>Supply Security Admin Access Key</h4>
9
  <form class="form-horizontal icwp-wizard-form">
10
+ <input name="wizard-step" value="security_admin_verify" type="hidden" />
11
  <input name="current_index" value="{{ current_index }}" type="hidden" />
12
  <div class="form-group">
13
  <label class="col-md-4 control-label" for="AccessKey">Access Key</label>
templates/twig/wizard/slides/importexport/finished.twig ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ {% extends 'wizard/slides/common/base_finish.twig' %}
2
+
3
+ {% block slide_body_top %}
4
+ <h3>Finished: Shield Options Import Wizard</h3>
5
+ <p>This is the end of the Shield Security Network/Import Wizard.</p>
6
+ {% endblock %}
templates/twig/wizard/{slide-import_options.twig → slides/importexport/import.twig} RENAMED
@@ -1,4 +1,4 @@
1
- {% extends 'wizard/base.twig' %}
2
 
3
  {% block slide_body %}
4
  <h3>Build Your Shield Security Network</h3>
@@ -10,9 +10,10 @@
10
  before proceeding.</p>
11
 
12
  <h4>Import Options</h4>
13
- <p><strong>Warning</strong>: If successful, on this site will be overwritten by those from the source.</p>
 
14
  <form class="form-horizontal icwp-wizard-form">
15
- <input name="wizard-step" value="import_options" type="hidden" />
16
 
17
  <div class="form-group">
18
  <label class="col-md-4 control-label" for="MasterSiteUrl">Master Site URL</label>
1
+ {% extends 'wizard/slides/common/base.twig' %}
2
 
3
  {% block slide_body %}
4
  <h3>Build Your Shield Security Network</h3>
10
  before proceeding.</p>
11
 
12
  <h4>Import Options</h4>
13
+ <p><strong>Warning</strong>: If successful, all options on this site will be overwritten by
14
+ those from the source.</p>
15
  <form class="form-horizontal icwp-wizard-form">
16
+ <input name="wizard-step" value="import" type="hidden" />
17
 
18
  <div class="form-group">
19
  <label class="col-md-4 control-label" for="MasterSiteUrl">Master Site URL</label>
templates/twig/wizard/{slide-import_start.twig → slides/importexport/start.twig} RENAMED
@@ -1,4 +1,4 @@
1
- {% extends 'wizard/base_start.twig' %}
2
 
3
  {% block slide_body %}
4
 
@@ -7,6 +7,10 @@
7
  your sites.</p>
8
  <p>You can, of course, simply use this as an ad-hoc import tool, but much more powerful is to create a
9
  <strong>Shield Network</strong>.</p>
 
 
 
 
10
  <h4>What is a Shield Network?</h4>
11
  <p>A Shield Network is where all your Shield Security sites are connected to a Master Site, from which they will
12
  derive their configuration. If you change settings on the Master Site, these will get propagated to the child sites.</p>
@@ -21,6 +25,5 @@
21
  <li>If you select to create the network, this site's URL will be added to the sync white list of the Master
22
  site, to allow for automated syncing.</li>
23
  </ul>
24
- <p>&nbsp;</p>
25
  <p>Right, let's get to it. Click 'Next Step' above to start your import.
26
  {% endblock %}
1
+ {% extends 'wizard/slides/common/base_start.twig' %}
2
 
3
  {% block slide_body %}
4
 
7
  your sites.</p>
8
  <p>You can, of course, simply use this as an ad-hoc import tool, but much more powerful is to create a
9
  <strong>Shield Network</strong>.</p>
10
+ <h4>What about simple options import?</h4>
11
+ <p>This is easily done. Move to the next step and enter the information for the site you want
12
+ to export from i.e. its URL and its secret key. Options will then be imported directly into this site.</p>
13
+ <p>If you want to keep your site options "synced" with the export site, read on...</p>
14
  <h4>What is a Shield Network?</h4>
15
  <p>A Shield Network is where all your Shield Security sites are connected to a Master Site, from which they will
16
  derive their configuration. If you change settings on the Master Site, these will get propagated to the child sites.</p>
25
  <li>If you select to create the network, this site's URL will be added to the sync white list of the Master
26
  site, to allow for automated syncing.</li>
27
  </ul>
 
28
  <p>Right, let's get to it. Click 'Next Step' above to start your import.
29
  {% endblock %}
templates/twig/wizard/slides/mfa/authemail.twig ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'wizard/slides/common/base.twig' %}
2
+
3
+ {% block slide_body %}
4
+
5
+ <h3>Setup Email-Based Authentication</h3>
6
+ <p>Email-based authentication involves you receiving an email to the address attached to your WordPress
7
+ user account. This email will contain a 6-digit code which you'll need to put into the
8
+ login confirmation page.</p>
9
+ <p>The tricky thing with email is that WordPress sites are terrible for sending emails, as most domains
10
+ and webhosting aren't configured properly for sending email reliably.</p>
11
+ <p>This means if you set this up and you don't get the email, you'll be locked out. So, before enabling
12
+ email-based authentication, we'll send you a test email first and ask you to verify that you got it.</p>
13
+
14
+ <h4>Email Sending Confirmation</h4>
15
+ <p>Click the button below to confirm your email address, to which we'll send a confirmation email.</p>
16
+ <form class="form-horizontal icwp-wizard-form" id>
17
+ <input name="wizard-step" value="authemail" type="hidden" />
18
+
19
+ <div class="form-group">
20
+ <label class="col-md-4 control-label" for="email">Your Email</label>
21
+ <div class="col-md-8">
22
+ <input type="email" class="form-control" name="email" placeholder="{{ data.user_email }}"
23
+ value="{{ data.user_email }}">
24
+ </div>
25
+ </div>
26
+
27
+ <div class="form-group stage-verificationcode" style="display: none;">
28
+ <label class="col-md-4 control-label" for="code">Verification Code</label>
29
+ <div class="col-md-8">
30
+ <input type="text" class="form-control" name="code"
31
+ maxlength="6" minlength="6" placeholder="" value="">
32
+ </div>
33
+ </div>
34
+
35
+ <div class="form-group stage-verificationcode" style="display: none;">
36
+ <label class="col-md-4 control-label" for="Email2FAOption">Turn On Email 2FA</label>
37
+ <div class="col-md-8">
38
+ <label for="Email2FAOption">
39
+ <input type="checkbox" value="Y" name="Email2FAOption" id="Email2FAOption">
40
+ Check to turn on Email-based 2 Factor Authentication
41
+ </label>
42
+ <span id="helpBlock" class="help-block">
43
+ When enabled, each time you login you'll get an email with a 2-factor authentication code.
44
+ You will need this code to log into your WordPress site. If your site
45
+ has problems in the future with emails, this could present a problem.
46
+ Emails not being received are the responsibility
47
+ of your WordPress site and your email provider. Shield uses the standard WordPress email
48
+ functionality and if it doesn't work, you'll need to check with your host.
49
+ </span>
50
+ </div>
51
+ </div>
52
+
53
+ <div class="form-group">
54
+ <div class="col-md-offset-4 col-md-8">
55
+ <button type="submit" class="btn btn-primary">Send Info</button>
56
+ </div>
57
+ </div>
58
+ </form>
59
+
60
+ <script type="text/javascript">
61
+ jQuery( document ).on( 'icwpWizardFormSubmit', function ( event, bSuccess ) {
62
+ if ( bSuccess ) {
63
+ var $oForm = jQuery( event.target );
64
+ jQuery( '.stage-verificationcode', $oForm ).slideDown();
65
+ jQuery( 'button[type=submit]', $oForm ).prop( 'disabled', false );
66
+ }
67
+ } );
68
+ </script>
69
+ {% endblock %}
templates/twig/wizard/slides/mfa/authga.twig ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'wizard/slides/common/base.twig' %}
2
+
3
+ {% block slide_body %}
4
+
5
+ <h3>Setup Google Authenticator</h3>
6
+ <p>Google Authenticator is a popular choice for 2FA. It has 1 drawback, however - if you'll lose
7
+ your phone or reset it, you lose all your 2FA login codes.</p>
8
+ <p>There is a solution to this and we <strong>strongly recommend</strong> that you do it: .</p>
9
+ <p>Once you're ready to proceed with Google Authenticator, please scan the barcode below, and enter
10
+ code to confirm.</p>
11
+ <p>Note: Turning on Google Authenticator for your user account will make the option available
12
+ to turn it on for all users on the site.</p>
13
+
14
+ <h4>Register Google Authenticator On Your Account</h4>
15
+
16
+ {% if flags.has_ga %}
17
+ <p>It looks like Google Authenticator is already configured for your WordPress account so
18
+ no need to set that up again.</p>
19
+ {% else %}
20
+ <p>Scan the barcode below and enter the 6-digit code to register.</p>
21
+ {% endif %}
22
+
23
+ <form class="form-horizontal icwp-wizard-form" id>
24
+ <input name="wizard-step" value="authga" type="hidden" />
25
+
26
+ {% if flags.has_ga %}
27
+ <input name="code" value="ignore" type="hidden" />
28
+
29
+ <div class="form-group stage-verificationcode">
30
+ <label class="col-md-4 control-label" for="enablega">Turn On Google Authenticator</label>
31
+ <div class="col-md-8">
32
+ <div class="radio">
33
+ <label>
34
+ <input type="radio" name="enablega" id="enablegaOn" value="Y" checked>
35
+ Enable Google Authenticator
36
+ </label>
37
+ </div>
38
+ <div class="radio">
39
+ <label>
40
+ <input type="radio" name="enablega" id="enablegaOff" value="N">
41
+ Disable Google Authenticator
42
+ </label>
43
+ </div>
44
+
45
+ <span id="helpBlock" class="help-block">
46
+ When enabled, this will allow any users of this site to configure and
47
+ use Google Authenticator on their WordPress accounts.
48
+ </span>
49
+ </div>
50
+ </div>
51
+ {% else %}
52
+ <input name="enablega" value="Y" type="hidden" />
53
+
54
+ <div class="form-group">
55
+ <label class="col-md-4 control-label">Scan your unique code</label>
56
+ <div class="col-md-8">
57
+ <img src="{{ hrefs.ga_chart }}" />
58
+ </div>
59
+ </div>
60
+
61
+ <div class="form-group">
62
+ <label class="col-md-4 control-label" for="code">Authenticator Code</label>
63
+ <div class="col-md-8">
64
+ <input type="text" class="form-control" name="code"
65
+ maxlength="6" minlength="6" placeholder="" value="">
66
+ </div>
67
+ </div>
68
+ {% endif %}
69
+
70
+ <div class="form-group">
71
+ <div class="col-md-offset-4 col-md-8">
72
+ <button type="submit" class="btn btn-primary">Configure Google Authenticator</button>
73
+ </div>
74
+ </div>
75
+ </form>
76
+ {% endblock %}
templates/twig/wizard/slides/mfa/finished.twig ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ {% extends 'wizard/slides/common/base_finish.twig' %}
2
+
3
+ {% block slide_body_top %}
4
+ <h3>Finished: Multi-Factor Authentication Setup</h3>
5
+ <p>This is the end of the Shield Security Multi-Factor Authentication Setup Wizard.</p>
6
+ {% endblock %}
templates/twig/wizard/slides/mfa/multiselect.twig ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'wizard/slides/common/base.twig' %}
2
+
3
+ {% block slide_body %}
4
+
5
+ <h3>Configure Multi-Factor or Two-Factor Authentication</h3>
6
+ <p>As we outlined on the first slide in this wizard, if you have a password and 1 extra factor,
7
+ you have what is known as "Two-Factor Authentication".</p>
8
+ <p>But if you have more than 1 extra factor, you have what is called
9
+ "Multi-Factor Authentication".</p>
10
+ <p>You have a choice between either of these, now that you've configured other login factors.</p>
11
+ <p>You can either set that <strong>all extra login factors</strong> are required when a user logs on.
12
+ Or you can set that <strong>only 1 extra login factor</strong> is required.</p>
13
+ <p>The balance here of course is between an easier user experience, or harder site security.
14
+ The choice is yours.</p>
15
+
16
+ <h4>Configure Factor Requirements</h4>
17
+
18
+ <form class="form-horizontal icwp-wizard-form" id>
19
+ <input name="wizard-step" value="multiselect" type="hidden" />
20
+
21
+ <div class="form-group stage-verificationcode">
22
+ <label class="col-md-4 control-label" for="multiselect">Configure Multi-Factor Authentication</label>
23
+ <div class="col-md-8">
24
+ <div class="radio">
25
+ <label>
26
+ <input type="radio" name="multiselect" id="multiselectOn" value="Y" checked>
27
+ Turn On Multi-Factor (all factors required)
28
+ </label>
29
+ </div>
30
+ <div class="radio">
31
+ <label>
32
+ <input type="radio" name="multiselect" id="multiselectOff" value="N">
33
+ Turn Off Multi-Factor (only 1 extra factor)
34
+ </label>
35
+ </div>
36
+
37
+ <span id="helpBlock" class="help-block">
38
+ Think of turning multi-factor <em>on</em> as "requiring all configured factors".
39
+ <br/>And think of turning multi-factor <em>off</em> as "requiring just 1 of your extra factors".
40
+ </span>
41
+ </div>
42
+ </div>
43
+
44
+ <div class="form-group">
45
+ <div class="col-md-offset-4 col-md-8">
46
+ <button type="submit" class="btn btn-primary">Configure Multi-Factor</button>
47
+ </div>
48
+ </div>
49
+ </form>
50
+ {% endblock %}
templates/twig/wizard/slides/mfa/start.twig ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'wizard/slides/common/base_start.twig' %}
2
+
3
+ {% block slide_body %}
4
+
5
+ <h3>Multi-Factor Authentication Wizard</h3>
6
+ <p>What is Multi-Factor / Two-Factor Authentication?</p>
7
+ <p>Simply put, it is the addition of an extra piece of information (or "factor") during your login.
8
+ It helps prevent anyone gaining access to your account with just your password.</p>
9
+ <p>This can take various forms, and you've probably seen it in other places. Some examples include:</p>
10
+ <ul>
11
+ <li>A memorable question, e.g. What is your favourite color</li>
12
+ <li>Google Authenticator - you supply a random 6-digit code</li>
13
+ <li>Email - you get an email with a link or a code to verify</li>
14
+ <li>SMS - you get text message with a code to verify</li>
15
+ </ul>
16
+ <p>Hopefully you see the pattern - there's a extra piece of information that you must
17
+ supply along with your password. This is your extra "factor".</p>
18
+ <p>If you have a password + 1 other factor, this is called Two-Factor Authentication</p>
19
+ <p>If you have a password + 2 or more other factors, this is called Multi-Factor Authentication</p>
20
+ <p>The Shield Security plugin lets you setup multiple login factors, and the simplest
21
+ of which is <strong>email</strong>. This wizard will walk you through setup of these extra factors.</p>
22
+ {% endblock %}
templates/twig/wizard/slides/ufc/config.twig ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'wizard/slides/common/base.twig' %}
2
+
3
+ {% block slide_body %}
4
+ <h3>Turn On Automatic Unrecognised File Scanner</h3>
5
+ <p>It looks like the unrecognised file scanner isn't set to run automatically.</p>
6
+ <p>Now that you've setup your file exclusions, we recommend the final option
7
+ - automatically delete discovered files and send an email report.</p>
8
+ <p>You can adjust this using the settings below.</p>
9
+
10
+ <form class="form-horizontal icwp-wizard-form">
11
+ <input name="wizard-step" value="ufcconfig" type="hidden" />
12
+ <div class="form-group">
13
+ <label class="col-md-4 control-label" for="enable_scan">Enable Automatic Scanning</label>
14
+ <div class="col-md-8">
15
+ <div class="radio">
16
+ <label>
17
+ <input type="radio" name="enable_scan" id="EnableScanReport" value="enabled_report_only">
18
+ Send email report only
19
+ </label>
20
+ </div>
21
+ <div class="radio">
22
+ <label>
23
+ <input type="radio" name="enable_scan" id="EnableScanDelete" value="enabled_delete_only">
24
+ Automatically delete discovered files
25
+ </label>
26
+ </div>
27
+ <div class="radio">
28
+ <label>
29
+ <input type="radio" name="enable_scan" id="EnableScanDeleteReport" value="enabled_delete_report">
30
+ Automatically delete discovered files and send email report<br/>(<em>recommended</em>)
31
+ </label>
32
+ </div>
33
+ </div>
34
+ </div>
35
+
36
+ <div class="form-group">
37
+ <div class="col-md-offset-4 col-md-8">
38
+ <button type="submit" class="btn btn-primary">Set Automatic Scan</button>
39
+ </div>
40
+ </div>
41
+ </form>
42
+ {% endblock %}
templates/twig/wizard/slides/ufc/exclusions.twig ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'wizard/slides/common/base.twig' %}
2
+
3
+ {% block slide_body %}
4
+
5
+ <h3>Unrecognised File Scanner - File Exclusions</h3>
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
+ <form class="form-horizontal icwp-wizard-form" id>
17
+ <input name="wizard-step" value="exclusions" type="hidden" />
18
+
19
+ <div class="form-group">
20
+ <label class="col-md-4 control-label" for="email">Excluded Files List</label>
21
+ <div class="col-md-8">
22
+ <textarea class="form-control" name="exclusions" rows="{{ data.files.count + 2 }}"
23
+ placeholder="{{ data.files.list }}">{{ data.files.list }}</textarea>
24
+ <span id="helpBlock" class="help-block">
25
+ Take a <strong>new line</strong> for each file name.
26
+ <br/>Note: You may also use regular expressions - if you don't know what this is,
27
+ that's no problem, then please use normal file names and ignore the following guidance.
28
+ <br/>Regular expressions must <strong>start and end</strong> with a "hash" character
29
+ i.e. <code>#</code>
30
+ <br />You must escape special characters.
31
+ <br />An example: <code>#\.log#</code>
32
+ <br />This will match the following files:
33
+ <code>test.log</code>, <code>text.log.txt</code>, <code>.log.ini</code>
34
+ </span>
35
+ </div>
36
+ </div>
37
+
38
+ <div class="form-group">
39
+ <div class="col-md-offset-4 col-md-8">
40
+ <button type="submit" class="btn btn-primary">Update File Exclusions</button>
41
+ </div>
42
+ </div>
43
+ </form>
44
+
45
+ <script type="text/javascript">
46
+ jQuery( document ).on( 'icwpWizardFormSubmit', function ( event, bSuccess ) {
47
+ if ( bSuccess ) {
48
+ var $oForm = jQuery( event.target );
49
+ jQuery( 'button[type=submit]', $oForm ).prop( 'disabled', false );
50
+ }
51
+ } );
52
+ </script>
53
+ {% endblock %}
templates/twig/wizard/slides/ufc/finished.twig ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ {% extends 'wizard/slides/common/base_finish.twig' %}
2
+
3
+ {% block slide_body_top %}
4
+ <h3>Finished: Unrecognised File Scanner</h3>
5
+ <p>This is the end of Shield Security's Unrecognised File Scanner Wizard.</p>
6
+ {% endblock %}
templates/twig/wizard/slides/ufc/scanresult.twig ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'wizard/slides/common/base.twig' %}
2
+
3
+ {% block slide_body %}
4
+
5
+ <h3>Unrecognised File Scanner Results</h3>
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>
12
+ {% endfor %}
13
+ </ul>
14
+ </div>
15
+ <p>To have the scanner delete the files listed above, use the confirmation form below.</p>
16
+ <p><strong>Important</strong>: Remember it is not the job of the scanner to determine
17
+ whether you need these files on your website. This is <em>your role</em>.
18
+ We can only show you what's there. If you have doubts, please discuss
19
+ this with your web hosting provider.
20
+ </p>
21
+ <form class="form-horizontal icwp-wizard-form">
22
+ <input name="wizard-step" value="deletefiles" type="hidden" />
23
+ <div class="form-group">
24
+ <label class="col-md-4 control-label" for="DeleteFiles">Delete Detected Files</label>
25
+ <div class="col-md-8">
26
+ <label for="DeleteFiles">
27
+ <input type="checkbox" value="Y" name="DeleteFiles" id="DeleteFiles">
28
+ Check to delete the unrecognised files.
29
+ </label>
30
+ <span id="helpBlock" class="help-block">
31
+ If there are files on this list that you do not want to delete, please go back
32
+ a step in the wizard and add them to your exclusions list.
33
+ <br />For security reasons, the scanner <strong>does not</strong>
34
+ currently support individual selection of files to delete.
35
+ </span>
36
+ </div>
37
+ </div>
38
+
39
+ <div class="form-group">
40
+ <div class="col-md-offset-4 col-md-8">
41
+ <button type="submit" class="btn btn-warning">Delete Unrecognised Files</button>
42
+ </div>
43
+ </div>
44
+ </form>
45
+
46
+ {% else %}
47
+ <p>There were no files discovered in the scan.</p>
48
+ <p>This could be because there are none, or your exclusions list is ensuring they're ignored.</p>
49
+ {% endif %}
50
+ {% endblock %}
templates/twig/wizard/slides/ufc/start.twig ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'wizard/slides/common/base_start.twig' %}
2
+
3
+ {% block slide_body %}
4
+
5
+ <h3>Start Unrecognised File Scanner</h3>
6
+ <p>What is the Unrecognised File Scanner?</p>
7
+ <p>Where the Core File Scanner is preoccupied with finding any official
8
+ WordPress files that are corrupt, the Unrecognised File Scanner is focused on
9
+ discovering all the other files on your web hosting that are not part of a
10
+ standard WordPress Installation.</p>
11
+ <p>Why are these files important?</p>
12
+ <p>They could perfectly fine, or they could be script files that a hacker has deployed on your hosting
13
+ to access your site or corrupt your WordPress installation in some way.</p>
14
+ <p><strong>Important Note: this scanner cannot direct you whether you should delete or keep these files,
15
+ it can only tell you that they exist. It is up to you to determine if they're okay.</strong>
16
+ </p>
17
+ <p>If you're in doubt, please discuss any results with your hosting provider.</p>
18
+ {% endblock %}
templates/twig/wizard/slides/wcf/config.twig ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'wizard/slides/common/base.twig' %}
2
+
3
+ {% block slide_body %}
4
+ <h3>Turn On Automatic WordPress Core File Scanner</h3>
5
+ <p>It looks like the WordPress Core File scanner isn't set to run automatically.</p>
6
+ <p>We recommend the final option
7
+ - automatically restore any discovered files and send an email report.</p>
8
+ <p>You can adjust this using the settings below.</p>
9
+
10
+ <form class="form-horizontal icwp-wizard-form">
11
+ <input name="wizard-step" value="wcfconfig" type="hidden" />
12
+ <div class="form-group">
13
+ <label class="col-md-4 control-label" for="enable_scan">Enable Automatic Scanning</label>
14
+ <div class="col-md-8">
15
+ <div class="radio">
16
+ <label>
17
+ <input type="radio" name="enable_scan" id="EnableScanReport" value="enabled_report_only">
18
+ Scan WordPress Core files and send email report
19
+ </label>
20
+ </div>
21
+ <div class="radio">
22
+ <label>
23
+ <input type="radio" name="enable_scan" id="EnableScanDeleteReport" value="enabled_restore_report">
24
+ Scan and automatically restore any discovered files and send email report<br/>(<em>recommended</em>)
25
+ </label>
26
+ </div>
27
+ </div>
28
+ </div>
29
+
30
+ <div class="form-group">
31
+ <div class="col-md-offset-4 col-md-8">
32
+ <button type="submit" class="btn btn-primary">Set Automatic Scan</button>
33
+ </div>
34
+ </div>
35
+ </form>
36
+ {% endblock %}
templates/twig/wizard/slides/wcf/finished.twig ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ {% extends 'wizard/slides/common/base_finish.twig' %}
2
+
3
+ {% block slide_body_top %}
4
+ <h3>Finished: WordPress Core File Scanner</h3>
5
+ <p>This is the end of Shield Security's WordPress Core File Scanner Wizard.</p>
6
+ {% endblock %}
templates/twig/wizard/slides/wcf/scanresult.twig ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'wizard/slides/common/base.twig' %}
2
+
3
+ {% block slide_body %}
4
+
5
+ <h3>WordPress Core File Scanner Results</h3>
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
+ <h4>Modified Core Files: {{ data.files.checksum.count }}</h4>
11
+ <ul>
12
+ {% for file in data.files.checksum.list %}
13
+ <li><code class="filepath">{{ file }}</code></li>
14
+ {% endfor %}
15
+ </ul>
16
+ {% endif %}
17
+ </div>
18
+
19
+ <div class="indent_slight">
20
+ {% if data.files.missing.has %}
21
+ <h4>Missing Core Files: {{ data.files.missing.count }}</h4>
22
+ <ul>
23
+ {% for file in data.files.missing.list %}
24
+ <li><code class="filepath">{{ file }}</code></li>
25
+ {% endfor %}
26
+ </ul>
27
+ {% endif %}
28
+ </div>
29
+
30
+ <p>To replace the files listed above with the official versions taken
31
+ directly from WordPress.org, use the confirmation form below.</p>
32
+ <p><strong>Important</strong>: Remember it is not the job of the scanner to determine
33
+ whether you need to replace these files on your website. This is <em>your role</em>.
34
+ We can only show you what's there. If you have doubts, please discuss
35
+ this with your web hosting provider or developers.
36
+ </p>
37
+ <form class="form-horizontal icwp-wizard-form">
38
+ <input name="wizard-step" value="restorefiles" type="hidden" />
39
+ <div class="form-group">
40
+ <label class="col-md-4 control-label" for="RestoreFiles">Replace Modified Files</label>
41
+ <div class="col-md-8">
42
+ <label for="RestoreFiles">
43
+ <input type="checkbox" value="Y" name="RestoreFiles" id="RestoreFiles">
44
+ Check to replace all of the modified files.
45
+ </label>
46
+ <span id="helpBlock" class="help-block">
47
+ If you are unsure about whether you can restore these files to official
48
+ WordPress originals, please discuss the results of this scan with your
49
+ web host/developer.
50
+ </span>
51
+ </div>
52
+ </div>
53
+
54
+ <div class="form-group">
55
+ <div class="col-md-offset-4 col-md-8">
56
+ <button type="submit" class="btn btn-warning">Replace Files</button>
57
+ </div>
58
+ </div>
59
+ </form>
60
+
61
+ {% else %}
62
+ <p>There were no modified files discovered in the scan.</p>
63
+ {% endif %}
64
+ {% endblock %}
templates/twig/wizard/slides/wcf/start.twig ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'wizard/slides/common/base_start.twig' %}
2
+
3
+ {% block slide_body %}
4
+ <h3>Start: WordPress Core File Scanner</h3>
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 %}
templates/twig/wizard/{slide-admin_access_restriction.twig → slides/welcome/admin_access_restriction.twig} RENAMED
@@ -1,4 +1,4 @@
1
- {% extends 'wizard/base.twig' %}
2
 
3
  {% block slide_body %}
4
 
1
+ {% extends 'wizard/slides/common/base.twig' %}
2
 
3
  {% block slide_body %}
4
 
templates/twig/wizard/{slide-audit_trail.twig → slides/welcome/audit_trail.twig} RENAMED
@@ -1,4 +1,4 @@
1
- {% extends 'wizard/base.twig' %}
2
 
3
  {% block slide_body %}
4
 
1
+ {% extends 'wizard/slides/common/base.twig' %}
2
 
3
  {% block slide_body %}
4
 
templates/twig/wizard/{slide-comments_filter.twig → slides/welcome/comments_filter.twig} RENAMED
@@ -1,4 +1,4 @@
1
- {% extends 'wizard/base.twig' %}
2
 
3
  {% block slide_body %}
4
 
1
+ {% extends 'wizard/slides/common/base.twig' %}
2
 
3
  {% block slide_body %}
4
 
templates/twig/wizard/{slide-how_shield_works.twig → slides/welcome/how_shield_works.twig} RENAMED
@@ -1,4 +1,4 @@
1
- {% extends 'wizard/base.twig' %}
2
 
3
  {% block slide_body %}
4
 
1
+ {% extends 'wizard/slides/common/base.twig' %}
2
 
3
  {% block slide_body %}
4
 
templates/twig/wizard/slides/welcome/import.twig ADDED
@@ -0,0 +1 @@
 
1
+ {% extends 'wizard/slides/importexport/import.twig' %}
templates/twig/wizard/slides/welcome/ip_detect.twig ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends 'wizard/slides/common/base.twig' %}
2
+
3
+ {% block slide_body %}
4
+
5
+ <h3>IP Detection</h3>
6
+ <p>All websites and webhosts are configured differently. This makes certain things a bit tricky
7
+ to automate.</p>
8
+ <p>An important example of this is detecting the correct IP address of a website visitor.</p>
9
+ <p>We try to do this automatically for you, of course, but sometimes a server configuration
10
+ can be... unexpected. So, to ensure we use the method that works best on your server,
11
+ we're going to ask you to help us.</p>
12
+ <p>It's easy, and works by you telling us what your IP address is, so we can match it against all the possibilities
13
+ that your webhost server presents to us. When we find a match, we'll have found the best way to detect visitor IPs
14
+ for your particular web hosting.</p>
15
+ <p>It involves 2 simple steps. Here goes ...</p>
16
+
17
+ <h4>Steps To Find Best Source For Visitor IP Address</h4>
18
+ <h5>Step 1: Find <em>your</em> current IP address</h5>
19
+ <p><a href="{{ hrefs.visitor_ip }}" target="_blank">Click here</a>
20
+ to open up a new page that will tell you your current IP Address.</p>
21
+ <h5>Step 2: Tell us your IP address</h5>
22
+ <p>Copy and paste the IP address from Step 1 into the text box below and click submit.</p>
23
+
24
+ <form class="form-horizontal icwp-wizard-form">
25
+ <input name="wizard-step" value="ip_detect" type="hidden" />
26
+ <div class="form-group">
27
+ <label class="col-md-4 control-label" for="ip">My IP Address:</label>
28
+ <div class="col-md-8">
29
+ <input type="text" class="form-control" maxlength="32" size="32"
30
+ name="ip" id="ip" placeholder="123.456.789.012">
31
+ </div>
32
+ </div>
33
+ <div class="form-group">
34
+ <div class="col-md-offset-4 col-md-8">
35
+ <button type="submit" class="btn btn-primary">Submit: This Is My IP</button>
36
+ </div>
37
+ </div>
38
+ </form>
39
+
40
+ {% endblock %}
templates/twig/wizard/{slide-ips.twig → slides/welcome/ips.twig} RENAMED
@@ -1,4 +1,4 @@
1
- {% extends 'wizard/base.twig' %}
2
 
3
  {% block slide_body %}
4
 
1
+ {% extends 'wizard/slides/common/base.twig' %}
2
 
3
  {% block slide_body %}
4
 
templates/twig/wizard/{slide-license.twig → slides/welcome/license.twig} RENAMED
@@ -1,4 +1,4 @@
1
- {% extends 'wizard/base.twig' %}
2
 
3
  {% block slide_body %}
4
 
1
+ {% extends 'wizard/slides/common/base.twig' %}
2
 
3
  {% block slide_body %}
4
 
templates/twig/wizard/{slide-login_protect.twig → slides/welcome/login_protect.twig} RENAMED
@@ -1,4 +1,4 @@
1
- {% extends 'wizard/base.twig' %}
2
 
3
  {% block slide_body %}
4
 
1
+ {% extends 'wizard/slides/common/base.twig' %}
2
 
3
  {% block slide_body %}
4
 
templates/twig/wizard/{slide-optin.twig → slides/welcome/optin.twig} RENAMED
@@ -1,4 +1,4 @@
1
- {% extends 'wizard/base.twig' %}
2
 
3
  {% block slide_body %}
4
 
1
+ {% extends 'wizard/slides/common/base.twig' %}
2
 
3
  {% block slide_body %}
4
 
templates/twig/wizard/{slide-thankyou.twig → slides/welcome/thankyou.twig} RENAMED
@@ -1,6 +1,6 @@
1
- {% extends 'wizard/base_finish.twig' %}
2
 
3
- {% block slide_body %}
4
 
5
  <h3>Thank You!</h3>
6
  <p>You've done it! This is the just scratching the surface of Shield Security and the options you have available.</p>
1
+ {% extends 'wizard/slides/common/base_finish.twig' %}
2
 
3
+ {% block slide_body_top %}
4
 
5
  <h3>Thank You!</h3>
6
  <p>You've done it! This is the just scratching the surface of Shield Security and the options you have available.</p>
templates/twig/wizard/{slide-welcome.twig → slides/welcome/welcome.twig} RENAMED
@@ -1,4 +1,4 @@
1
- {% extends 'wizard/base_start.twig' %}
2
 
3
  {% block slide_body %}
4
 
1
+ {% extends 'wizard/slides/common/base_start.twig' %}
2
 
3
  {% block slide_body %}
4